Freecad polyline arc starting to comply..

It seems, that the polyline arc project is starting to bend to my will sort of.

It seems like a line and an arc is working now..

 

The next test would be line-arc-line.

 

 

Ok… A few kinks fixed.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Getting close to reaching the goal.. Working on the Arc-Arc I’m getting some weirdness.
At the moment I’m befuddled why this isnt’ working.. There a tangent line that’s defined prior to the arc being generated in the mouse move.   Big  Hmmmm. (Problem was I had my tangent line pointing in the wrong direction.)

 

 

 

 

 

 

Success. Drawing the polyline but still some loose ends.

 

Research notes for Single stepping python code for in Qt-Creator for free-cad

Working through single stepping through the freecad in the qt-creator I hit some python scripts that would have been really handy to step into.    I thought I through the question out to the qt-creator  irc if it was possible to single step into python code from the qt-creator ide.   The impression that I got was that it’s been attempted but it’s never got working…
I now know there was a  code::blocks project that attempted this:http://wiki.codeblocks.org/index.php?title=Python_plugin

But apparently, there was some work with qt-creator as well.
Here’s the pertinent points from that conversation:
there’s a project (Python IDE) which can be used as a starting point: http://code.google.com/p/pynoto/
you will need to embed libpython into your than you’ll be able to run stuff from that IDE (it’s written in Python)
it’s rather advanced, e.g. includes refactoring
as for debug stepping from C++ to Python and back, I have no idea how it should be implemented but I’m sure it’s possiblealso, there’s an abandoned effort here:
https://github.com/PySide/QtCreator/tree/python-plugin

This link to gaming engines came up in the discussion as well. (Not really what I was interested in at the moment.. but might come in handy for some other projects.

http://www.satori.org/2009/03/the-engine-survey-general-results/

Constraints issues with the polyline Arc

It seems that I’ve isolated issue that’s been causing me the pain in my question for the polyline arc.

The issue that I’ve been having relates to arcs which appear to be drawn clockwise but are rendered clockwise by reversing the start and end points.    When I disabled the code, for applying the coincident point constraint my pictures seemed to be coming out better, but unfortunately the points are not connected.

Interestingly enough, when things went weird, it appears to be related to an autoconstraint kicking in.   It seems like these are occurring further upstream or possible some residual code I haven’t figured out yet.
Anyway as I said when I disabled my attempt at a applying a coincident point constraint things looked better:

The 4′th from the left on the top row actually drew out correctly but when I moved them it came appart because the coincident point constraint was applied.

On the bottom row, things got weird by themselves.  It seems to be intermittent a coincident point constraint snuck in there somehow.

 

 

My pain for the moment seems to be centered here:

//                if (coincidentPoint != 0)
//                {
//                    Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addConstraint(Sketcher.Constraint(‘Coincident’,%i,%i,%i,1)) ”
//                          ,sketchgui->getObject()->getNameInDocument()
//                          ,previousCurve-1,coincidentPoint,previousCurve
//                          );
//

Because this is a python call, my IDE wont single step into it which makes it difficult to see whats going on.

For those interested this is what my release button code looks like at the moment:

virtual bool releaseButton(Base::Vector2D onSketchPos){

if (Mode==STATUS_LINE_Do || Mode==STATUS_LINE_Close||Mode==STATUS_ARC_Do || Mode==STATUS_ARC_Close )
{

if (Mode==STATUS_LINE_Do || Mode==STATUS_LINE_Close)
{
// open the transaction
Gui::Command::openCommand(“add sketch wire”);
// issue the geometry
Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))”,
sketchgui->getObject()->getNameInDocument(),
EditCurve[0].fX,EditCurve[0].fY,EditCurve[1].fX,EditCurve[1].fY);
}
else
{//We’re dealing with an Arc
Gui::Command::openCommand(“Add sketch arc”);
Gui::Command::doCommand(Gui::Command::Doc,
“App.ActiveDocument.%s.addGeometry(Part.ArcOfCircle”
“(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),%f),”
“%f,%f))”,
sketchgui->getObject()->getNameInDocument(),
CenterPoint.fX, CenterPoint.fY, radiusLength,
startAngleDraw, endAngleDraw); //arcAngle > 0 ? 0 : 1);
}
// issue the constraint

if (previousCurve != -1){
//we need to figure which point on the previous curve we’re connecting to
//if the we have a ccw arc we should be connecting to the second point
//if we’re going cw the start/ends are reversed since the arc is rendered ccw
//A line in theory should be the second point, but if we’re restarting the polyline is could
//todo need to check the previous curve(once this is all working
//if we don’t have a match on the previous curve need to keep going back till find one to make it coincident
int coincidentPoint=0;

const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(previousCurve);
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
//if (EditCurve[0] == Base::Vector2D(lineSeg->getStartPoint().x, lineSeg->getStartPoint().y))
//    coincidentPoint=1;
//else if (EditCurve[0] == Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y));
coincidentPoint=2;
}
else if(geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
//The previous element is an arc.
const Part::GeomArcOfCircle *arcSeg = dynamic_cast<const Part::GeomArcOfCircle *>(geom);
if (previousArcDirection==1.0)
//if (EditCurve[0] == Base::Vector2D(arcSeg->getStartPoint().x, arcSeg->getStartPoint().y))
coincidentPoint=1;
else// if  (EditCurve[0] == Base::Vector2D(arcSeg->getEndPoint().x, arcSeg->getEndPoint().y))
coincidentPoint=2;
}

//                if (coincidentPoint != 0)
//                {
//                    Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addConstraint(Sketcher.Constraint(‘Coincident’,%i,%i,%i,1)) ”
//                          ,sketchgui->getObject()->getNameInDocument()
//                          ,previousCurve-1,coincidentPoint,previousCurve
//                          );
//                }
}
if (Mode==STATUS_LINE_Close|| Mode==STATUS_ARC_Close)
{
// close the loop by constrain to the first curve pointConstraint

Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addConstraint(Sketcher.Constraint(‘Coincident’,%i,%2,%i,1)) ”
,sketchgui->getObject()->getNameInDocument()
,previousCurve,firstCurve
);

Gui::Command::commitCommand();
Gui::Command::updateActive();

if (sugConstr2.size() > 0) {
// exclude any coincidence constraints
std::vector<AutoConstraint> sugConstr;
for (int i=0; i < sugConstr2.size(); i++) {
if (sugConstr2[i].Type != Sketcher::Coincident)
sugConstr.push_back(sugConstr2[i]);
}
createAutoConstraints(sugConstr, getHighestCurveIndex(), Sketcher::end);
sugConstr2.clear();
}

unsetCursor();
EditCurve.clear();
resetPositionText();
sketchgui->drawEdit(EditCurve);
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider

}

else{

Gui::Command::commitCommand();
Gui::Command::updateActive();

// Add auto constraints
if (sugConstr1.size() > 0)
{
createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::start);
sugConstr1.clear();
}

if (sugConstr2.size() > 0)
{
createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::end);
sugConstr2.clear();
}

//remember the vertex for the next rounds constraint..
previousCurve = getHighestCurveIndex() + 1;

// setup for the next line segment
// Use updated endPoint as autoconstraints can modify the position
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(getHighestCurveIndex());
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
previousArcDirection=0.0;
EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
}
else if (geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){
const Part::GeomArcOfCircle *arcSeg = dynamic_cast<const Part::GeomArcOfCircle *>(geom);
previousArcDirection=kVec.z;
if (kVec.z ==1.0)//cw arc
EditCurve[0] = Base::Vector2D(arcSeg->getStartPoint().x,arcSeg->getStartPoint().y);
else //cw arc are rendered in reverse
EditCurve[0] = Base::Vector2D(arcSeg->getEndPoint().x,arcSeg->getEndPoint().y);

}

EditCurve.resize(2);

applyCursor();

Mode = STATUS_LINE_SEEK_Second;//LineMode is checked in mousemove and will reset mode to arc
//And will resize Edit Curve to and Arc if required.

}

}
return true;
}

[5-1]

Some notes from the IRC…

tangency constraint has 3 modes, edge to edge, edge to point, and point to point
if you select two end points and apply the tangency constraint, it also enforces the coincidence of the points
in general it is more robust to use a point to point tangency constraint than a point to point coincidence + an edge to edge tangency constraints
however it should work if you just put some breakpoints in the python *Impl.cpp files

File containing routine causing me pain:
you can catch the execution of this command in PyObject* SketchPy::addConstraint(PyObject *args) inside SketchPyImp.cpp

Sketcher.Constraint(‘Coinicident…. where is that implemented?
in ConstraintPyImp.cpp

Sketch components and command line can be view by:
print App.ActiveDocument.Sketch.Geometry
1 the same for print App.ActiveDocument.Sketch.Constraints

pressButton and releaseButton for the freeCad Polylinearc

The mousemove arcs and CW CCW seem to be working out ok. Now comes the fun stuff: To see if I can get the Arc to actually draw out properly as a real freecad object in the pressButton and releaseButton  event.   Some of the initial code is basically recycled from draw arc object which was combined into the polyline.  I had some initial seg faults with obvious errors, which I managed to clean up.  Now there is the first set of things to work on:

 

 

 

 

 

 

 

 

 

 

 

I had a bunch of silly errors going on here.  At this point it’s basically copy paste incompatbilities of bringing DrawSketchHandlerArc functionalility into
std::vector<Base::Vector2D> EditCurve;   Isn’t getting cleared out properly.  That construct is both in the draw arc and DrawSketchHandlerLineSet.  Fixed  and a few other things..

Ok. Got the Easy errors out of the way and I’m left with this.

 

 

 

 

 

The error that I’m seeing in this is the circle not curving the correct way when the arc is drawn clockwise.
The offending culprit is here:

else{//We’re dealing with an Arc
Gui::Command::openCommand(“Add sketch arc”);
Gui::Command::doCommand(Gui::Command::Doc,
“App.ActiveDocument.%s.addGeometry(Part.ArcOfCircle”
“(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),%f),”
“%f,%f))”,
sketchgui->getObject()->getNameInDocument(),
CenterPoint.fX, CenterPoint.fY, radiusLength,
startAngle, endAngle); //arcAngle > 0 ? 0 : 1);

}

At this point, I haven’t do on the openCommand and doCommand stuff.  I’m hoping this is not going to turn into a mutli-week adventure.  I’m thinking one think I might try before digging into to that is to figure out how to add a tangent constraint as see if that fixes everything. (Worth a try).
4-22-12.
Having slept on this a thought occurs to me.

All kinds of errors but I’m just focusing on one at the moment.     At this point, if I draw a polyline arc which results in a clockwise arc being generated the arc is drawn counter clockwise.
Now if I draw 2 line segments separately and then connect them through the DrawSketchHandlerFillet utility is constructs just fine.

 

 

 

 

 

So I’m thinking that I need to digest DrawSketchHandlerFillet a bit.  When I understand that, I should have a handle on how to fix my clockwise arc issue.

 

 

 

 

 

