[Sketcher] [C++] Issue 0002735, and Meaning of PosIDs in Angle constraint?

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
jnxd
Posts: 952
Joined: Mon Mar 30, 2015 2:30 pm
Contact:

[Sketcher] [C++] Issue 0002735, and Meaning of PosIDs in Angle constraint?

Post by jnxd »

While trying to resolve issue #2735 I hit a roadblock in the form of a question regarding the angle constraint. It appears that every constraint has a set of GeoId properties that indicate the feature(s) that are constrained, which are accessible from python, and a set of PosId properties that indicate the specific points, if any, on those features that are constrained, which are kept at C++ level. The PosId properties make sense for some constraints, like distance and coincident. But what do they mean for Angle constraints?

Angles make sense only for a pair of lines or line segments, but the FirstPosId and SecondPosID properties are still not set to None, which is probably a better option. However, they might also indicate the direction of the line wrt which the angle should be computed: if the angle is "A" between lines "l " and "m", it is (pi - A) between "l" and "-m". I can't find any documentation that tells what it means, so I'm asking it here.
abdullah
Veteran
Posts: 4935
Joined: Sun May 04, 2014 3:16 pm
Contact:

Re: [Sketcher] [C++] Issue 0002735, and Meaning of PosIDs in Angle constraint?

Post by abdullah »

Hi!

I am not sure if I am replying to what you are asking. Anyway:

GeoId is the identifier of a geometric object. There are a maximum of 3 GeoIds used within a Constraint (so a constraint can maximally involve 3 different objects):

Code: Select all

class SketcherExport Constraint : public Base::Persistence
{
    TYPESYSTEM_HEADER();

public:
    Constraint();
    Constraint(const Constraint&);
    virtual ~Constraint();
    virtual Constraint *clone(void) const; // does copy the tag, it will be treated as a rename by the expression engine.
    virtual Constraint *copy(void) const; // does not copy the tag, but generates a new one

    static const int GeoUndef;

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

    virtual PyObject *getPyObject(void);

    void setValue(double newValue);
    Base::Quantity getPresentationValue() const;
    double getValue() const;

    friend class Sketch;
    friend class PropertyConstraintList;

private:
    double Value;
public:
    ConstraintType Type;
    InternalAlignmentType AlignmentType;
    std::string Name;
    int First;
    PointPos FirstPos;
    int Second;
    PointPos SecondPos;
    int Third;
    PointPos ThirdPos;
    float LabelDistance;
    float LabelPosition;
    bool isDriving;

protected:
    boost::uuids::uuid tag;
};
PosId is a subidentifier within a geometric object. This is generally used to indicate the edge (none), starting point, ending point and mid point. Not all geometric objects have starting point, end point or midpoint. It is defined in Constraint.h as:

Code: Select all

/// define if you want to use the end or start point
enum PointPos { none, start, end, mid };
There are two types of angle constraints, the normal angle constraint, which defines two edges (so PosId=none) and the one implemented via "AngleViaPoint" (courtesy of DeepSOIC), which is defined by three points (those three points that you see in an angle, endpoints and vertex) and has an autolocking mechanism that substantially avoids the angle from flipping when dragging the whole (or during solving). For this second one, you define three points so PosId!=none for all three elements.

If you want to check this, open the sketcher, select a first point defining an endpoint, a second point defining another endpoint and a third point being the vertex where it hinges.

If you are curious about the code, the angle constraint creation code is in CommandConstraints.cpp, a excerpt:

Code: Select all

if (SubNames.size() == 3){//standalone implementation of angle-via-point

        //let's sink the point to be GeoId3. We want to keep the order the two curves have been selected in.
        if ( isVertex(GeoId1, PosId1) ){
            std::swap(GeoId1,GeoId2);
            std::swap(PosId1,PosId2);
        };
        if ( isVertex(GeoId2, PosId2) ){
            std::swap(GeoId2,GeoId3);
            std::swap(PosId2,PosId3);
        };
        
        bool bothexternal=checkBothExternal(GeoId1, GeoId2);

        if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) {
            double ActAngle = 0.0;

            openCommand("Add angle constraint");

            //add missing point-on-object constraints
            if(! IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)){
                Gui::Command::doCommand(
                    Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
                    selection[0].getFeatName(),GeoId3,PosId3,GeoId1);
            };
            if(! IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)){
                Gui::Command::doCommand(
                    Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
                    selection[0].getFeatName(),GeoId3,PosId3,GeoId2);
            };
            if(! IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)){//FIXME: it's a good idea to add a check if the sketch is solved
                Gui::Command::doCommand(
                    Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
                    selection[0].getFeatName(),GeoId3,PosId3,GeoId1);
            };

            //assuming point-on-curves have been solved, calculate the angle.
            //DeepSOIC: this may be slow, but I wanted to reuse the conversion from Geometry to GCS shapes that is done in Sketch
            Base::Vector3d p = Obj->getPoint(GeoId3, PosId3 );
            ActAngle = Obj->calculateAngleViaPoint(GeoId1,GeoId2,p.x,p.y);

            //negative constraint value avoidance
            if (ActAngle < -Precision::Angular()){
                std::swap(GeoId1, GeoId2);
                std::swap(PosId1, PosId2);
                ActAngle = -ActAngle;
            }

            Gui::Command::doCommand(
                Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('AngleViaPoint',%d,%d,%d,%d,%f)) ",
                selection[0].getFeatName(),GeoId1,GeoId2,GeoId3,PosId3,ActAngle);
            
            if (bothexternal || constraintCreationMode==Reference) { // it is a constraint on a external line, make it non-driving
                const std::vector<Sketcher::Constraint *> &ConStr = Obj->Constraints.getValues();
                
                Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.setDriving(%i,%s)",
                selection[0].getFeatName(),ConStr.size()-1,"False");
                finishDistanceConstraint(this, Obj,false);
            }
            else
                finishDistanceConstraint(this, Obj,true);
            
            return;
        };

    }
Regards,
Abdullah
User avatar
Kunda1
Veteran
Posts: 13434
Joined: Thu Jan 05, 2017 9:03 pm

Re: [Sketcher] [C++] Issue 0002735, and Meaning of PosIDs in Angle constraint?

Post by Kunda1 »

Alone you go faster. Together we go farther
Please mark thread [Solved]
Want to contribute back to FC? Checkout:
'good first issues' | Open TODOs and FIXMEs | How to Help FreeCAD | How to report Bugs
Post Reply