예제 #1
0
double DrawViewDimension::getDimValue() const
{
    double result = 0.0;
    if (!has2DReferences()) {                                            //happens during Dimension creation
        Base::Console().Message("INFO - DVD::getDimValue - Dimension has no References\n");
        return result;
    }

    if (!getViewPart()->hasGeometry()) {                              //happens when loading saved document
        Base::Console().Message("INFO - DVD::getDimValue ViewPart has no Geometry yet\n");
        return result;
    }

    if (MeasureType.isValue("True")) {
        // True Values
        if (!measurement->has3DReferences()) {
            return result;
        }
        if(Type.isValue("Distance")) {
            result = measurement->delta().Length();
        } else if(Type.isValue("DistanceX")){
            Base::Vector3d delta = measurement->delta();
            result = delta.x;
        } else if(Type.isValue("DistanceY")){
            Base::Vector3d delta = measurement->delta();
            result = delta.y;
        } else if(Type.isValue("DistanceZ")){
            Base::Vector3d delta = measurement->delta();
            result = delta.z;
        } else if(Type.isValue("Radius")){
            result =  measurement->radius();
        } else if(Type.isValue("Diameter")){
            result =  measurement->radius() * 2.0;
        } else if(Type.isValue("Angle")){
            result = measurement->angle();
        } else {
            throw Base::Exception("getDimValue() - Unknown Dimension Type (1)");
        }
    } else {
        // Projected Values
        const std::vector<App::DocumentObject*> &objects = References2D.getValues();
        const std::vector<std::string> &subElements      = References2D.getSubValues();
        if (Type.isValue("Distance") && getRefType() == oneEdge) {
            //TODO: Check for straight line Edge?
            int idx = DrawUtil::getIndexFromName(subElements[0]);
            TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx);
            TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom);
            Base::Vector2D start = gen->points[0];
            Base::Vector2D end = gen->points[1];
            Base::Vector2D line = end - start;
            result = line.Length() / getViewPart()->Scale.getValue();
        } else if (Type.isValue("Distance") && getRefType() == twoEdge) {
            //only works for straight line edges
            int idx0 = DrawUtil::getIndexFromName(subElements[0]);
            int idx1 = DrawUtil::getIndexFromName(subElements[1]);
            TechDrawGeometry::BaseGeom* geom0 = getViewPart()->getProjEdgeByIndex(idx0);
            TechDrawGeometry::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1);
            TechDrawGeometry::Generic* gen0 = static_cast<TechDrawGeometry::Generic*>(geom0);
            TechDrawGeometry::Generic* gen1 = static_cast<TechDrawGeometry::Generic*>(geom1);
            Base::Vector2D s0 = gen0->points[0];
            Base::Vector2D e0 = gen0->points[1];
            Base::Vector2D s1 = gen1->points[0];
            Base::Vector2D e1 = gen1->points[1];
            result = dist2Segs(s0,e0,s1,e1) / getViewPart()->Scale.getValue();
        } else if (Type.isValue("Distance") && getRefType() == twoVertex) {
            int idx0 = DrawUtil::getIndexFromName(subElements[0]);
            int idx1 = DrawUtil::getIndexFromName(subElements[1]);
            TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0);
            TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1);
            Base::Vector2D start = v0->pnt;
            Base::Vector2D end = v1->pnt;
            Base::Vector2D line = end - start;
            result = line.Length() / getViewPart()->Scale.getValue();
        } else if (Type.isValue("DistanceX") && getRefType() == oneEdge) {
            int idx = DrawUtil::getIndexFromName(subElements[0]);
            TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx);
            TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom);
            Base::Vector2D start = gen->points[0];
            Base::Vector2D end = gen->points[1];
            Base::Vector2D line = end - start;
            return fabs(line.fX) / getViewPart()->Scale.getValue();
        } else if (Type.isValue("DistanceY") && getRefType() == oneEdge) {
            int idx = DrawUtil::getIndexFromName(subElements[0]);
            TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx);
            TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom);
            Base::Vector2D start = gen->points[0];
            Base::Vector2D end = gen->points[1];
            Base::Vector2D line = end - start;
            result = fabs(line.fY) / getViewPart()->Scale.getValue();
        } else if (Type.isValue("DistanceX") && getRefType() == twoVertex) {
            int idx0 = DrawUtil::getIndexFromName(subElements[0]);
            int idx1 = DrawUtil::getIndexFromName(subElements[1]);
            TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0);
            TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1);
            Base::Vector2D start = v0->pnt;
            Base::Vector2D end = v1->pnt;
            Base::Vector2D line = end - start;
            result = fabs(line.fX) / getViewPart()->Scale.getValue();
        } else if (Type.isValue("DistanceY") && getRefType() == twoVertex) {
            int idx0 = DrawUtil::getIndexFromName(subElements[0]);
            int idx1 = DrawUtil::getIndexFromName(subElements[1]);
            TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0);
            TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1);
            Base::Vector2D start = v0->pnt;
            Base::Vector2D end = v1->pnt;
            Base::Vector2D line = end - start;
            result = fabs(line.fY) / getViewPart()->Scale.getValue();
        } else if(Type.isValue("Radius")){
            //only 1 reference for a Radius
            int idx = DrawUtil::getIndexFromName(subElements[0]);
            TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx);
            TechDrawGeometry::Circle* circle = static_cast<TechDrawGeometry::Circle*> (base);
            result = circle->radius / getViewPart()->Scale.getValue();            //Projected BaseGeom is scaled for drawing
        } else if(Type.isValue("Diameter")){
            //only 1 reference for a Diameter
            int idx = DrawUtil::getIndexFromName(subElements[0]);
            TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx);
            TechDrawGeometry::Circle* circle = static_cast<TechDrawGeometry::Circle*> (base);
            result = (circle->radius  * 2.0) / getViewPart()->Scale.getValue();   //Projected BaseGeom is scaled for drawing
        } else if(Type.isValue("Angle")){
            // Must project lines to 2D so cannot use measurement framework this time
            //Relcalculate the measurement based on references stored.
            //WF: why not use projected geom in GeomObject and Vector2D.GetAngle? intersection pt & direction issues?
            //TODO: do we need to distinguish inner vs outer angle? -wf
//            if(subElements.size() != 2) {
//                throw Base::Exception("FVD - Two references required for angle measurement");
//            }
            if (getRefType() != twoEdge) {
                throw Base::Exception("FVD - Two edge references required for angle measurement");
            }
            int idx0 = DrawUtil::getIndexFromName(subElements[0]);
            int idx1 = DrawUtil::getIndexFromName(subElements[1]);
            TechDraw::DrawViewPart *viewPart = dynamic_cast<TechDraw::DrawViewPart *>(objects[0]);
            TechDrawGeometry::BaseGeom* edge0 = viewPart->getProjEdgeByIndex(idx0);
            TechDrawGeometry::BaseGeom* edge1 = viewPart->getProjEdgeByIndex(idx1);

            // Only can find angles with straight line edges
            if(edge0->geomType == TechDrawGeometry::GENERIC &&
               edge1->geomType == TechDrawGeometry::GENERIC) {
                TechDrawGeometry::Generic *gen1 = static_cast<TechDrawGeometry::Generic *>(edge0);
                TechDrawGeometry::Generic *gen2 = static_cast<TechDrawGeometry::Generic *>(edge1);

                Base::Vector3d p1S(gen1->points.at(0).fX, gen1->points.at(0).fY, 0.);
                Base::Vector3d p1E(gen1->points.at(1).fX, gen1->points.at(1).fY, 0.);

                Base::Vector3d p2S(gen2->points.at(0).fX, gen2->points.at(0).fY, 0.);
                Base::Vector3d p2E(gen2->points.at(1).fX, gen2->points.at(1).fY, 0.);

                Base::Vector3d dir1 = p1E - p1S;
                Base::Vector3d dir2 = p2E - p2S;

                // Line Intersetion (taken from ViewProviderSketch.cpp)
                double det = dir1.x*dir2.y - dir1.y*dir2.x;
                if ((det > 0 ? det : -det) < 1e-10)
                    throw Base::Exception("Invalid selection - Det = 0");

                double c1 = dir1.y*gen1->points.at(0).fX - dir1.x*gen1->points.at(0).fY;
                double c2 = dir2.y*gen2->points.at(1).fX - dir2.x*gen2->points.at(1).fY;
                double x = (dir1.x*c2 - dir2.x*c1)/det;
                double y = (dir1.y*c2 - dir2.y*c1)/det;

                // Intersection point
                Base::Vector3d p0 = Base::Vector3d(x,y,0);

                Base::Vector3d lPos((double) X.getValue(), (double) Y.getValue(), 0.);
                //Base::Vector3d delta = lPos - p0;

                // Create vectors point towards intersection always
                Base::Vector3d a = -p0, b = -p0;
                a += ((p1S - p0).Length() < FLT_EPSILON) ? p1E : p1S;
                b += ((p2S - p0).Length() < FLT_EPSILON) ? p2E : p2S;

                double angle2 = atan2( a.x*b.y - a.y*b.x, a.x*b.x + a.y*b.y );
                result = angle2 * 180. / M_PI;
            } else {
                throw Base::Exception("getDimValue() - Unknown Dimension Type (2)");
            }
        }  //endif Angle
    } //endif Projected
    return result;
}
예제 #2
0
int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
                                          const Base::Vector2D& Pos, const Base::Vector2D& Dir,
                                          AutoConstraint::TargetType type)
{
    suggestedConstraints.clear();

    if (!sketchgui->Autoconstraints.getValue())
        return 0; // If Autoconstraints property is not set quit

    Base::Vector3d hitShapeDir = Base::Vector3d(0,0,0); // direction of hit shape (if it is a line, the direction of the line)
        
    // Get Preselection
    int preSelPnt = sketchgui->getPreselectPoint();
    int preSelCrv = sketchgui->getPreselectCurve();
    int preSelCrs = sketchgui->getPreselectCross();
    int GeoId = Constraint::GeoUndef;
    Sketcher::PointPos PosId = Sketcher::none;
    if (preSelPnt != -1)
        sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId);
    else if (preSelCrv != -1){
        GeoId = preSelCrv;
        const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId);
        
        if(geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()){
            const Part::GeomLineSegment *line = static_cast<const Part::GeomLineSegment *>(geom);
            hitShapeDir= line->getEndPoint()-line->getStartPoint();     
        }
            
    }
    else if (preSelCrs == 0) { // root point
        GeoId = -1;
        PosId = Sketcher::start;
    }
    else if (preSelCrs == 1){ // x axis
        GeoId = -1;
        hitShapeDir = Base::Vector3d(1,0,0);
        
    }
    else if (preSelCrs == 2){ // y axis
        GeoId = -2;
        hitShapeDir = Base::Vector3d(0,1,0);
    }

    if (GeoId != Constraint::GeoUndef) {
        // Currently only considers objects in current Sketcher
        AutoConstraint constr;
        constr.Type = Sketcher::None;
        constr.GeoId = GeoId;
        constr.PosId = PosId;
        if (type == AutoConstraint::VERTEX && PosId != Sketcher::none)
            constr.Type = Sketcher::Coincident;
        else if (type == AutoConstraint::CURVE && PosId != Sketcher::none)
            constr.Type = Sketcher::PointOnObject;
        else if (type == AutoConstraint::VERTEX && PosId == Sketcher::none)
            constr.Type = Sketcher::PointOnObject;
        else if (type == AutoConstraint::CURVE && PosId == Sketcher::none)
            constr.Type = Sketcher::Tangent;
        
        if(constr.Type == Sketcher::Tangent && Dir.Length() > 1e-8 && hitShapeDir.Length() > 1e-8) { // We are hitting a line and have hitting vector information
            Base::Vector3d dir3d = Base::Vector3d(Dir.fX,Dir.fY,0);
            double cosangle=dir3d.Normalize()*hitShapeDir.Normalize();
            
            // the angle between the line and the hitting direction are over around 6 degrees (it is substantially parallel)
            // or if it is an sketch axis (that can not move to accomodate to the shape), then only if it is around 6 degrees with the normal (around 84 degrees)
            if (fabs(cosangle) < 0.995f || ((GeoId==-1 || GeoId==-2) && fabs(cosangle) < 0.1))
                suggestedConstraints.push_back(constr);
            
            
            return suggestedConstraints.size();
        }

        if (constr.Type != Sketcher::None)
            suggestedConstraints.push_back(constr);
    }
        
    if (Dir.Length() < 1e-8 || type == AutoConstraint::CURVE)
        // Direction not set so return;
        return suggestedConstraints.size();

    // Suggest vertical and horizontal constraints

    // Number of Degree of deviation from horizontal or vertical lines
    const double angleDev = 2;
    const double angleDevRad = angleDev *  M_PI / 180.;

    AutoConstraint constr;
    constr.Type = Sketcher::None;
    constr.GeoId = Constraint::GeoUndef;
    constr.PosId = Sketcher::none;
    double angle = std::abs(atan2(Dir.fY, Dir.fX));
    if (angle < angleDevRad || (M_PI - angle) < angleDevRad )
        // Suggest horizontal constraint
        constr.Type = Sketcher::Horizontal;
    else if (std::abs(angle - M_PI_2) < angleDevRad)
        // Suggest vertical constraint
        constr.Type = Sketcher::Vertical;

    if (constr.Type != Sketcher::None)
        suggestedConstraints.push_back(constr);

    // Find if there are tangent constraints (currently arcs and circles)

    int tangId = Constraint::GeoUndef;

    // Do not consider if distance is more than that.
    // Decrease this value when a candidate is found.
    double tangDeviation = 0.1 * sketchgui->getScaleFactor();

    // Get geometry list
    const std::vector<Part::Geometry *> geomlist = sketchgui->getSketchObject()->getCompleteGeometry();

    Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f);                 // Current cursor point
    Base::Vector3d tmpDir(Dir.fX, Dir.fY, 0.f);                 // Direction of line
    Base::Vector3d tmpStart(Pos.fX-Dir.fX, Pos.fY-Dir.fY, 0.f);  // Start point

    // Iterate through geometry
    int i = 0;
    for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) {

        if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) {
            const Part::GeomCircle *circle = static_cast<const Part::GeomCircle *>((*it));

            Base::Vector3d center = circle->getCenter();

            double radius = circle->getRadius();

            // ignore if no touch (use dot product)
            if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0)
                continue;

            Base::Vector3d projPnt(0.f, 0.f, 0.f);
            projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir);
            double projDist = std::abs(projPnt.Length() - radius);

            // Find if nearest
            if (projDist < tangDeviation) {
                tangId = i;
                tangDeviation = projDist;
            }

        } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) {
            
            const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>((*it));

            Base::Vector3d center = ellipse->getCenter();

            double a = ellipse->getMajorRadius();
            double b = ellipse->getMinorRadius();
            Base::Vector3d majdir = ellipse->getMajorAxisDir();
            
            double cf = sqrt(a*a - b*b);
                
            Base::Vector3d focus1P = center + cf * majdir;
            Base::Vector3d focus2P = center - cf * majdir;
            
            Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize();
            
            double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line
                        
            Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line
            
            double error = fabs((focus1PMirrored-focus2P).Length() - 2*a);
            
            if ( error< tangDeviation) { 
                    tangId = i;
                    tangDeviation = error;
            }

        } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
            const Part::GeomArcOfCircle *arc = static_cast<const Part::GeomArcOfCircle *>((*it));

            Base::Vector3d center = arc->getCenter();
            double radius = arc->getRadius();

            // ignore if no touch (use dot product)
            if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0)
                continue;

            Base::Vector3d projPnt(0.f, 0.f, 0.f);
            projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir);
            double projDist = std::abs(projPnt.Length() - radius);

            if (projDist < tangDeviation) {
                double startAngle, endAngle;
                arc->getRange(startAngle, endAngle, /*emulateCCW=*/true);

                double angle = atan2(projPnt.y, projPnt.x);
                while(angle < startAngle)
                    angle += 2*D_PI;         // Bring it to range of arc

                // if the point is on correct side of arc
                if (angle <= endAngle) {     // Now need to check only one side
                    tangId = i;
                    tangDeviation = projDist;
                }
            }
        } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) {
            const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>((*it));

            Base::Vector3d center = aoe->getCenter();

            double a = aoe->getMajorRadius();
            double b = aoe->getMinorRadius();
            Base::Vector3d majdir = aoe->getMajorAxisDir();
            
            double cf = sqrt(a*a - b*b);
                
            Base::Vector3d focus1P = center + cf * majdir;
            Base::Vector3d focus2P = center - cf * majdir;
            
            Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize();
            
            double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line
                        
            Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line
            
            double error = fabs((focus1PMirrored-focus2P).Length() - 2*a);
            
            if ( error< tangDeviation ) {
                    tangId = i;
                    tangDeviation = error;
            }

            if (error < tangDeviation) {
                double startAngle, endAngle;
                aoe->getRange(startAngle, endAngle, /*emulateCCW=*/true);
                
                double angle = Base::fmod(
                    atan2(-aoe->getMajorRadius()*((tmpPos.x-center.x)*majdir.y-(tmpPos.y-center.y)*majdir.x),
                                aoe->getMinorRadius()*((tmpPos.x-center.x)*majdir.x+(tmpPos.y-center.y)*majdir.y)
                    )- startAngle, 2.f*M_PI); 
                
                while(angle < startAngle)
                    angle += 2*D_PI;         // Bring it to range of arc

                // if the point is on correct side of arc
                if (angle <= endAngle) {     // Now need to check only one side
                    tangId = i;
                    tangDeviation = error;
                }
            }
        }
    }

    if (tangId != Constraint::GeoUndef) {
        if (tangId > getHighestCurveIndex()) // external Geometry
            tangId = getHighestCurveIndex() - tangId;
        // Suggest vertical constraint
        constr.Type = Tangent;
        constr.GeoId = tangId;
        constr.PosId = Sketcher::none;
        suggestedConstraints.push_back(constr);
    }

    return suggestedConstraints.size();
}
예제 #3
0
int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints,
        const Base::Vector2D& Pos, const Base::Vector2D& Dir,
        AutoConstraint::TargetType type)
{
    suggestedConstraints.clear();

    if (!sketchgui->Autoconstraints.getValue())
        return 0; // If Autoconstraints property is not set quit

    // Get Preselection
    int preSelPnt = sketchgui->getPreselectPoint();
    int preSelCrv = sketchgui->getPreselectCurve();
    int GeoId = Constraint::GeoUndef;
    Sketcher::PointPos PosId = Sketcher::none;
    if (preSelPnt != -1)
        sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId);
    else if (preSelCrv != -1)
        GeoId = preSelCrv;

    // Currently only considers objects in current Sketcher
    AutoConstraint constr;
    constr.Type = Sketcher::None;
    constr.GeoId = GeoId;
    constr.PosId = PosId;
    if (type == AutoConstraint::VERTEX && preSelPnt != -1)
        constr.Type = Sketcher::Coincident;
    else if (type == AutoConstraint::CURVE && preSelPnt != -1)
        constr.Type = Sketcher::PointOnObject;
    else if (type == AutoConstraint::VERTEX && preSelCrv != -1)
        constr.Type = Sketcher::PointOnObject;
    else if (type == AutoConstraint::CURVE && preSelCrv != -1)
        constr.Type = Sketcher::Tangent;

    if (constr.Type != Sketcher::None)
        suggestedConstraints.push_back(constr);

    if (Dir.Length() < 1)
        // Direction not set so return;
        return suggestedConstraints.size();

    // Suggest vertical and horizontal constraints

    // Number of Degree of deviation from horizontal or vertical lines
    const double angleDev = 2;
    const double angleDevRad = angleDev *  M_PI / 180.;

    constr.Type = Sketcher::None;
    constr.GeoId = Constraint::GeoUndef;
    constr.PosId = Sketcher::none;
    double angle = std::abs(atan2(Dir.fY, Dir.fX));
    if (angle < angleDevRad || (M_PI - angle) < angleDevRad )
        // Suggest horizontal constraint
        constr.Type = Sketcher::Horizontal;
    else if (std::abs(angle - M_PI_2) < angleDevRad)
        // Suggest vertical constraint
        constr.Type = Sketcher::Vertical;

    if (constr.Type != Sketcher::None)
        suggestedConstraints.push_back(constr);

    // Find if there are tangent constraints (currently arcs and circles)
    // FIXME needs to consider when zooming out?
    const float tangDeviation = 2.;

    int tangId = Constraint::GeoUndef;
    float smlTangDist = 1e15f;

    // Get geometry list
    const std::vector<Part::Geometry *> geomlist = sketchgui->getSketchObject()->getCompleteGeometry();

    // Iterate through geometry
    int i = 0;
    for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) {

        if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) {
            const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>((*it));

            Base::Vector3d center = circle->getCenter();
            Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f);

            float radius = (float) circle->getRadius();

            Base::Vector3d projPnt(0.f, 0.f, 0.f);
            projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY));
            float projDist = projPnt.Length();

            if ( (projDist < radius + tangDeviation ) && (projDist > radius - tangDeviation)) {
                // Find if nearest
                if (projDist < smlTangDist) {
                    tangId = i;
                    smlTangDist = projDist;
                }
            }

        } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
            const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>((*it));

            Base::Vector3d center = arc->getCenter();
            double radius = arc->getRadius();

            Base::Vector3d projPnt(0.f, 0.f, 0.f);
            Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f);

            projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY));
            float projDist = projPnt.Length();

            if ( projDist < radius + tangDeviation && projDist > radius - tangDeviation) {
                double startAngle, endAngle;
                arc->getRange(startAngle, endAngle);

                projPnt += center;
                double angle = atan2(projPnt.y, projPnt.x);

                // if the pnt is on correct side of arc and find if nearest
                if ((angle > startAngle && angle < endAngle) &&
                        (projDist < smlTangDist) ) {
                    tangId = i;
                    smlTangDist = projDist;
                }
            }
        }
    }

    if (tangId != Constraint::GeoUndef) {
        if (tangId > getHighestCurveIndex()) // external Geometry
            tangId = getHighestCurveIndex() - tangId;
        // Suggest vertical constraint
        constr.Type = Tangent;
        constr.GeoId = tangId;
        constr.PosId = Sketcher::none;
        suggestedConstraints.push_back(constr);
    }

    return suggestedConstraints.size();
}