Hmm. it looks like everything runs through the python inter-phase which wraps some c++ code.

Looking at the pertinent python lines:

  • App.ActiveDocument.Sketch.addGeometry(Part.ArcOfCircle(Part.Circle(App.Vector(-39.882378,82.379395,0),App.Vector(0,0,1),64.732491),-2.201594,-1.347593))
  • App.ActiveDocument.Sketch.fillet(3,4,App.Vector(-153.321411,28.704008,0),App.Vector(-99.413879,-8.751223,0),97.736731)

The thing is that App.ActiveDocument.Sketch.fillet needs a vector which I don’t have yet and App.ActiveDocument.Sketch.addGeometry(Part.ArcOfCircle doesn’t seem to work for me.

What’s frustrating is that my c++ IDE won’t let me step into the python stuff.
ArcOfCircle of circle appears here:http://free-cad.sourceforge.net/SrcDocu/da/d6b/classPart_1_1ArcOfCirclePy.html
http://free-cad.sourceforge.net/SrcDocu/de/d18/ArcOfCirclePyImp_8cpp.html

Lets see if I can find anything on this fillet stuff.. Not not sure if this is it:
http://free-cad.sourceforge.net/SrcDocu/dc/d77/classSketcher_1_1SketchObjectPy.html#acb8afeb9c0f5a6be444dad29ed74109b
I think I need to think on this a bit, and do something else for a little while… (Like mow the lawn).

4-23-12

The suggestion came to reverse the start and finish on drawing out a clockwise arc was req’d
Logic that could be adapted is this:

 else {
EditCurve.resize(30);
float angle1 = atan2(onSketchPos.fY – CenterPoint.fY,
onSketchPos.fX – CenterPoint.fX) – startAngle;
float angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;

arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
if (arcAngle > 0)
endAngle = startAngle + arcAngle;
else {
endAngle = startAngle;
startAngle += arcAngle;
}

sketchgui->drawEdit(EditCurve);
applyCursor();
Mode = STATUS_End;
}

I tried to incorporate that code just before drawing the arc and I seem to be getting a few issues that need to be worked out.

4-25-12 Update..
Found a bunch of issues in the releasebutton event.

Tried incorporation above code in mouse move… Didn’t work as well as what I had… (Behavior was irratic.) Since What I had might have been a little more complex, it worked.  Went back to that.

Starting to get into the constraints.  This python wrapper thing is somewhat of a nuisance since I can’t step into that while debugging in the IDE. ;(
I code myself into a seg fault condition… Need to look at what baseline code was to figure out where things went south.

http://free-cad.sourceforge.net/SrcDocu/da/deb/CommandCreateGeo_8cpp_source.html#l00551

Well I moved the error around, but still no joy.

Working out ccw cw on the polyline-arc for freecad

So… I’m going to need how to figure out whether or not I need to go cw or ccw when drawing a polyline arc.

So what I need to know if the point “B” is basically about the Tangent line to the Arc (ccw ) or below (cw).
Originally my thought was to do a coordinate transformation  to the align the axis to the tangent line and see if B was basically above or below the axis.  This seemed like a alot of work and I asked for input on the freecad IRC

So the suggestion came back:
you have the line (x1,y1), (x2,y2) and you want to connect it to an arc from (x2,y2) to (x3,y3)
I think you just need to calculate the determinant of [x1,x2,x3; y1,y2,y3; 1,1,1]
if it is positive your arc goes in one direction if it is negative it goes in the other direction if it is zero (x3,y3) lies on the line
hmm, not exactly, you can find the right calculation in

ConstraintP2LDistance::error

in http://free-cad.git.sourceforge.net/git/gitweb.cgi?p=free-cad/free-cad;a=blob;f=src/Mod/Sketcher/App/freegcs/Constraints.cpp;h=76b42f8d73c6da7ae90394b334382d2520ee8e39;hb=HEAD

you just need to calculate the variable “area” and check its sign

http://people.richland.edu/james/lecture/m116/matrices/applications.html

 

Ok… All I have to say is this was easy(compared to getting the arcs to draw out correctly)..

switch(Mode){
case STATUS_LINE_SEEK_First:
case STATUS_ARC_SEEK_First:
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
break;
case STATUS_LINE_SEEK_Second:
EditCurve[1] = onSketchPos;
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos – EditCurve[0])) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
break;
case STATUS_ARC_SEEK_Second:
if (getHighestCurveIndex()<0){
//Need to figure if there was a previous element?? In order to find perpendicular to the tangent
//Otherwise there can be infinate solutions do drawing an element.
tangent.Set(1.0,0.0,0.0);//todo needs to be addressed

}
else{
//Need to determine if the previous element was a line or an arc or ???
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(getHighestCurveIndex());
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {

const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
tangent.Set(lineSeg->getEndPoint().x-lineSeg->getStartPoint().x,
lineSeg->getEndPoint().y-lineSeg->getStartPoint().y,
0.0);

}
else if(geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){

//todo
//need to get some info on the prior arc
tangent.Set(1.0,0.0,0.0);//todo needs to be addressed

}
else{
//It is neither a point or a line.
//todo.. Need to figure out what to do here.
tangent.Set(1.0,0.0,0.0);//todo needs to be addressed

}

//At this point we need to solve for the previous
}

Distance =onSketchPos-EditCurve[0];
Base::Vector2D tangent2d(tangent.x,tangent.y);

double theta =(double)tangent2d.GetAngle(Distance);
float radiusLength= (Distance.Length())/(2.0*sin(theta ));

Base::Vector3d kVec;
//At this point we need a unit normal vector pointing torwards then center of the arc we are drawing.
//CCW -1, CW =1
// Derivation of the formula used here can be found here: http://people.richland.edu/james/lecture/m116/matrices/area.html
// Since we can be potentially be dealing with a line or an arc, we need to build the area triangle from the tangent

float x1 = EditCurve[0].fX;
float y1 = EditCurve[0].fY;

float x2 = x1+tangent2d.fX;
float y2 = y1+tangent2d.fY;

float x3 = onSketchPos.fX ;
float y3 = onSketchPos.fY;

float twoTimesArea = (x2*y3-x3*y2)-(x1*y3-x3*y1)+(x1*y2-x2*y1);

if (twoTimesArea <0 )
kVec.Set(0.0,0.0,1.0);//CW

else
kVec.Set(0.0,0.0,-1.0);//CCW

Base::Vector3d centerVec = (tangent% kVec);
centerVec.Normalize();
centerVec.Scale(radiusLength,radiusLength,radiusLength);

CenterPoint.Set(centerVec.x,centerVec.y);
CenterPoint =CenterPoint + EditCurve[0];

 

 

 

Continuing on working on my mouse moves in DrawSketchHandlerLineSet

 

 

 

Ok… So I thinking I’m approaching a point where the rubber hits the road…. Or  not… So… What I’m attempting to do is to add an arc to the polyline mode.

I came up with a sketch for solving the polyline arc

So basically A would be the first mouse click and B would be the second mouse click.

So what I need to do is to solve for C which would be the center of the arc.

Goal:
The goal in this sub-project is to determine  the vector position of the center of the Arc “C”.  Once  worked out, I’m on easy street (in this sub-project anyway) for  drawing the Arc in the mouse movement  since the code has  already been worked out

Figuring out the scalar value of VC what I need to do is to figure out the vector position of C

“A” would be the end point of the previous element and the starting point of the Arc.  It would make sense that if we’re drawing a polyline that the Arc should be tangent to the previous element.

That begs the questions… Is there a previous element. Looking at the code, I believe that question could be answered by getHighestCurveIndex().  The question, is that does this return if there is no prior curve?

This function is defined in:
class SketcherExport SketchObject : public Part::Part2DObject
as:
int getHighestCurveIndex(void) const { return Geometry.getSize() – 1; }

Stepping into this:

int DrawSketchHandler::getHighestCurveIndex(void)
{
return sketchgui->getSketchObject()->getHighestCurveIndex();
}
—-
Sketcher::SketchObject *ViewProviderSketch::getSketchObject(void) const
{
return dynamic_cast<Sketcher::SketchObject *>(pcObject);
}

—-

in SketchObject

—-

int getHighestCurveIndex(void) const { return Geometry.getSize() – 1; }

 

int PropertyGeometryList::getSize(void) const
{
return static_cast<int>(_lValueList.size());
}

where Geometry is defined as:

/// Property
Part    ::PropertyGeometryList   Geometry;

 

int PropertyGeometryList::getSize ( void  ) const [virtual]

int PropertyGeometryList::getSize(void) const
{
return static_cast<int>(_lValueList.size());
}

So… after all that if getHighestCurveIndex returns -1 then there is no preset curve and I need to fake a tangent..
Otherwise I should pick tangent to the last element…
So  I think I just need to add a few  vectors:
Base::Vector2D centerPoint,tangent,distance;

This is cool check out the Vector2D member functions.  There’s a bunch I can use here.

float GetAngle (const Vector2D &rclVect) const
float Length (void) const
void Normalize (void)
float operator* (const Vector2D &rclVct) const
Vector2D operator+ (const Vector2D &rclVct) const
Vector2D operator- (const Vector2D &rclVct) const
Vector2D & operator= (const Vector2D &rclVct)
bool operator== (const Vector2D &rclVct) const
void ProjToLine (const Vector2D &rclPt, const Vector2D &rclLine)
void Scale (float fS)
void Set (float fPX, float fPY)
Vector2D (const Vector2D &rclVct)
Vector2D (double x, double y)
Vector2D (float x, float y)
Vector2D (void)
Part::Part2DObject Part::Feature App::GeoFeature App::DocumentObject App::PropertyContainer Base::Persistence Base::BaseClass

One thing that I still need to do is to execute a vector cross product. I was have discussion of how to do this on the #freecad IRC and one had showed how to do this in python:https://gist.github.com/2297556

def getTangent(edge):
    ”Returns a tangent vector from an edge in FreeCAD”
    if isinstance(edge.Curve,Part.Line):
        vec = edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point)
    elif isinstance(edge.Curve,Part.Circle):
        v1 = edge.Vertexes[-1].sub(edge.Curve.Center)
        v2 = edge.Curve.Axis
        vec = v1.cross(v2)
    else:
        print “not supported”
        vec = None
    return vec
So the question became where does python wrap around the c++ code?   The suggestion came to look at /home/jonas/freecad/free-cad/src/Base/VectorPy.cpp
What was really curious was that this file exists but doesn’t exist as a QT project file, looking inside the file explains why.
// This file is generated by src/Tools/generateTemaplates/templateClassPyExport.py out of the .XML file
// Every change you make here get lost at the next full rebuild!
// This File is normaly build as an include in VectorPyImp.cpp! Its not intended to be in a project!
Looking at Base::VectorPy
PyObject*  VectorPy::cross(PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, “O!”, &(VectorPy::Type), &obj))
return 0;VectorPy* vec = static_cast<VectorPy*>(obj);VectorPy::PointerType this_ptr = reinterpret_cast<VectorPy::PointerType>(_pcTwinPointer);
VectorPy::PointerType vect_ptr = reinterpret_cast<VectorPy::PointerType>(vec->_pcTwinPointer);Base::Vector3d v = (*this_ptr) % (*vect_ptr);
return new VectorPy(v);
}
and?
PyObject*  VectorPy::sub(PyObject *args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, “O!”, &(VectorPy::Type), &obj))
return 0;VectorPy* vec = static_cast<VectorPy*>(obj);VectorPy::PointerType this_ptr = reinterpret_cast<VectorPy::PointerType>(_pcTwinPointer);
VectorPy::PointerType vect_ptr = reinterpret_cast<VectorPy::PointerType>(vec->_pcTwinPointer);Base::Vector3d v = (*this_ptr) – (*vect_ptr);
return new VectorPy(v);
}
so sub is vector subtraction… duh….
So… I managed to get rid of seg-faults in the mouse move and I’m starting to get a polyline arc… Sort of
This is amusing to me. I copied the code from DrawSketchHandlerArc and I neglected to populate the variables rx and ry
So I fixed that and thought for the mouse move, add a couple of more lines which would would go from last point to center, to first point… and here is the result.
That makes things a little more interesting.
The one radius line on this arc is supposed to be perpendicular to the line… Clear its not.. Something is obviously not correct..
Oh… this might be it… duhhh:
tangent.Set(lineSeg->getEndPoint().x-lineSeg->getStartPoint().x,
lineSeg->getEndPoint().x-lineSeg->getStartPoint().y,
0.0);
Ok.. now we have this.

It’s not up in this picture but I need to fix if the center of the arc is above the line or below the line.
Also not really represented in this picture, I think something is screwed up in my radius length calculation of the vector from the endpoint of the previous line.
Double duhh..
float radiusLength= (Distance.Length()/2)/(2*sin(theta ));
s/b
float radiusLength= (Distance.Length())/(2*sin(theta ));
Ok… this is looking somewhat better but the arc should be on the cursor..
Oh… Another silly bug.
I copied the code for the arc from DrawSketchHandlerArc whose behavior is different.
The critter lies here:
            arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
arcAngle must be initially calculated in DrawSketchHandlerArc
Success
So… I got this working (barely on the mouse move but..at least its a start)
I need to get the center to flip when the center goes above the line.
4/17 update
I’m widdling down ther issues, but now I have two issues that I need to work out.
1) When arc gets to 180 degrees the arc reverses.
2) The curve is not breaking to the right

So.. I think issue 1) is easy…

referring to http://www.cplusplus.com/reference/clibrary/cmath/atan/

and

http://www.cplusplus.com/reference/clibrary/cmath/atan2/
Atan2 returns Principal arc tangent of y/x, in the interval [-pi,+pi] radians.
What I need to wind up with is 0 to 2PI if I’m going to the left CCW and 0 to -2PI if I’m going CCW.
So.. I need to factor direction when I’m calculating the angle… (More on this later)
I had this vector reference bookmarked at work.. It’s a nice site… This really belongs in my useful links, but good for know

http://chortle.ccsu.edu/VectorLessons/vch09/vch09_6.html

http://free-cad.sourceforge.net/SrcDocu/d6/d23/Tools2D_8cpp_source.html#l00036

4-19 update…Getting tanalizing closer… Stupid logic errors that I almost have worked out for the CCW polyline arc.  I still done have the mousedown event written to draw the arc, so I revert to line (key up on the “A” to test the next case.  Here’s where it’s bombing.

 

 

 

 

 

 

4-21 update. Yeah… Arcs to draw out properly CCW condition. I’m going to get the  the code to respond to a hard set clockwise before start working on the CCW/CW selector.

 

 

 

 

 

This is the little section of code(Which works at the moment) that caused me such pain, no big deal..

(Just in case I need to get back to this point

 

// if ((kVec.z ==-1) ){//ccw
if (startAngle<=0 && finishAngle>=0  )
arcAngle = finishAngle – startAngle ;
else if (startAngle>=0  && finishAngle<=0 )
arcAngle = abs(finishAngle+ 2 * M_PI – startAngle);
else if(( startAngle<0 && finishAngle<0 )|| (startAngle>0 && finishAngle>0 )){//somewhere in the 3 or 4 quandrant
if (finishAngle>startAngle){
arcAngle =finishAngle-startAngle;

}
else{
arcAngle =finishAngle-startAngle+ 2* M_PI;
}

}
else
arcAngle = abs(finishAngle – startAngle);
//  }
// else
//  {

//  }
—–
Ok… I think I got the arcs to draw out properly for both ccw and cw conditions. Here’s the magic:

            if ((kVec.z ==-1) ){//ccw
if (startAngle<=0 && finishAngle>=0  )
arcAngle = finishAngle – startAngle ;
else if (startAngle>=0  && finishAngle<=0 )
arcAngle = abs(finishAngle+ 2 * M_PI – startAngle);
else if(( startAngle<0 && finishAngle<0 )|| (startAngle>0 && finishAngle>0 )){//BOTH START AND FINISH EITHER UPPER OR LOWER QUANDRANTS
if (finishAngle>startAngle){
arcAngle =finishAngle-startAngle;

}
else{
arcAngle =finishAngle-startAngle+ 2* M_PI;
}

}
else
arcAngle = abs(finishAngle – startAngle);//Don’t think this point is ever reached
}
else{//cw rotation
if (startAngle<=0 && finishAngle>=0  )
arcAngle = abs(finishAngle – startAngle-2 *M_PI) ;
else if (startAngle>=0  && finishAngle<=0 )
arcAngle = abs( -finishAngle + startAngle);
else if(( startAngle<0 && finishAngle<0 )|| (startAngle>0 && finishAngle>0 )){//BOTH START AND FINISH EITHER UPPER OR LOWER QUANDRANTS
if (finishAngle>startAngle){

arcAngle =abs(finishAngle-startAngle- 2* M_PI);

}
else{
arcAngle =abs(finishAngle-startAngle);

}

}
else
arcAngle = abs(finishAngle – startAngle);
}

rx = EditCurve[0].fX – CenterPoint.fX;
ry = EditCurve[0].fY – CenterPoint.fY;
for (int i=1; i <= 29; i++) {
float angle = i*arcAngle/29.0;
float dx,dy;
if (kVec.z ==-1){
dx = rx * cos(angle) – ry * sin(angle);
dy = rx * sin(angle) + ry * cos(angle);
}
else{
dx = rx * cos(-angle) – ry * sin(-angle);
dy = rx * sin(-angle) + ry * cos(-angle);
}

EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy);
}
EditCurve[30]=CenterPoint;
EditCurve[31]= EditCurve[0];

sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr3);
return;
}
break;
}
applyCursor();

}

So… Unless I missed something as far as the arc logic in mouse moves… It’s done…. Now on to setting cw and ccw

DrawSketchHandlerLineSet walk through

I’ve been trying to get the silly arc going without really understanding how the whole line thing draws out so I thought it be good for me to work it out.    The polyline code migrates back and forth through mousemoves, mouse down and mouse up events…  There’s are lot of weaving in and out, of varying states so it’s sort of hard to figure out what’s going on.    I got the code hacked up to start incorporating the arc, but only the line portion is fully functional at this point(The enums are slightly different. Once again this may only make sense to me…

I’m wondering if I be better off flowcharting this out, but…let  see if this works…
Ok.. So the DrawSketchHanlderLineSet Object gets create here:

void CmdSketcherCreatePolyline::activated(int iMsg)
{
ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerLineSet() );
}

So… This will fire off the constructor

DrawSketchHandlerLineSet()
: Mode(STATUS_LINE_SEEK_First),EditCurve(2),firstPoint(-1),previousCurve(-1),LineMode(LINE_MODE_Line){
keyArcValue=(int)SoKeyboardEvent::A;
}

STATUS_LINE_SEE_First, LineMode, KeyArcValue are my creations…..

So… what are these variables getting initialized: (Bold was prehacked)
std::vector<Base::Vector2D> EditCurve;
    Base::Vector2D lastPos;
    int firstPoint;
    int firstCurve;
    int previousCurve;
    std::vector<AutoConstraint> sugConstr1, sugConstr2, sugConstr3;

Base::Vector2D CenterPoint;
float rx, ry, startAngle, endAngle, arcAngle;

private:
int keyArcValue;
SelectLineMode LineMode;

 

So EditCurve is a freecad construct and everything else seems seems pretty straight forward except for the suggested constraints.

 

The Vector2D is defined within ../src/Base/Tools2D.h

 

namespace Base {

class Vector2D;
class BoundBox2D;
class Line2D;
class Polygon2D;

/**
* The vector class for 2D calculations.
*/
class BaseExport Vector2D
{
public:
float fX, fY;

inline Vector2D (void);
inline Vector2D (float x, float y);
inline Vector2D (double x, double y);
inline Vector2D (const Vector2D &rclVct);

// methods
inline float Length (void) const;

// operators
inline Vector2D& operator= (const Vector2D &rclVct);
inline float     operator* (const Vector2D &rclVct) const;
inline bool      operator== (const Vector2D &rclVct) const;
inline Vector2D  operator+ (const Vector2D &rclVct) const;
inline Vector2D  operator- (const Vector2D &rclVct) const;

inline void Set (float fPX, float fPY);
inline void Scale (float fS);
inline void Normalize (void);
float GetAngle (const Vector2D &rclVect) const;
void  ProjToLine (const Vector2D &rclPt, const Vector2D &rclLine);
};

Note to self… that GetAngle function look like it could come in handy for me…
Ok… So I guess I should look at the AutoConstraint to see what that’s made out of..

// A Simple data type to hold basic information for suggested constraints
struct AutoConstraint
{
Sketcher::ConstraintType Type;
int Index;
};

enum Type
{
VERTEX,
CURVE
};

Everything appears straight forward  except I don’t know how the Index in the AutoConstraint structure is used yet.

So at this point, when I’m in polyline  the cursor shows is replaced by a polyline graphic and a coordinate.  This polyline graphic is being done further  upstream to the function I’m looking at the moment. And the coordinates are being set by setPositionText(onSketchPos)
The bolded test in the next routine are the lines which fire on a mouseMove prior to a buttton being clicked

 

virtual void mouseMove(Base::Vector2D onSketchPos)
{

setPositionText(onSketchPos);

// This addresses the Arc being enabled or disabled during
switch (LineMode){
case LINE_MODE_Arc:
switch(Mode){
case STATUS_ARC_SEEK_First:
case STATUS_ARC_SEEK_Second:
case STATUS_ARC_Do:
case STATUS_ARC_Close:
// we are in Arc mode and we are in an arc state.
// All is well
break;
case STATUS_LINE_SEEK_Second:
Mode =STATUS_ARC_SEEK_Second;
break;
default:
Mode =STATUS_ARC_SEEK_First;//Put us in the default arc state mode
}
break;
case LINE_MODE_Line:
switch(Mode){
case STATUS_LINE_SEEK_First:
case STATUS_LINE_SEEK_Second:
case STATUS_LINE_Do:
case STATUS_LINE_Close:
break;
case STATUS_ARC_SEEK_Second:
Mode =STATUS_LINE_SEEK_Second;
break;
default:
Mode =STATUS_LINE_SEEK_First;

}
break;
}
switch(Mode){
case STATUS_LINE_SEEK_First:
case STATUS_ARC_SEEK_First:
    if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
                    renderSuggestConstraintsCursor(sugConstr1);
                    return;
}
break;
case STATUS_LINE_SEEK_Second:
EditCurve[1] = onSketchPos;
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos – EditCurve[0])) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
break;
case STATUS_ARC_SEEK_Second:
float angle1 = atan2(onSketchPos.fY – CenterPoint.fY,
onSketchPos.fX – CenterPoint.fX) – startAngle;
float angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
for (int i=1; i <= 29; i++) {
float angle = i*arcAngle/29.0;
float dx = rx * cos(angle) – ry * sin(angle);
float dy = rx * sin(angle) + ry * cos(angle);
EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy);
}
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
break;
}

applyCursor();
}

Ok so If I disable setPositionText(onSketchPos) I don’t get the coordinates….

If I re-enable setPositionText(onSketchPos) and disable applyCursor()  I’m not seeing any obvious change in behavior so I need to do some digging to see what applyCursor does.

Stepping into I find myself here:

 

void DrawSketchHandler::applyCursor(void)
{
applyCursor(actCursor);
}

Soo what’s actCursor

 

class SketcherGuiExport DrawSketchHandler
{
public:
DrawSketchHandler();
virtual ~DrawSketchHandler();

virtual void activated(ViewProviderSketch *sketchgui){};
virtual void mouseMove(Base::Vector2D onSketchPos)=0;
virtual bool pressButton(Base::Vector2D onSketchPos)=0;
virtual bool releaseButton(Base::Vector2D onSketchPos)=0;
virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { return false; };

virtual void quit(void);

friend class ViewProviderSketch;

// get the actual highest vertex index, the next use will be +1
int getHighestVertexIndex(void);
// get the actual highest edge index, the next use will be +1
int getHighestCurveIndex(void);

int seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
const Base::Vector2D &Pos, const Base::Vector2D &Dir, Type selType = VERTEX);
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);

void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);
virtual void registerPressedKey(bool pressed, int key){};
protected:
// helpers
void setCursor( const QPixmap &p,int x,int y );
void unsetCursor(void);
void applyCursor(void);
void applyCursor(QCursor &newCursor);

ViewProviderSketch *sketchgui;
QCursor oldCursor;
QCursor actCursor;
};

So  applying the cursor goes.

void DrawSketchHandler::applyCursor(QCursor &newCursor)
{
Gui::MDIView* view = Gui::getMainWindow()->activeWindow();
if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();
viewer->getWidget()->setCursor(newCursor);
}
}


Ok… I hope I don’t need to go down to the coin layer in this path… So I think I stop here..
I’m still curious to  see If I can figure out where actCursor is set before going back

 

void DrawSketchHandler::setCursor(const QPixmap &p,int x,int y)
{
Gui::MDIView* view = Gui::getMainWindow()->activeWindow();
if (view && view->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) {
Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>(view)->getViewer();

oldCursor = viewer->getWidget()->cursor();
        QCursor cursor(p, x, y);
        actCursor = cursor;

viewer->getWidget()->setCursor(cursor);
}
}

Ok… I have

to know, what fires void DrawSketchHandler::setCursor(const QPixmap &p,int x,int y)

So setCursor is called by

(DrawSketchHandlerLineSet)

 

virtual void activated(ViewProviderSketch *sketchgui)
{
setCursor(QPixmap(cursor_createlineset),7,7);
}

which is called by:

// handler management ***************************************************************
void ViewProviderSketch::activateHandler(DrawSketchHandler *newHandler)
{
assert(edit);
assert(edit->sketchHandler == 0);
edit->sketchHandler = newHandler;
Mode = STATUS_SKETCH_UseHandler;
edit->sketchHandler->sketchgui = this;
edit->sketchHandler->activated(this);
}

Ohhhh… I think a light bulb sort of just flickered in my head here…. So sketchHandler is basically the pointer to DrawSketchHandlerLineSet.  How that gets set, I hope to avoid at the moment but this is all starting to make sense….
Now let see if I can collapse and get back to my walk through….

So I’m at this line of code:

 

    if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
                    renderSuggestConstraintsCursor(sugConstr1);
                    return;
}
break;

Basically what it does is a  little dot to the cursor showing a point or line on the highlighted object based on whether we’re looking a  point, line or arc.
Points to note… the actual bolding of the selected object is happening further up stream… We’re just messing with the cursor here.

As interesting as it might be to drill into seekAutoConstraint, as well as the activated inside DrawSketchHandlerLineSet (which does some really cools stuff) I think I need to move unto the next part of the life cycle of the polyline….

The next thing I need to follow is when the mousedown is pressed.

————————————————————————-

 

virtual bool pressButton(Base::Vector2D onSketchPos){

switch (Mode){

case STATUS_LINE_SEEK_First:
// remember our first point
firstPoint = getHighestVertexIndex() + 1;
firstCurve = getHighestCurveIndex() + 1;
EditCurve[0] = onSketchPos;
Mode = STATUS_LINE_SEEK_Second;
break;

Alrighty… This is less studied for me, so I need really dissect what’s going on here:
so firstPoint and firstCurve are int’s which are….????? fairly obvious what I need to step into here:

/** Handler to create new sketch geometry
* This class has to be reimplemented to create geometry in the
* sketcher while its in editing.
*/
class SketcherGuiExport DrawSketchHandler
{
public:
DrawSketchHandler();
virtual ~DrawSketchHandler();

virtual void activated(ViewProviderSketch *sketchgui){};
virtual void mouseMove(Base::Vector2D onSketchPos)=0;
virtual bool pressButton(Base::Vector2D onSketchPos)=0;
virtual bool releaseButton(Base::Vector2D onSketchPos)=0;
virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { return false; };

virtual void quit(void);

friend class ViewProviderSketch;

    // get the actual highest vertex index, the next use will be +1
    int getHighestVertexIndex(void);
    // get the actual highest edge index, the next use will be +1
    int getHighestCurveIndex(void);

int seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
const Base::Vector2D &Pos, const Base::Vector2D &Dir, Type selType = VERTEX);
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);

void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);
virtual void registerPressedKey(bool pressed, int key){};
protected:
// helpers
void setCursor( const QPixmap &p,int x,int y );
void unsetCursor(void);
void applyCursor(void);
void applyCursor(QCursor &newCursor);

ViewProviderSketch *sketchgui;
QCursor oldCursor;
QCursor actCursor;
};

} // namespace SketcherGui

A few things I find noteworthy here are that getHighestVertexIndex and getHighestCurveIndex is that these are not virtual functions so all the business is being handled by the DrawSketchHandler base class… So probably a bunch of coin stuff?  (Hopefully, I can stay on the outer layers to get what I need  done…)

 

int DrawSketchHandler::getHighestVertexIndex(void)
{
return sketchgui->getSketchObject()->getHighestVertexIndex();
}

int DrawSketchHandler::getHighestCurveIndex(void)
{
return sketchgui->getSketchObject()->getHighestCurveIndex();
}

Oh boy…. so  what the heck is sketchgui….

class SketcherGuiExport DrawSketchHandler
{
public:
DrawSketchHandler();
virtual ~DrawSketchHandler();

virtual void activated(ViewProviderSketch *sketchgui){};
virtual void mouseMove(Base::Vector2D onSketchPos)=0;
virtual bool pressButton(Base::Vector2D onSketchPos)=0;
virtual bool releaseButton(Base::Vector2D onSketchPos)=0;
virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { return false; };

virtual void quit(void);

friend class ViewProviderSketch;

// get the actual highest vertex index, the next use will be +1
int getHighestVertexIndex(void);
// get the actual highest edge index, the next use will be +1
int getHighestCurveIndex(void);

int seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
const Base::Vector2D &Pos, const Base::Vector2D &Dir, Type selType = VERTEX);
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);

void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);
virtual void registerPressedKey(bool pressed, int key){};
protected:
// helpers
void setCursor( const QPixmap &p,int x,int y );
void unsetCursor(void);
void applyCursor(void);
void applyCursor(QCursor &newCursor);

ViewProviderSketch *sketchgui;
QCursor oldCursor;
QCursor actCursor;
};

Ahhh ViewProviderSketch,  I’ve dealt with you before, keypresses and mouse clicks get fed into DrawSketchHandlerLineSet through you..
So… how does the pointer to sketchgui get set…

Well,
Not through the constructor:

DrawSketchHandler::DrawSketchHandler()
: sketchgui(0)
{

}

Hmm.. I think the pointer to sketchgui gets set here:

// handler management ***************************************************************
void ViewProviderSketch::activateHandler(DrawSketchHandler *newHandler)
{
assert(edit);
assert(edit->sketchHandler == 0);
edit->sketchHandler = newHandler;
Mode = STATUS_SKETCH_UseHandler;
edit->sketchHandler->sketchgui = this;
edit->sketchHandler->activated(this);
}

And it looks like  ViewProvider sketch sets things in motion.
Ok… One more thing to look at… What is all defined in ViewProviderSketch.
I’m still trying to trace sketchgui->getSketchObject()->getHighestVertexIndex();

 

class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObject, public Gui::SelectionObserver
{
PROPERTY_HEADER(PartGui::ViewProviderSketch);

public:
/// constructor
ViewProviderSketch();
/// destructor
virtual ~ViewProviderSketch();

App::PropertyBool Autoconstraints;

/// draw constraint icon given the constraint id
void drawConstraintIcons();
/// draw the sketch in the inventor nodes
void draw(bool temp=false);
/// draw the edit curve
void drawEdit(const std::vector<Base::Vector2D> &EditCurve);

/// Is the view provider selectable
bool isSelectable(void) const;
/// Observer message from the Selection
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);

/** @name handler control */
//@{
/// sets an DrawSketchHandler in control
void activateHandler(DrawSketchHandler *newHandler);
/// removes the active handler
void purgeHandler(void);
//@}

/** @name modus handling */
//@{
/// mode table
enum SketchMode{
STATUS_NONE,              /**< enum value View provider is in neutral. */
STATUS_SELECT_Point,      /**< enum value a point was selected. */
STATUS_SELECT_Edge,       /**< enum value a edge was selected. */
STATUS_SELECT_Constraint, /**< enum value a constraint was selected. */
STATUS_SELECT_Cross,      /**< enum value the base coordinate system was selected. */
STATUS_SKETCH_DragPoint,  /**< enum value while dragging a point. */
STATUS_SKETCH_DragCurve,  /**< enum value while dragging a curve. */
STATUS_SKETCH_DragConstraint,  /**< enum value while dragging a compatible constraint. */
STATUS_SKETCH_UseHandler  /**< enum value a DrawSketchHandler is in control. */
};
/// is called by GuiCommands to set the drawing mode
void setSketchMode(SketchMode mode) {Mode = mode;}
/// get the sketch mode
SketchMode getSketchMode(void) const {return Mode;}
//@}

/** @name helper functions */
//@{
/// give the coordinates of a line on the sketch plane in sketcher (2D) coordinates
void getCoordsOnSketchPlane(double &u, double &v,const SbVec3f &point, const SbVec3f &normal);
/// helper to detect preselection
//bool handlePreselection(const SoPickedPoint *pp);
/// helper to detect preselection
bool detectPreselection(const SoPickedPoint *Point, int &PtIndex,int &CurvIndex, int &ConstrIndex, int &CrossIndex);
/// helper change the color of the sketch according to selection and solver status
void updateColor(void);
/// get the pointer to the sketch document object
Sketcher::SketchObject *getSketchObject(void) const;

/// snap points x,y (mouse coordinates) onto grid if enabled
void snapToGrid(double &x, double &y);

/// moves a selected constraint
void moveConstraint(int constNum, const Base::Vector2D &toPos);
/// checks if there is a constraint object at position vector
bool isConstraintAtPosition(const Base::Vector3d &constrPos, const SoNode *constraint);
/// finds a free position for placing a constraint icon
Base::Vector3d seekConstraintPosition(const Base::Vector3d &suggestedPos,
const Base::Vector3d &dir, float step,
const SoNode *constraint);

float getScaleFactor();
int getPreselectPoint(void) const;
int getPreselectCurve(void) const;
int getPreselectConstraint(void) const;
//@}

/** @name base class implementer */
//@{
virtual void attach(App::DocumentObject *);
virtual void updateData(const App::Property *);

virtual void setupContextMenu(QMenu *menu, QObject *receiver, const char *member);
/// is called when the Provider is in edit and a deletion request occurs
virtual bool onDelete(const std::vector<std::string> &);
/// is called by the tree if the user double click on the object
virtual bool doubleClicked(void);
/// is called when the Provider is in edit and the mouse is moved
virtual bool mouseMove(const SbVec3f &pNear, const SbVec3f &pFar, const SoPickedPoint *pp);
/// is called when the Provider is in edit and a key event ocours. Only ESC ends edit.
virtual bool keyPressed(bool pressed, int key);
/// is called when the Provider is in edit and the mouse is clicked
virtual bool mouseButtonPressed(int Button, bool pressed, const SbVec3f &point,
const SbVec3f &normal, const SoPickedPoint *pp);
//@}

friend class DrawSketchHandler;

/// signals if the constraints list has changed
boost::signal<void ()> signalConstraintsChanged;
/// signals if the sketch has been set up
boost::signal<void (int type, int dofs, std::string &msg)> signalSetUp;
/// signals if the sketch has been solved
boost::signal<void (int type, float time)> signalSolved;

protected:
virtual bool setEdit(int ModNum);
virtual void unsetEdit(int ModNum);
virtual void setEditViewer(Gui::View3DInventorViewer*, int ModNum);
virtual void unsetEditViewer(Gui::View3DInventorViewer*);
/// helper to detect whether the picked point lies on the sketch
bool isPointOnSketch(const SoPickedPoint *pp) const;
/// get called by the container whenever a property has been changed
virtual void onChanged(const App::Property *prop);

/// get called if a subelement is double clicked while editing
void editDoubleClicked(void);

/// set up the edition data structure EditData
void createEditInventorNodes(void);
/// pointer to the edit data structure if the ViewProvider is in edit.
EditData *edit;
/// build up the visual of the constraints
void rebuildConstraintsVisual(void);

void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);

// handle preselection and selection of points
void setPreselectPoint(int PreselectPoint);
void resetPreselectPoint(void);
void addSelectPoint(int SelectPoint);
void removeSelectPoint(int SelectPoint);
void clearSelectPoints(void);

// modes while sketching
SketchMode Mode;

// colors
static SbColor VertexColor;
static SbColor CurveColor;
static SbColor CurveDraftColor;
static SbColor CurveExternalColor;
static SbColor CrossColorV;
static SbColor CrossColorH;
static SbColor FullyConstrainedColor;
static SbColor ConstrDimColor;
static SbColor ConstrIcoColor;
static SbColor PreselectColor;
static SbColor SelectColor;

static SbTime prvClickTime;
static SbVec3f prvClickPoint;

float zCross;
float zLines;
float zPoints;
float zConstr;
float zHighlight;
float zText;
float zEdit;

// reference coordinates for relative operations
double xInit,yInit;
bool relative;
};

Oh darn… the C++ train has just come to a halt…
Sketcher::SketchObject *getSketchObject(void) const;   has got me a bit confused..  It appears to be a function which a point to sketch object.   If that’s the case there should an implementation of it in the ViewProviderSketch.cpp. (and there is..)

 

Sketcher::SketchObject *ViewProviderSketch::getSketchObject(void) const
{
return dynamic_cast<Sketcher::SketchObject *>(pcObject);
}

So I use this line make sense than sketchgui->getSketchObject()->getHighestVertexIndex()

And now a new player has just arrived on the seen pcObject politcally correct?
When I hover my cursor in the QT id it tells me this is off type App:DocumentObject

I’m some what confused by the pcObject when I do a search for this, it show’s up in a bunch of spots.  At first glance it seems like this variable name is redeclared a whole bunch of times… but think this variable should be defined either in ViewProviderSketch or one of its inherited classes.
class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObject, public Gui::SelectionObserver

Not in ViewProviderSketch

class PartGuiExport ViewProvider2DObject: public PartGui::ViewProviderPart

Not in ViewProvider2Object

class PartGuiExport ViewProviderPart : public ViewProviderPartExt

Not in ViewProviderPartExt

class PartGuiExport ViewProviderPartExt : public Gui::ViewProviderGeometryObject

ViewProviderGeometryObject has a reference to it but it’s not declared

class GuiExport ViewProviderGeometryObject : public ViewProviderDocumentObject

Bingo..

class GuiExport ViewProviderDocumentObject : public ViewProvider
{
PROPERTY_HEADER(Gui::ViewProviderDocumentObject);

public:
/// constructor.
ViewProviderDocumentObject();

/// destructor.
virtual ~ViewProviderDocumentObject();

// Display properties
App::PropertyEnumeration DisplayMode;
App::PropertyBool Visibility;

virtual void attach(App::DocumentObject *pcObject);
/// Get the default display mode
virtual const char* getDefaultDisplayMode() const;
/// Return a list of all possible modes
virtual std::vector<std::string> getDisplayModes(void) const;
/// Set the active mode, i.e. the first item of the ‘Display’ property.
void setActiveMode();
/// Hide the object in the view
virtual void hide(void);
/// Show the object in the view
virtual void show(void);

/// Get a list of TaskBoxes associated with this object
virtual void getTaskViewContent(std::vector<Gui::TaskView::TaskContent*>&) const;

/// Run a redraw
void updateView();
/// Gets called if some of the property hade bin changed
virtual void updateData(const App::Property*){};
/// Get the object of this ViewProvider object
App::DocumentObject *getObject(void) const {return pcObject;}
/// Get the python wrapper for that ViewProvider
PyObject* getPyObject();

/** @name Restoring view provider from document load */
//@{
virtual void startRestoring();
virtual void finishRestoring();
//@}

protected:
/// Get the active mdi view of a view provider
Gui::MDIView* getActiveView() const;
/// Gets called by the container whenever a property has been changed
virtual void onChanged(const App::Property* prop);
/** Searches in all view providers that are attached to an object that
* is part of the same document as the object this view provider is
* attached to for an front root of \a type.
* Before calling this function this view provider has to be attached
* to an object. The method returns after the first front root node
* matches. If no front root node matches, 0 is returned.
*/
SoNode* findFrontRootOfType(const SoType& type) const;

protected:
App::DocumentObject *pcObject;

private:
std::vector<const char*> aDisplayEnumsArray;
std::vector<std::string> aDisplayModesArray;
};

} // namespace Gui

Eeeeeh..  Ok… looking back at my notes, I’m trying to understand what’s going on with

int DrawSketchHandler::getHighestVertexIndex(void)
{
return sketchgui->getSketchObject()->getHighestVertexIndex();
}

int DrawSketchHandler::getHighestCurveIndex(void)
{
return sketchgui->getSketchObject()->getHighestCurveIndex();
}

 

Ok…

namespace Sketcher
{

class SketcherExport SketchObject : public Part::Part2DObject
{
PROPERTY_HEADER(Sketcher::SketchObject);

public:
SketchObject();
~SketchObject();

/// Property
Part    ::PropertyGeometryList   Geometry;
Sketcher::PropertyConstraintList Constraints;
App     ::PropertyLinkSubList    ExternalGeometry;
/** @name methods overide Feature */
//@{
/// recalculate the Feature
App::DocumentObjectExecReturn *execute(void);

/// returns the type name of the ViewProvider
const char* getViewProviderName(void) const {
return “SketcherGui::ViewProviderSketch”;
}
//@}

/// add unspecified geometry
int addGeometry(const Part::Geometry *geo);
/// add unspecified geometry
int addGeometry(const std::vector<Part::Geometry *> &geoList);
/// delete geometry
int delGeometry(int GeoId);
/// add all constraints in the list
int addConstraints(const std::vector<Constraint *> &ConstraintList);
/// add constraint
int addConstraint(const Constraint *constraint);
/// delete constraint
int delConstraint(int ConstrId);
int delConstraintOnPoint(int GeoId, PointPos PosId, bool onlyCoincident=true);
int delConstraintOnPoint(int VertexId, bool onlyCoincident=true);
/// transfers all contraints of a point to a new point
int transferConstraints(int fromGeoId, PointPos fromPosId, int toGeoId, PointPos toPosId);
/// add an external geometry reference
int addExternal(App::DocumentObject *Obj, const char* SubName);
/** delete external
*  ExtGeoId >= 0 with 0 corresponding to the first user defined
*  external geometry
*/
int delExternal(int ExtGeoId);

/** returns a pointer to a given Geometry index, possible indexes are:
*  id>=0 for user defined geometries,
*  id==-1 for the horizontal sketch axis,
*  id==-2 for the vertical sketch axis
*  id<=-3 for user defined projected external geometries,
*/
const Part::Geometry* getGeometry(int GeoId) const;
/// returns a list of all internal geometries
const std::vector<Part::Geometry *> &getInternalGeometry(void) const { return Geometry.getValues(); }
/// returns a list of projected external geometries
const std::vector<Part::Geometry *> &getExternalGeometry(void) const { return ExternalGeo; }
/// rebuilds external geometry (projection onto the sketch plane)
void rebuildExternalGeometry(void);
/// returns the number of external Geometry entities
int getExternalGeometryCount(void) const { return ExternalGeo.size(); }

/// retrieves a vector containing both normal and external Geometry (including the sketch axes)
std::vector<Part::Geometry*> getCompleteGeometry(void) const;

/// returns non zero if the sketch contains conflicting constraints
int hasConflicts(void) const;

/// set the datum of a Distance or Angle constraint and solve
int setDatum(int ConstrId, double Datum);
/// move this point to a new location and solve
int movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative=false);
/// retrieves the coordinates of a point
Base::Vector3d getPoint(int GeoId, PointPos PosId) const;

/// toggle geometry to draft line
int toggleConstruction(int GeoId);

/// create a fillet
int fillet(int geoId, PointPos pos, double radius, bool trim=true);
int fillet(int geoId1, int geoId2,
const Base::Vector3d& refPnt1, const Base::Vector3d& refPnt2,
double radius, bool trim=true);

/// trim a curve
int trim(int geoId, const Base::Vector3d& point);

/// retrieves for a Vertex number the corresponding GeoId and PosId
void getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId);
    int getHighestVertexIndex(void) const { return VertexId2GeoId.size() – 1; }
    int getHighestCurveIndex(void) const { return Geometry.getSize() – 1; }
void rebuildVertexIndex(void);

/// retrieves for a Vertex number a list with all coincident points
void getCoincidentPoints(int GeoId, PointPos PosId, std::vector<int> &GeoIdList,
std::vector<PointPos> &PosIdList);
void getCoincidentPoints(int VertexId, std::vector<int> &GeoIdList, std::vector<PointPos> &PosIdList);

/// generates a warning message about constraint conflicts and appends it to the given message
static void appendConflictMsg(const std::vector<int> &conflicting, std::string &msg);

// from base class
virtual PyObject *getPyObject(void);
virtual unsigned int getMemSize(void) const;
virtual void Save(Base::Writer &/*writer*/) const;
virtual void Restore(Base::XMLReader &/*reader*/);

/// returns the number of construction lines (to be used as axes)
virtual int getAxisCount(void) const;
/// retrieves an axis iterating through the construction lines of the sketch (indices start at 0)
virtual Base::Axis getAxis(int axId) const;

protected:
/// get called by the container when a property has changed
virtual void onChanged(const App::Property* /*prop*/);
virtual void onDocumentRestored();
virtual void onFinishDuplicating();

private:
std::vector<Part::Geometry *> ExternalGeo;

std::vector<int> VertexId2GeoId;
std::vector<PointPos> VertexId2PosId;
};

typedef App::FeaturePythonT<SketchObject> SketchObjectPython;

} //namespace Sketcher

——-

So I narrowing in on this stuff in on this so the sketch object has a PropertyGeometryList object defined within it.

class PartExport PropertyGeometryList: public App::PropertyLists
{
TYPESYSTEM_HEADER();

public:
/**
* A constructor.
* A more elaborate description of the constructor.
*/
PropertyGeometryList();

/**
* A destructor.
* A more elaborate description of the destructor.
*/
virtual ~PropertyGeometryList();

virtual void setSize(int newSize);
virtual int getSize(void) const;

/** Sets the property
*/
void setValue(const Geometry*);
void setValues(const std::vector<Geometry*>&);

/// index operator
const Geometry *operator[] (const int idx) const {
return _lValueList[idx];
}

const std::vector<Geometry*> &getValues(void) const {
return _lValueList;
}

virtual PyObject *getPyObject(void);
virtual void setPyObject(PyObject *);

virtual void Save(Base::Writer &writer) const;
virtual void Restore(Base::XMLReader &reader);

virtual Property *Copy(void) const;
virtual void Paste(const App::Property &from);

virtual unsigned int getMemSize(void) const;

private:
std::vector<Geometry*> _lValueList;
};

} // namespace Part

 

This just keeps going and going..

/** Base class of all property lists.
* The PropertyLists class is the base class for properties which can contain
* multiple values, not only a single value.
* All property types which may contain more than one value inherits this class.
*/
class AppExport PropertyLists : public Property
{
TYPESYSTEM_HEADER();

public:
virtual void setSize(int newSize)=0;
virtual int getSize(void) const =0;
};

} // namespace App

—–

And what sees what Property has in it..

namespace App
{

class PropertyContainer;

/** Base class of all properties
* This is the father of all properties. Properties are objects which are used
* in the document tree to parametrize e.g. features and their graphical output.
* They are also used to gain access from the scripting facility.
* /par
* This abstract base class defines all methods shared by all
* possible properties. It is also possible to define user properties
* and use them in the framework…
*/
class AppExport Property : public Base::Persistence
{
TYPESYSTEM_HEADER();

public:
Property();
virtual ~Property();

/** This method is used to get the size of objects
* It is not meant to have the exact size, it is more or less an estimation
* which runs fast! Is it two bytes or a GB?
* This method is defined in Base::Persistence
* @see Base::Persistence
*/
virtual unsigned int getMemSize (void) const {
// you have to implement this method in all property classes!
return Base::Persistence::getMemSize() + sizeof(father) + sizeof(StatusBits);
}

/// get the name of this property in the belonging container
const char* getName(void) const;

/// Get the class name of the associated property editor item
virtual const char* getEditorName(void) const { return “”; }

/// Get the type of the property in the container
short getType(void) const;

/// Get the group of this property
const char* getGroup(void) const;

/// Get the documentation of this property
const char* getDocumentation(void) const;

/// Is called by the framework to set the father (container)
void setContainer(PropertyContainer *Father);

/// Get a pointer to the PropertyContainer derived class the property belongs to
PropertyContainer *getContainer(void) const {return father;}
/// Set the property touched
void touch();
/// Test if this property is touched
bool isTouched(void) const {return StatusBits.test(0);}
/// Reset this property touched
void purgeTouched(void){StatusBits.reset(0);}

/// Returns a new copy of the property (mainly for Undo/Redo and transactions)
virtual Property *Copy(void) const = 0;
/// Paste the value from the property (mainly for Undo/Redo and transactions)
virtual void Paste(const Property &from) = 0;
/// Encodes an attribute upon saving.
std::string encodeAttribute(const std::string&) const;

friend class PropertyContainer;

/** Status bits of the property
* The first 8 bits are used for the base system the rest can be used in
* descendent classes to to mark special stati on the objects.
* The bits and their meaning are listed below:
* 0 – object is marked as ‘touched’
* 1 – object is marked as ‘immutable’
* 2 – object is marked as ‘read-ony’ (for property editor)
* 3 – object is marked as ‘hidden’ (for property editor)
*/
std::bitset<32> StatusBits;

protected:
/// Gets called by all setValue() methods after the value has changed
void hasSetValue(void);
/// Gets called by all setValue() methods before the value has changed
void aboutToSetValue(void);

private:
// forbidden
Property(const Property&);
Property& operator = (const Property&);

private:
PropertyContainer *father;
};

/** Base class of all property lists.
* The PropertyLists class is the base class for properties which can contain
* multiple values, not only a single value.
* All property types which may contain more than one value inherits this class.
*/
class AppExport PropertyLists : public Property
{
TYPESYSTEM_HEADER();

public:
virtual void setSize(int newSize)=0;
virtual int getSize(void) const =0;
};

} // namespace App

———

So… I went digging down so far, I kind of lost track of what I was trying to accomplish..   So I just went from mousemove and now we just pressed the button…

virtual bool pressButton(Base::Vector2D onSketchPos){

switch (Mode){

case STATUS_LINE_SEEK_First:
// remember our first point
firstPoint = getHighestVertexIndex() + 1;
firstCurve = getHighestCurveIndex() + 1;
EditCurve[0] = onSketchPos;
Mode = STATUS_LINE_SEEK_Second;
break;

…………………….
At this point, everything going on appears self-evident to me… I don’t understand the cuts of getHighestVertexIndex() and getHighestCurveIndex()  but perhaps I don’t need to at this point,
So the next step in the polyline life cycle should be:

(At this point, I haven’t hacked up any of this code yet, so its original… At this point, we’ve defined what the first point and first curve id will be and we’ve let go of the mouse button. Looking at the code (I haven’t stepped yet to verify, looks like release button only does something if (Mode==STATUS_LINE_Do || Mode==STATUS_LINE_Close), so we’re back to the mousemove

 

virtual bool releaseButton(Base::Vector2D onSketchPos)
{
//???? NEED TO FIGURE OUT to return
// getPolylineElementMode() returned here..

if (Mode==STATUS_LINE_Do || Mode==STATUS_LINE_Close) {
// open the transaction
Gui::Command::openCommand(“add sketch wire”);
// issue the geometry
Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))”,
sketchgui->getObject()->getNameInDocument(),
EditCurve[0].fX,EditCurve[0].fY,EditCurve[1].fX,EditCurve[1].fY);

// issue the constraint
if (previousCurve != -1) {
Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addConstraint(Sketcher.Constraint(‘Coincident’,%i,2,%i,1)) ”
,sketchgui->getObject()->getNameInDocument()
,previousCurve-1,previousCurve
);
}

if (Mode==STATUS_LINE_Close) {
// close the loop by constrain to the first curve point
Gui::Command::doCommand(Gui::Command::Doc,”App.ActiveDocument.%s.addConstraint(Sketcher.Constraint(‘Coincident’,%i,2,%i,1)) ”
,sketchgui->getObject()->getNameInDocument()
,previousCurve,firstCurve
);

Gui::Command::commitCommand();
Gui::Command::updateActive();

if (sugConstr2.size() > 0) {
// exclude any coincidence constraints
std::vector<AutoConstraint> sugConstr;
for (int i=0; i < sugConstr2.size(); i++) {
if (sugConstr2[i].Type != Sketcher::Coincident)
sugConstr.push_back(sugConstr2[i]);
}
createAutoConstraints(sugConstr, getHighestCurveIndex(), Sketcher::end);
sugConstr2.clear();
}

unsetCursor();
EditCurve.clear();
resetPositionText();
sketchgui->drawEdit(EditCurve);
sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider
}
else {
Gui::Command::commitCommand();
Gui::Command::updateActive();

// Add auto constraints
if (sugConstr1.size() > 0) {
createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::start);
sugConstr1.clear();
}

if (sugConstr2.size() > 0) {
createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::end);
sugConstr2.clear();
}

//remember the vertex for the next rounds constraint…
previousCurve = getHighestCurveIndex() + 1;

// setup for the next line segment
// Use updated endPoint as autoconstraints can modify the position
const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(getHighestCurveIndex());
if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) {
const Part::GeomLineSegment *lineSeg = dynamic_cast<const Part::GeomLineSegment *>(geom);
EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
}
else
EditCurve[0] = onSketchPos;

sketchgui->drawEdit(EditCurve);
applyCursor();

Mode = STATUS_LINE_SEEK_Second;
}
}
return true;
}

 

—————–

We’re back to the mousemove where Mode = STATUS_LINE_SEEK_Second

 

virtual void mouseMove(Base::Vector2D onSketchPos)
{

setPositionText(onSketchPos);

………………..
switch(Mode){
case STATUS_LINE_SEEK_First:
case STATUS_ARC_SEEK_First:
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr1);
return;
}
break;
case STATUS_LINE_SEEK_Second:
    EditCurve[1] = onSketchPos;
                sketchgui->drawEdit(EditCurve);
                if (seekAutoConstraint(sugConstr2, onSketchPos, onSketchPos – EditCurve[0])) {
                    renderSuggestConstraintsCursor(sugConstr2);
                    return;
                }
                break;

 

—–

At this point, everything seems to to be making sense to me up to this point, and I want to start working on drawing the arc in the mouse move up to the second click……  This blog post has gotten way to log for my tastes…

Working on the registerPressedKey for freecad polyline

Ok… So I thought I had the  registerPressedKey function working, but for some reason I’m generating a segmentation fault which I don’t understand at the moment ;(

So… I need to retrace my steps to see where things when south.

class SketcherGuiExport DrawSketchHandler
{
public:
DrawSketchHandler();
virtual ~DrawSketchHandler();

virtual void activated(ViewProviderSketch *sketchgui){};
virtual void mouseMove(Base::Vector2D onSketchPos)=0;
virtual bool pressButton(Base::Vector2D onSketchPos)=0;
virtual bool releaseButton(Base::Vector2D onSketchPos)=0;
virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { return false; };

virtual void quit(void);

friend class ViewProviderSketch;

// get the actual highest vertex index, the next use will be +1
int getHighestVertexIndex(void);
// get the actual highest edge index, the next use will be +1
int getHighestCurveIndex(void);

int seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
const Base::Vector2D &Pos, const Base::Vector2D &Dir, Type selType = VERTEX);
void createAutoConstraints(const std::vector<AutoConstraint> &autoConstrs,
int geoId, Sketcher::PointPos pointPos=Sketcher::none);

void setPositionText(const Base::Vector2D &Pos);
void resetPositionText(void);
void renderSuggestConstraintsCursor(std::vector<AutoConstraint> &suggestedConstraints);

    void registerPressedKey(bool pressed, SoKeyboardEvent::Key key);
    bool keyArcPressed(void);
 private:
    SoKeyboardEvent::Key keyArcValue;
    SoKeyboardEvent::Key mode;

protected:
// helpers
void setCursor( const QPixmap &p,int x,int y );
void unsetCursor(void);
void applyCursor(void);
void applyCursor(QCursor &newCursor);

ViewProviderSketch *sketchgui;
QCursor oldCursor;
QCursor actCursor;
};

} // namespace SketcherGui

I created keyArcValue value because, I wanted to leave the option to make it user configurable in the future…  I initialize it in the constructor.

—-

DrawSketchHandler::DrawSketchHandler()
: sketchgui(0)
{

//at some point may want to make keyArcValue user configurable
keyArcValue=SoKeyboardEvent::A;
mode=SoKeyboardEvent::ANY;

}

void DrawSketchHandler::registerPressedKey(bool pressed, SoKeyboardEvent::Key key)
{
if (pressed)
mode = key;
else
mode = SoKeyboardEvent::ANY;
}
bool DrawSketchHandler::keyArcPressed(void)
{
if (mode == keyArcValue)
return true;
else
return false;
}

—–
I’m having registerPressedKey called from here:

bool ViewProviderSketch::keyPressed(bool pressed, int key)
{
switch (key)
{
case SoKeyboardEvent::ESCAPE:
{
// make the handler quit but not the edit mode
if (edit && edit->sketchHandler) {
if (!pressed)
edit->sketchHandler->quit();
return true;
}
return false;
}
default:
{
edit->sketchHandler->registerPressedKey(pressed,(SoKeyboardEvent::Key)key);
}

}

return true; // handle all other key events
}

—-

Ok… So I’m in sketch mode (in debug) and I just press and depress the A key and I get this message

The inferior stopped because it received a signal from the Operating System.

Signal name :

SIGSEGV

Signal meaning :

Segmentation fault

And it debugger is on this line:

void DrawSketchHandler::registerPressedKey(bool pressed, SoKeyboardEvent::Key key)
{
if (pressed)
     mode = key;
else
mode = SoKeyboardEvent::ANY;
}
bool DrawSketchHandler::keyArcPressed(void)
{
if (mode == keyArcValue)
return true;
else
return false;
}

And the call stack looks like this:
0    SketcherGui::DrawSketchHandler::registerPressedKey    DrawSketchHandler.cpp    405    0x7fffd272880d
1    SketcherGui::ViewProviderSketch::keyPressed    ViewProviderSketch.cpp    286    0x7fffd2703a42
2    Gui::ViewProvider::eventCallback    ViewProvider.cpp    182    0x7ffff779a121
3    SoEventCallback::handleEvent(SoHandleEventAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51c3e0b
4    SoNode::handleEventS(SoAction*, SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff51dcda7
5    SoAction::traverse(SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff4fa44f7
6    SoChildList::traverse(SoAction*, int, int)    /usr/lib/libCoin.so.60    0    0x7ffff50f8ded
7    SoGroup::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51cffbb
8    SoSeparator::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51f393f
9    Gui::SoFCUnifiedSelection::handleEvent    SoFCUnifiedSelection.cpp    322    0x7ffff76f1ef9
10    SoNode::handleEventS(SoAction*, SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff51dcda7
11    SoAction::traverse(SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff4fa44f7
12    SoChildList::traverse(SoAction*, int, int)    /usr/lib/libCoin.so.60    0    0x7ffff50f8ded
13    SoGroup::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51cffbb
14    SoSeparator::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51f393f
15    SoNode::handleEventS(SoAction*, SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff51dcda7
16    SoAction::traverse(SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff4fa44f7
17    SoChildList::traverse(SoAction*, int, int)    /usr/lib/libCoin.so.60    0    0x7ffff50f8ded
18    SoGroup::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51cffbb
19    SoSeparator::doAction(SoAction*)    /usr/lib/libCoin.so.60    0    0x7ffff51f393f
20    SoNode::handleEventS(SoAction*, SoNode*)    /usr/lib/libCoin.so.60    0    0x7ffff51dcda7
…    <More>
Hmm.. I missing something obvious here:
Oh hold on….
Ah I think I know whats going on here:
DrawSketchHandler is inherited into DrawSketchhandlerline set and a bunch of other objects… If the keypress is depressed and none of these things are in memory…. Walla  seg fault…

 

 

 

Poking around drawedit.

I’m been poking around the code, and things have been more or less making sense to me until I ran into this draw edit thing…

void ViewProviderSketch::drawEdit(const std::vector<Base::Vector2D> &EditCurve)
{
assert(edit);

edit->EditCurveSet->numVertices.setNum(1);
edit->EditCurvesCoordinate->point.setNum(EditCurve.size());
SbVec3f *verts = edit->EditCurvesCoordinate->point.startEditing();
int32_t *index = edit->EditCurveSet->numVertices.startEditing();

int i=0; // setting up the line set
for (std::vector<Base::Vector2D>::const_iterator it = EditCurve.begin(); it != EditCurve.end(); ++it,i++)
verts[i].setValue(it->fX,it->fY,zEdit);

index[0] = EditCurve.size();
edit->EditCurvesCoordinate->point.finishEditing();
edit->EditCurveSet->numVertices.finishEditing();
}

I’m note really sure what’s going on here. So I’m going to attempt to figure this one out here…

Ok…It seems like the first thing I should look at is edit and see what’s up with that….

Sooo.. edit is a pointer to  a Structure EditData   declared in class ViewProviderSketch

struct EditData {
EditData():
sketchHandler(0),
DragPoint(-1),
DragCurve(-1),
DragConstraint(-1),
PreselectPoint(-1),
PreselectCurve(-1),
PreselectCross(-1),
PreselectConstraint(-1),
blockedPreselection(false),
FullyConstrained(false),
//ActSketch(0),
EditRoot(0),
PointsMaterials(0),
CurvesMaterials(0),
PointsCoordinate(0),
CurvesCoordinate(0),
CurveSet(0),
PointSet(0)
{}

// pointer to the active handler for new sketch objects
DrawSketchHandler *sketchHandler;

// dragged point
int DragPoint;
// dragged curve
int DragCurve;
// dragged constraint
int DragConstraint;

SbColor PreselectOldColor;
int PreselectPoint;
int PreselectCurve;
int PreselectCross;
int PreselectConstraint;
bool blockedPreselection;
bool FullyConstrained;

// pointer to the Solver
Sketcher::Sketch ActSketch;
// container to track our own selected parts
std::set<int> SelPointSet;
std::set<int> SelCurvSet; // also holds cross axes at -1 and -2
std::set<int> SelConstraintSet;

// helper data structure for the constraint rendering
std::vector<ConstraintType> vConstrType;

// nodes for the visuals
SoSeparator   *EditRoot;
SoMaterial    *PointsMaterials;
SoMaterial    *CurvesMaterials;
SoMaterial    *RootCrossMaterials;
SoMaterial    *EditCurvesMaterials;
SoCoordinate3 *PointsCoordinate;
SoCoordinate3 *CurvesCoordinate;
SoCoordinate3 *RootCrossCoordinate;
SoCoordinate3 *EditCurvesCoordinate;
SoLineSet     *CurveSet;
SoLineSet     *EditCurveSet;
SoLineSet     *RootCrossSet;
SoMarkerSet   *PointSet;

SoText2       *textX;
SoTranslation *textPos;

SoGroup       *constrGroup;
};

EditData *edit;

The structure look like this:
/// Data structure while edit the sketch
struct EditData {
EditData():
sketchHandler(0),
DragPoint(-1),
DragCurve(-1),
DragConstraint(-1),
PreselectPoint(-1),
PreselectCurve(-1),
PreselectCross(-1),
PreselectConstraint(-1),
blockedPreselection(false),
FullyConstrained(false),
//ActSketch(0),
EditRoot(0),
PointsMaterials(0),
CurvesMaterials(0),
PointsCoordinate(0),
CurvesCoordinate(0),
CurveSet(0),
PointSet(0)
{}

// pointer to the active handler for new sketch objects
DrawSketchHandler *sketchHandler;

// dragged point
int DragPoint;
// dragged curve
int DragCurve;
// dragged constraint
int DragConstraint;

SbColor PreselectOldColor;
int PreselectPoint;
int PreselectCurve;
int PreselectCross;
int PreselectConstraint;
bool blockedPreselection;
bool FullyConstrained;

// pointer to the Solver
Sketcher::Sketch ActSketch;
// container to track our own selected parts
std::set<int> SelPointSet;
std::set<int> SelCurvSet; // also holds cross axes at -1 and -2
std::set<int> SelConstraintSet;

// helper data structure for the constraint rendering
std::vector<ConstraintType> vConstrType;

// nodes for the visuals
SoSeparator   *EditRoot;
SoMaterial    *PointsMaterials;
SoMaterial    *CurvesMaterials;
SoMaterial    *RootCrossMaterials;
SoMaterial    *EditCurvesMaterials;
SoCoordinate3 *PointsCoordinate;
SoCoordinate3 *CurvesCoordinate;
SoCoordinate3 *RootCrossCoordinate;
SoCoordinate3 *EditCurvesCoordinate;
SoLineSet     *CurveSet;
SoLineSet     *EditCurveSet;
SoLineSet     *RootCrossSet;
SoMarkerSet   *PointSet;

SoText2       *textX;
SoTranslation *textPos;

SoGroup       *constrGroup;
};

Sooo..  the pointer edit is set to null in the ViewProviderSketch constructor.

edit has the address of a new object of type EditData that is created and assigned in  bool ViewProviderSketch::setEdit(int ModNum).

It seems that this object is destroyed in void ViewProviderSketch::unsetEdit(int ModNum)

void ViewProviderSketch::unsetEdit(int ModNum)
{
ShowGrid.setValue(false);
TightGrid.setValue(true);

edit->EditRoot->removeAllChildren();
pcRoot->removeChild(edit->EditRoot);

if (edit->sketchHandler)
purgeHandler();

delete edit;
edit = 0;

this->show();

// and update the sketch
getSketchObject()->getDocument()->recompute();

// clear the selection and set the new/edited sketch(convenience)
Gui::Selection().clearSelection();
std::string ObjName = getSketchObject()->getNameInDocument();
std::string DocName = getSketchObject()->getDocument()->getName();
Gui::Selection().addSelection(DocName.c_str(),ObjName.c_str());

// when pressing ESC make sure to close the dialog
Gui::Control().closeDialog();
}

Ok… I set a break point on setEdit and it seemed to break when a sketch is created

0    SketcherGui::ViewProviderSketch::setEdit    ViewProviderSketch.cpp    2683    0x7fffd672852d
1    Gui::ViewProvider::startEditing    ViewProvider.cpp    94    0x7ffff7799ca5
2    Gui::View3DInventorViewer::setEditingViewProvider    View3DInventorViewer.cpp    363    0x7ffff7776c5d
3    Gui::Document::setEdit    Document.cpp    188    0x7ffff75388cf
4    Gui::DocumentPy::setEdit    DocumentPyImp.cpp    108    0x7ffff75564cf
5    Gui::DocumentPy::staticCallback_setEdit    DocumentPy.cpp    399    0x7ffff75534cf
6    PyEval_EvalFrameEx    /usr/lib/libpython2.6.so.1.0    0    0x7ffff651a030
7    PyEval_EvalCodeEx    /usr/lib/libpython2.6.so.1.0    0    0x7ffff651bd60
8    PyEval_EvalCode    /usr/lib/libpython2.6.so.1.0    0    0x7ffff651be32
9    PyRun_StringFlags    /usr/lib/libpython2.6.so.1.0    0    0x7ffff6539d1c
10    Base::InterpreterSingleton::runString    Interpreter.cpp    117    0x7ffff69ed333
11    Gui::Command::doCommand    Command.cpp    413    0x7ffff75794bb
12    CmdSketcherNewSketch::activated    Command.cpp    156    0x7fffd66e2990
13    Gui::Command::invoke    Command.cpp    282    0x7ffff7578d6f
14    Gui::Action::onActivated    Action.cpp    82    0x7ffff756e4fb
15    Gui::Action::qt_metacall    moc_Action.cpp    73    0x7ffff7574d04
16    QMetaObject::activate(QObject*, QMetaObject const*, int, void**)    /usr/lib/libQtCore.so.4    0    0x7ffff15f2e3f
17    QAction::triggered(bool)    /usr/lib/libQtGui.so.4    0    0x7ffff2696032
18    QAction::activate(QAction::ActionEvent)    /usr/lib/libQtGui.so.4    0    0x7ffff26980ab
19    ??    /usr/lib/libQtGui.so.4    0    0x7ffff2ad739d
20    ??    /usr/lib/libQtGui.so.4    0    0x7ffff2adcdda
21    QWidget::event(QEvent*)    /usr/lib/libQtGui.so.4    0    0x7ffff26f2582
22    QMenu::event(QEvent*)    /usr/lib/libQtGui.so.4    0    0x7ffff2adef9b
23    QApplicationPrivate::notify_helper(QObject*, QEvent*)    /usr/lib/libQtGui.so.4    0    0x7ffff269c22c
24    QApplication::notify(QObject*, QEvent*)    /usr/lib/libQtGui.so.4    0    0x7ffff26a2ecb
25    Gui::GUIApplication::notify    Application.cpp    1465    0x7ffff751a1c1
26    QCoreApplication::notifyInternal(QObject*, QEvent*)    /usr/lib/libQtCore.so.4    0    0x7ffff15e006c
27    QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool)    /usr/lib/libQtGui.so.4    0    0x7ffff26a20ae
28    ??    /usr/lib/libQtGui.so.4    0    0x7ffff27223dd
29    QApplication::x11ProcessEvent(_XEvent*)    /usr/lib/libQtGui.so.4    0    0x7ffff27208ac
30    ??    /usr/lib/libQtGui.so.4    0    0x7ffff274c882
31    g_main_context_dispatch    /lib/libglib-2.0.so.0    0    0x7fffeb89e8c2
32    ??    /lib/libglib-2.0.so.0    0    0x7fffeb8a2748
33    g_main_context_iteration    /lib/libglib-2.0.so.0    0    0x7fffeb8a28fc
34    QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)    /usr/lib/libQtCore.so.4    0    0x7ffff1609513
35    ??    /usr/lib/libQtGui.so.4    0    0x7ffff274c46e
36    QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>)    /usr/lib/libQtCore.so.4    0    0x7ffff15de992
37    QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>)    /usr/lib/libQtCore.so.4    0    0x7ffff15ded6c
38    QCoreApplication::exec()    /usr/lib/libQtCore.so.4    0    0x7ffff15e2aab
39    Gui::Application::runApplication    Application.cpp    1689    0x7ffff7516557
40    main    MainGui.cpp    361    0x4096e7

void ViewProviderSketch::drawEdit(const std::vector<Base::Vector2D> &EditCurve)
{
assert(edit);

edit->EditCurveSet->numVertices.setNum(1);
edit->EditCurvesCoordinate->point.setNum(EditCurve.size());
SbVec3f *verts = edit->EditCurvesCoordinate->point.startEditing();
int32_t *index = edit->EditCurveSet->numVertices.startEditing();

int i=0; // setting up the line set
for (std::vector<Base::Vector2D>::const_iterator it = EditCurve.begin(); it != EditCurve.end(); ++it,i++)
verts[i].setValue(it->fX,it->fY,zEdit);

index[0] = EditCurve.size();
edit->EditCurvesCoordinate->point.finishEditing();
edit->EditCurveSet->numVertices.finishEditing();
}

Ok EditCurveSet is of type SoLineSet

http://doc.coin3d.org/Coin/classSoLineSet.html#_details

SoCoordinate3 *EditCurvesCoordinate;

http://doc.coin3d.org/Coin/classSoCoordinate3.html#_details

Ok… My brain is starting to ache..  I guess I need to look at this coin/inventor stuff.
I found a link to a pdf tutorial that looks fairly interesting; PG-GettingStarted.pdf

http://www.ims.tuwien.ac.at/teaching/vr/tutorial/content1.html

This  looks… like the place to get started:

http://www.cse.unr.edu/~b_yi/coin3d/chapter01/index.html

 

 

Peeking under the hood of DrawSketchHandlerArc::

I’ve been poking around DrawSketchHandlerArc  (Check around line 700 here) just trying to see how this thing ticks.
These notes probably won’t make sense to anyone but me, and probably if I go back to read them later, they won’t make sense to me either.

DrawSketchHandlerArc has a enumeration mode which consists of the following values:

   enum SelectMode {
STATUS_SEEK_First,      /**< enum value —-. */
STATUS_SEEK_Second,     /**< enum value —-. */
STATUS_SEEK_Third,      /**< enum value —-. */
STATUS_End
};

If you take a look at DrawSketchHandlerLineSet it has a similar enumeration that looks like:
enum SelectMode {
STATUS_SEEK_First,      /**< enum value —-. */
STATUS_SEEK_Second,     /**< enum value —-. */
STATUS_Do,
STATUS_Close
};

My oh my… there are some darn interesting things going  here:

I drew a couple of lines in polylines got out of that mode and went into draw arc…

 

in DrawSketchHandlerArc

virtual void mouseMove(Base::Vector2D onSketchPos)
{
setPositionText(onSketchPos);

if (Mode==STATUS_SEEK_First) {
if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) {
                renderSuggestConstraintsCursor(sugConstr1);
return;
}
}
else if (Mode==STATUS_SEEK_Second) {
float dx_ = onSketchPos.fX – EditCurve[0].fX;
float dy_ = onSketchPos.fY – EditCurve[0].fY;
for (int i=0; i < 16; i++) {
float angle = i*M_PI/16.0;
float dx = dx_ * cos(angle) + dy_ * sin(angle);
float dy = -dx_ * sin(angle) + dy_ * cos(angle);
EditCurve[1+i] = Base::Vector2D(EditCurve[0].fX + dx, EditCurve[0].fY + dy);
EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX – dx, EditCurve[0].fY – dy);
}
EditCurve[33] = EditCurve[1];
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr2);
return;
}
}
else if (Mode==STATUS_SEEK_Third) {
float angle1 = atan2(onSketchPos.fY – CenterPoint.fY,
onSketchPos.fX – CenterPoint.fX) – startAngle;
float angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ;
arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;
for (int i=1; i <= 29; i++) {
float angle = i*arcAngle/29.0;
float dx = rx * cos(angle) – ry * sin(angle);
float dy = rx * sin(angle) + ry * cos(angle);
EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy);
}
sketchgui->drawEdit(EditCurve);
if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) {
renderSuggestConstraintsCursor(sugConstr3);
return;
}
}
applyCursor();

}

There are a bunch of interesting functions at play:  (I was going to screen shoot this and post pretty pictures, put for some strange reason, screen shots are not picking up the red arc or constraint (which is a bit of a bummer).  The strange thing is that this is occurring if I just printscreen the form or the whole screen…

If the cursor is set over an element, it’s highlighted… (I think this is probably happening further up stream.)
Just to test that out //’d out everything I bolded above. I’m thinking the when I’m in arc mode, I should only see elements with focus light up… And the result is…
Ok.. This is interesting,  //setPositionText(onSketchPos); stop the display of the coordinates… no surprise there.

//renderSuggestConstraintsCursor(sugConstr1); Blocked displaying the constraint symbols (either constraint or tangency but the cursors was replaced with the Arc…   Ok… what I just noticed is that when I did a screen shot, the regular mouse cursor copied not the little arc…
It does appear that the objects with focus is indeed happening further upstream.. One more test to be sure is to put an immediate return on the mousemove after uncommenting everything.  Yep… object focus happening further up stream, but that’s no surprise.

Ok… Stepping between the mouse move and the button events is making sense to me up this point.  The next point of study is this

void ViewProviderSketch::drawEdit(const std::vector<Base::Vector2D> &EditCurve) and in particular I need to research SbVec3f

Off to the job….