diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 3bc8f6710832..9e6e440ab405 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -1761,6 +1761,26 @@ int Sketch::addEqualConstraint(int geoId1, int geoId2) GCSsys.addConstraintEqualRadius(a1, a2, tag); return ConstraintsCounter; } + + if (Geoms[geoId2].type == ArcOfEllipse) { + if (Geoms[geoId1].type == ArcOfEllipse) { + GCS::ArcOfEllipse &a1 = ArcsOfEllipse[Geoms[geoId1].index]; + GCS::ArcOfEllipse &a2 = ArcsOfEllipse[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintEqualRadii(a1, a2, tag); + return ConstraintsCounter; + } + } + + if (Geoms[geoId1].type == Ellipse) { + GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; + if (Geoms[geoId2].type == ArcOfEllipse) { + GCS::ArcOfEllipse &a2 = ArcsOfEllipse[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintEqualRadii(a2, e1, tag); + return ConstraintsCounter; + } + } Base::Console().Warning("Equality constraints between %s and %s are not supported.\n", nameByType(Geoms[geoId1].type), nameByType(Geoms[geoId2].type)); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index a49a346b13ac..605166c53acd 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -30,11 +30,13 @@ # include # include # include +# include # include # include # include # include # include +# include # include # include # include @@ -957,8 +959,95 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) return 0; } } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { - // TODO: Ellipse Trim support + const Part::GeomEllipse *ellipse = dynamic_cast(geo); + Base::Vector3d center = ellipse->getCenter(); + double theta0 = Base::fmod( + atan2(-ellipse->getMajorRadius()*((point.x-center.x)*sin(ellipse->getAngleXU())-(point.y-center.y)*cos(ellipse->getAngleXU())), + ellipse->getMinorRadius()*((point.x-center.x)*cos(ellipse->getAngleXU())+(point.y-center.y)*sin(ellipse->getAngleXU())) + ), 2.f*M_PI); + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod( + atan2(-ellipse->getMajorRadius()*((point1.x-center.x)*sin(ellipse->getAngleXU())-(point1.y-center.y)*cos(ellipse->getAngleXU())), + ellipse->getMinorRadius()*((point1.x-center.x)*cos(ellipse->getAngleXU())+(point1.y-center.y)*sin(ellipse->getAngleXU())) + ), 2.f*M_PI); + double theta2 = Base::fmod( + atan2(-ellipse->getMajorRadius()*((point2.x-center.x)*sin(ellipse->getAngleXU())-(point2.y-center.y)*cos(ellipse->getAngleXU())), + ellipse->getMinorRadius()*((point2.x-center.x)*cos(ellipse->getAngleXU())+(point2.y-center.y)*sin(ellipse->getAngleXU())) + ), 2.f*M_PI); + if (Base::fmod(theta1 - theta0, 2.f*M_PI) > Base::fmod(theta2 - theta0, 2.f*M_PI)) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 == theta0 || theta1 == theta2) + return -1; + else if (theta1 > theta2) + theta2 += 2.f*M_PI; + + // Trim Point between intersection points + + // Create a new arc to substitute Circle in geometry list and set parameters + Part::GeomArcOfEllipse *geoNew = new Part::GeomArcOfEllipse(); + geoNew->setCenter(center); + geoNew->setMajorRadius(ellipse->getMajorRadius()); + geoNew->setMinorRadius(ellipse->getMinorRadius()); + geoNew->setAngleXU(ellipse->getAngleXU()); + geoNew->setRange(theta1, theta2); + + std::vector< Part::Geometry * > newVals(geomlist); + newVals[GeoId] = geoNew; + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + delete geoNew; + rebuildVertexIndex(); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if(secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + // Add Second Constraint + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + delete newConstr; + return 0; + } } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *aoc = dynamic_cast(geo); Base::Vector3d center = aoc->getCenter(); @@ -1106,6 +1195,176 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) newConstr->FirstPos = end; newConstr->Second = GeoId1; + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + return 0; + } + } + } + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoe = dynamic_cast(geo); + Base::Vector3d center = aoe->getCenter(); + double startAngle, endAngle; + aoe->getRange(startAngle, endAngle); + double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1 + double arcLength = (endAngle - startAngle)*dir; + double theta0 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point.x-center.x)*sin(aoe->getAngleXU())-(point.y-center.y)*cos(aoe->getAngleXU())), + aoe->getMinorRadius()*((point.x-center.x)*cos(aoe->getAngleXU())+(point.y-center.y)*sin(aoe->getAngleXU())) + )- startAngle, 2.f*M_PI); // x0 + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point1.x-center.x)*sin(aoe->getAngleXU())-(point1.y-center.y)*cos(aoe->getAngleXU())), + aoe->getMinorRadius()*((point1.x-center.x)*cos(aoe->getAngleXU())+(point1.y-center.y)*sin(aoe->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x1 + double theta2 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point2.x-center.x)*sin(aoe->getAngleXU())-(point2.y-center.y)*cos(aoe->getAngleXU())), + aoe->getMinorRadius()*((point2.x-center.x)*cos(aoe->getAngleXU())+(point2.y-center.y)*sin(aoe->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x2 + + if (theta1 > theta2) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 >= 0.001*arcLength && theta2 <= 0.999*arcLength) { + // Trim Point between intersection points + if (theta1 < theta0 && theta2 > theta0) { + int newGeoId = addGeometry(geo); + // go through all constraints and replace the point (GeoId,end) with (newGeoId,end) + transferConstraints(GeoId, end, newGeoId, end); + + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + Part::GeomArcOfEllipse *aoe2 = dynamic_cast(geomlist[newGeoId]); + aoe1->setRange(startAngle, startAngle + theta1); + aoe2->setRange(startAngle + theta2, endAngle); + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + + // Build Constraints associated with new pair of arcs + newConstr->Type = Sketcher::Equal; + newConstr->First = GeoId; + newConstr->Second = newGeoId; + addConstraint(newConstr); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && + (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if (secondPos2 == Sketcher::none && + (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + newConstr->Type = constrType2; + newConstr->First = newGeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + newConstr->Type = Sketcher::Coincident; + newConstr->First = GeoId; + newConstr->FirstPos = Sketcher::mid; + newConstr->Second = newGeoId; + newConstr->SecondPos = Sketcher::mid; + addConstraint(newConstr); + + delete newConstr; + + return 0; + } else + return -1; + } else if (theta1 < 0.001*arcLength) { // drop the second intersection point + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } else if (theta2 > 0.999*arcLength) { + } + else + return -1; + } + + if (GeoId1 >= 0) { + + ConstraintType constrType = Sketcher::PointOnObject; + PointPos secondPos = Sketcher::none; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if ((constr->First == GeoId1 && constr->Second == GeoId)) { + constrType = Sketcher::Coincident; + secondPos = constr->FirstPos; + delConstraintOnPoint(GeoId1, constr->FirstPos, false); + break; + } + } + + double theta1 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point1.x-center.x)*sin(aoe->getAngleXU())-(point1.y-center.y)*cos(aoe->getAngleXU())), + aoe->getMinorRadius()*((point1.x-center.x)*cos(aoe->getAngleXU())+(point1.y-center.y)*sin(aoe->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x1 + + if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) { + if (theta1 > theta0) { // trim arc start + delConstraintOnPoint(GeoId, start, false); + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle + theta1, endAngle); + // constrain the trimming point on the corresponding geometry + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + return 0; + } + else { // trim arc end + delConstraintOnPoint(GeoId, end, false); + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle, startAngle + theta1); + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + if (constrType == Sketcher::Coincident) newConstr->SecondPos = secondPos; @@ -1438,6 +1697,35 @@ void SketchObject::rebuildExternalGeometry(void) ExternalGeo.push_back(arc); } } + else if (projCurve.GetType() == GeomAbs_Ellipse) { + gp_Elips e = projCurve.Ellipse(); + gp_Pnt p = e.Location(); + gp_Pnt P1 = projCurve.Value(projCurve.FirstParameter()); + gp_Pnt P2 = projCurve.Value(projCurve.LastParameter()); + + gp_Dir normal = e.Axis().Direction(); + gp_Dir xdir = e.XAxis().Direction(); + gp_Ax2 xdirref(p, normal); + + if (P1.SquareDistance(P2) < Precision::Confusion()) { + Part::GeomEllipse* ellipse = new Part::GeomEllipse(); + ellipse->setMajorRadius(e.MajorRadius()); + ellipse->setMinorRadius(e.MinorRadius()); + ellipse->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + ellipse->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal)); + ellipse->Construction = true; + ExternalGeo.push_back(ellipse); + } + else { + Part::GeomArcOfEllipse* aoe = new Part::GeomArcOfEllipse(); + Handle_Geom_Curve curve = new Geom_Ellipse(e); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(curve, projCurve.FirstParameter(), + projCurve.LastParameter()); + aoe->setHandle(tCurve); + aoe->Construction = true; + ExternalGeo.push_back(aoe); + } + } else { throw Base::Exception("Not yet supported geometry for external geometry"); } diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.cpp b/src/Mod/Sketcher/App/freegcs/Constraints.cpp index 7017600f3022..d4004d01e581 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/freegcs/Constraints.cpp @@ -1792,7 +1792,7 @@ double ConstraintInternalAlignmentPoint2Ellipse::grad(double *param) } // ConstraintEqualMajorAxesEllipse - ConstraintEqualMajorAxesEllipse:: ConstraintEqualMajorAxesEllipse(Ellipse &e1, Ellipse &e2) +ConstraintEqualMajorAxesEllipse:: ConstraintEqualMajorAxesEllipse(Ellipse &e1, Ellipse &e2) { pvec.push_back(e1.center.x); pvec.push_back(e1.center.y); @@ -1808,6 +1808,38 @@ double ConstraintInternalAlignmentPoint2Ellipse::grad(double *param) rescale(); } +ConstraintEqualMajorAxesEllipse:: ConstraintEqualMajorAxesEllipse(ArcOfEllipse &a1, Ellipse &e2) +{ + pvec.push_back(a1.center.x); + pvec.push_back(a1.center.y); + pvec.push_back(a1.focus1X); + pvec.push_back(a1.focus1Y); + pvec.push_back(a1.radmin); + pvec.push_back(e2.center.x); + pvec.push_back(e2.center.y); + pvec.push_back(e2.focus1X); + pvec.push_back(e2.focus1Y); + pvec.push_back(e2.radmin); + origpvec = pvec; + rescale(); +} + +ConstraintEqualMajorAxesEllipse:: ConstraintEqualMajorAxesEllipse(ArcOfEllipse &a1, ArcOfEllipse &a2) +{ + pvec.push_back(a1.center.x); + pvec.push_back(a1.center.y); + pvec.push_back(a1.focus1X); + pvec.push_back(a1.focus1Y); + pvec.push_back(a1.radmin); + pvec.push_back(a2.center.x); + pvec.push_back(a2.center.y); + pvec.push_back(a2.focus1X); + pvec.push_back(a2.focus1Y); + pvec.push_back(a2.radmin); + origpvec = pvec; + rescale(); +} + ConstraintType ConstraintEqualMajorAxesEllipse::getTypeId() { return EqualMajorAxesEllipse; diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.h b/src/Mod/Sketcher/App/freegcs/Constraints.h index aee25200b23e..6cfe395c277a 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.h +++ b/src/Mod/Sketcher/App/freegcs/Constraints.h @@ -400,6 +400,8 @@ namespace GCS inline double* e2rmin() { return pvec[9]; } public: ConstraintEqualMajorAxesEllipse(Ellipse &e1, Ellipse &e2); + ConstraintEqualMajorAxesEllipse(ArcOfEllipse &a1, Ellipse &e2); + ConstraintEqualMajorAxesEllipse(ArcOfEllipse &a1, ArcOfEllipse &a2); virtual ConstraintType getTypeId(); virtual void rescale(double coef=1.); virtual double error(); diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index cb0b259e3eeb..3d6ceea0e5fd 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -798,6 +798,24 @@ int System::addConstraintEqualRadii(Ellipse &e1, Ellipse &e2, int tagId) return addConstraint(constr); } +int System::addConstraintEqualRadii(ArcOfEllipse &a1, ArcOfEllipse &a2, int tagId) +{ + addConstraintEqual(a1.radmin, a2.radmin, tagId); + + Constraint *constr = new ConstraintEqualMajorAxesEllipse(a1,a2); + constr->setTag(tagId); + return addConstraint(constr); +} + +int System::addConstraintEqualRadii(ArcOfEllipse &a1, Ellipse &e2, int tagId) +{ + addConstraintEqual(a1.radmin, e2.radmin, tagId); + + Constraint *constr = new ConstraintEqualMajorAxesEllipse(a1,e2); + constr->setTag(tagId); + return addConstraint(constr); +} + int System::addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId) { return addConstraintEqual(c1.rad, a2.rad, tagId); @@ -828,71 +846,81 @@ int System::addConstraintInternalAlignmentPoint2Ellipse(Ellipse &e, Point &p1, I } int System::addConstraintInternalAlignmentEllipseMajorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId) -{ - //chechk which of the points is closer to satisfying positivemajor - double err1=0.0, err2=0.0; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p1,EllipsePositiveMajorX); - err1+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p1,EllipsePositiveMajorY); - err1+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p2,EllipsePositiveMajorX); - err2+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p2,EllipsePositiveMajorY); - err2+=abs(constr.error()); - }; - if(err1<=err2){ +{ + double X_1=*p1.x; + double Y_1=*p1.y; + double X_2=*p2.x; + double Y_2=*p2.y; + double X_c=*e.center.x; + double Y_c=*e.center.y; + double X_F1=*e.focus1X; + double Y_F1=*e.focus1Y; + double b=*e.radmin; + + // P1=vector([X_1,Y_1]) + // P2=vector([X_2,Y_2]) + // dF1= (F1-C)/sqrt((F1-C)*(F1-C)) + // print "these are the extreme points of the major axis" + // PA = C + a * dF1 + // PN = C - a * dF1 + // print "this is a simple function to know which point is closer to the positive edge of the ellipse" + // DMC=(P1-PA)*(P1-PA)-(P2-PA)*(P2-PA) + double closertopositivemajor=pow(X_1 - X_c - (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), + 2) - pow(X_2 - X_c - (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) + + pow(Y_1 - Y_c - (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) - + pow(Y_2 - Y_c - (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2); + + if(closertopositivemajor>0){ + //p2 is closer to positivemajor. Assign constraints back-to-front. + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMajorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMajorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMajorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMajorY,tagId); + } + else{ //p1 is closer to positivemajor addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMajorX,tagId); addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMajorY,tagId); addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMajorX,tagId); return addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMajorY,tagId); - } else { - //p2 is closer to positivemajor. Assign constraints back-to-front. - addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMajorX,tagId); - addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMajorY,tagId); - addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMajorX,tagId); - return addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMajorY,tagId); } } int System::addConstraintInternalAlignmentEllipseMinorDiameter(Ellipse &e, Point &p1, Point &p2, int tagId) { - //chechk which of the points is closer to satisfying positivemajor - double err1=0.0, err2=0.0; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p1,EllipsePositiveMinorX); - err1+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p1,EllipsePositiveMinorY); - err1+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p2,EllipsePositiveMinorX); - err2+=abs(constr.error()); - }; - { - ConstraintInternalAlignmentPoint2Ellipse constr (e,p2,EllipsePositiveMinorY); - err2+=abs(constr.error()); - }; - if(err1<=err2){ + double X_1=*p1.x; + double Y_1=*p1.y; + double X_2=*p2.x; + double Y_2=*p2.y; + double X_c=*e.center.x; + double Y_c=*e.center.y; + double X_F1=*e.focus1X; + double Y_F1=*e.focus1Y; + double b=*e.radmin; + + // Same idea as for major above, but for minor + // DMC=(P1-PA)*(P1-PA)-(P2-PA)*(P2-PA) + double closertopositiveminor= pow(X_1 - X_c + b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)), 2) - pow(X_2 - X_c + b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - + X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) + pow(-Y_1 + Y_c + b*(X_F1 - + X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) - pow(-Y_2 + Y_c + + b*(X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2); + + if(closertopositiveminor>0){ + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMinorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMinorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMinorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMinorY,tagId); + } else { addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMinorX,tagId); addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipsePositiveMinorY,tagId); addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMinorX,tagId); return addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipseNegativeMinorY,tagId); - } else { - addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMinorX,tagId); - addConstraintInternalAlignmentPoint2Ellipse(e,p2,EllipsePositiveMinorY,tagId); - addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMinorX,tagId); - return addConstraintInternalAlignmentPoint2Ellipse(e,p1,EllipseNegativeMinorY,tagId); - }; + } } int System::addConstraintInternalAlignmentEllipseFocus1(Ellipse &e, Point &p1, int tagId) @@ -916,18 +944,80 @@ int System::addConstraintInternalAlignmentPoint2Ellipse(ArcOfEllipse &a, Point & int System::addConstraintInternalAlignmentEllipseMajorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId) { - addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorX,tagId); - addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorY,tagId); - addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorX,tagId); - return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorY,tagId); + double X_1=*p1.x; + double Y_1=*p1.y; + double X_2=*p2.x; + double Y_2=*p2.y; + double X_c=*a.center.x; + double Y_c=*a.center.y; + double X_F1=*a.focus1X; + double Y_F1=*a.focus1Y; + double b=*a.radmin; + + // P1=vector([X_1,Y_1]) + // P2=vector([X_2,Y_2]) + // dF1= (F1-C)/sqrt((F1-C)*(F1-C)) + // print "these are the extreme points of the major axis" + // PA = C + a * dF1 + // PN = C - a * dF1 + // print "this is a simple function to know which point is closer to the positive edge of the ellipse" + // DMC=(P1-PA)*(P1-PA)-(P2-PA)*(P2-PA) + double closertopositivemajor=pow(X_1 - X_c - (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, + 2) + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), + 2) - pow(X_2 - X_c - (X_F1 - X_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) + + pow(Y_1 - Y_c - (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) - + pow(Y_2 - Y_c - (Y_F1 - Y_c)*sqrt(pow(b, 2) + pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2))/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2); + + if(closertopositivemajor>0){ + //p2 is closer to positivemajor. Assign constraints back-to-front. + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipsePositiveMajorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipsePositiveMajorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseNegativeMajorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseNegativeMajorY,tagId); + } + else{ + //p1 is closer to positivemajor + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMajorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMajorY,tagId); + } } int System::addConstraintInternalAlignmentEllipseMinorDiameter(ArcOfEllipse &a, Point &p1, Point &p2, int tagId) { - addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorX,tagId); - addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorY,tagId); - addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorX,tagId); - return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorY,tagId); + double X_1=*p1.x; + double Y_1=*p1.y; + double X_2=*p2.x; + double Y_2=*p2.y; + double X_c=*a.center.x; + double Y_c=*a.center.y; + double X_F1=*a.focus1X; + double Y_F1=*a.focus1Y; + double b=*a.radmin; + + // Same idea as for major above, but for minor + // DMC=(P1-PA)*(P1-PA)-(P2-PA)*(P2-PA) + double closertopositiveminor= pow(X_1 - X_c + b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - X_c, 2) + + pow(Y_F1 - Y_c, 2)), 2) - pow(X_2 - X_c + b*(Y_F1 - Y_c)/sqrt(pow(X_F1 - + X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) + pow(-Y_1 + Y_c + b*(X_F1 - + X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2) - pow(-Y_2 + Y_c + + b*(X_F1 - X_c)/sqrt(pow(X_F1 - X_c, 2) + pow(Y_F1 - Y_c, 2)), 2); + + if(closertopositiveminor>0){ + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipsePositiveMinorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipsePositiveMinorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseNegativeMinorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipseNegativeMinorY,tagId); + } else { + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorX,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p1,EllipsePositiveMinorY,tagId); + addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorX,tagId); + return addConstraintInternalAlignmentPoint2Ellipse(a,p2,EllipseNegativeMinorY,tagId); + } } int System::addConstraintInternalAlignmentEllipseFocus1(ArcOfEllipse &a, Point &p1, int tagId) @@ -1749,7 +1839,7 @@ int System::diagnose() Eigen::MatrixXd Q = qrJT.matrixQ (); int paramsNum = qrJT.rows(); int constrNum = qrJT.cols(); - qrJT.setThreshold(1e-10); + qrJT.setThreshold(1e-13); int rank = qrJT.rank(); Eigen::MatrixXd R; diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index 3d99da2c9bb5..f624551253fd 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -165,6 +165,8 @@ namespace GCS int addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId=0); int addConstraintEqualRadius(Circle &c1, Circle &c2, int tagId=0); int addConstraintEqualRadii(Ellipse &e1, Ellipse &e2, int tagId=0); + int addConstraintEqualRadii(ArcOfEllipse &a1, ArcOfEllipse &a2, int tagId=0); + int addConstraintEqualRadii(ArcOfEllipse &a1, Ellipse &e2, int tagId=0); int addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId=0); int addConstraintEqualRadius(Arc &a1, Arc &a2, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 347067c80003..c7acb0fb6ec3 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1314,6 +1314,97 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) QObject::tr("One of the selected edges should be a line.")); return; } + + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId2 is the line + geo1 = Obj->getGeometry(GeoId1); + geo2 = Obj->getGeometry(GeoId2); + + if( geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ) { + + Base::Vector3d center; + double majord; + double minord; + double phi; + + if( geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() ){ + const Part::GeomEllipse *ellipse = static_cast(geo1); + + center=ellipse->getCenter(); + majord=ellipse->getMajorRadius(); + minord=ellipse->getMinorRadius(); + phi=ellipse->getAngleXU(); + } else + if( geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ){ + const Part::GeomArcOfEllipse *aoe = static_cast(geo1); + + center=aoe->getCenter(); + majord=aoe->getMajorRadius(); + minord=aoe->getMinorRadius(); + phi=aoe->getAngleXU(); + } + + const Part::GeomLineSegment *line = static_cast(geo2); + + Base::Vector3d point1=line->getStartPoint(); + Base::Vector3d point2=line->getEndPoint(); + + Base::Vector3d direction=point1-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + + Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); + + Base::Vector3d endpoint = PoE+perp; + + int currentgeoid= Obj->getHighestCurveIndex(); + + openCommand("add perpendicular constraint"); + + try { + + // Add a construction line + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + selection[0].getFeatName(), + PoE.x,PoE.y,endpoint.x,endpoint.y); + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + // Point on first object (ellipse, arc of ellipse) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); + // construction line tangent to ellipse/arcofellipse + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId1); + // Point on second object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); + + // line perpendicular to construction line + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId2); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return; + } + + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + + } openCommand("add perpendicular constraint"); Gui::Command::doCommand( @@ -1423,6 +1514,188 @@ void CmdSketcherConstrainTangent::activated(int iMsg) } else if (isEdge(GeoId1,PosId1) && isEdge(GeoId2,PosId2)) { // simple tangency between GeoId1 and GeoId2 + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId1 is the ellipse + geom1 = Obj->getGeometry(GeoId1); + geom2 = Obj->getGeometry(GeoId2); + + if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + + const Part::GeomEllipse *ellipse = static_cast(geom1); + + Base::Vector3d center=ellipse->getCenter(); + double majord=ellipse->getMajorRadius(); + double minord=ellipse->getMinorRadius(); + double phi=ellipse->getAngleXU(); + + Base::Vector3d center2; + + if( geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() ) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + + Base::Vector3d direction=center2-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + + Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); + + Base::Vector3d endpoint = PoE+perp; + + int currentgeoid= Obj->getHighestCurveIndex(); + + openCommand("add tangent constraint"); + + try { + //construct the point + /*Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), + PoE.x,PoE.y);*/ + + // Add a construction line + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + selection[0].getFeatName(), + PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + // Point on first object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis + // Point on second object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis + // tangent to first object + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId1); + // tangent to second object + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId2); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return; + } + + + + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + } + + } + + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId1 is the arc of ellipse + geom1 = Obj->getGeometry(GeoId1); + geom2 = Obj->getGeometry(GeoId2); + + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() ) { + + const Part::GeomArcOfEllipse *aoe = static_cast(geom1); + + Base::Vector3d center=aoe->getCenter(); + double majord=aoe->getMajorRadius(); + double minord=aoe->getMinorRadius(); + double phi=aoe->getAngleXU(); + + Base::Vector3d center2; + + if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + + Base::Vector3d direction=center2-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + Base::Vector3d PoE = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + + Base::Vector3d perp = Base::Vector3d(direction.y,-direction.x); + + Base::Vector3d endpoint = PoE+perp; + + int currentgeoid= Obj->getHighestCurveIndex(); + + openCommand("add tangent constraint"); + + try { + + // Add a construction line + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + selection[0].getFeatName(), + PoE.x,PoE.y,endpoint.x,endpoint.y); // create line for major axis + + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ",Obj->getNameInDocument(),currentgeoid+1); + + // Point on first object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId1); // constrain major axis + // Point on second object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,Sketcher::start,GeoId2); // constrain major axis + // tangent to first object + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId1); + // tangent to second object + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", + selection[0].getFeatName(),currentgeoid+1,GeoId2); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return; + } + + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + } + + } + openCommand("add tangent constraint"); Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d)) ", @@ -1806,7 +2079,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) } std::vector ids; - bool lineSel = false, arcSel = false, circSel = false, hasAlreadyExternal = false; + bool lineSel = false, arcSel = false, circSel = false, ellipsSel = false, arcEllipsSel=false, hasAlreadyExternal = false; for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { @@ -1838,8 +2111,12 @@ void CmdSketcherConstrainEqual::activated(int iMsg) lineSel = true; else if (geo->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) arcSel = true; - else if (geo->getTypeId() != Part::GeomCircle::getClassTypeId()) // TODO: ellipse + else if (geo->getTypeId() != Part::GeomCircle::getClassTypeId()) circSel = true; + else if (geo->getTypeId() != Part::GeomEllipse::getClassTypeId()) // TODO: ellipse + ellipsSel = true; + else if (geo->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) // TODO: ellipse + arcEllipsSel = true; else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select two or more edges of similar type")); @@ -1849,7 +2126,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) ids.push_back(GeoId); } - if (lineSel && (arcSel || circSel)) { + if (lineSel && (arcSel || circSel) && (ellipsSel || arcEllipsSel)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select two or more edges of similar type")); return; diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 889baf358ed5..f6627947632d 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -1887,13 +1887,10 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler return; } } - else if (Mode==STATUS_SEEK_Third) { - double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter - double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter - + else if (Mode==STATUS_SEEK_Third) { // angle between the major axis of the ellipse and the X axis double a = (EditCurve[1]-EditCurve[0]).Length(); - double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + double phi = atan2(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); // This is the angle at cursor point double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); @@ -1915,9 +1912,9 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler setPositionText(onSketchPos, text); sketchgui->drawEdit(EditCurve); - if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f), AutoConstraint::CURVE)) { - renderSuggestConstraintsCursor(sugConstr2); + renderSuggestConstraintsCursor(sugConstr3); return; } } @@ -1949,11 +1946,11 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler // angle between the major axis of the ellipse and the X axis double a = (EditCurve[1]-EditCurve[0]).Length(); - double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + double phi = atan2(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); // This is the angle at cursor point double angleatpoint = acos((EditCurve[2].fX-EditCurve[0].fX+(EditCurve[2].fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); - double b=(EditCurve[2].fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi)); + double b=abs((EditCurve[2].fY-EditCurve[0].fY-a*cos(angleatpoint)*sin(phi))/(sin(angleatpoint)*cos(phi))); Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint; // We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction @@ -2012,7 +2009,7 @@ class DrawSketchHandlerEllipse : public DrawSketchHandler protected: SelectMode Mode; std::vector EditCurve; - std::vector sugConstr1, sugConstr2; + std::vector sugConstr1, sugConstr2, sugConstr3; }; @@ -2136,13 +2133,10 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler return; } } - else if (Mode==STATUS_SEEK_Third) { - double rx0 = EditCurve[1].fX - EditCurve[0].fX; // first semidiameter - double ry0 = EditCurve[1].fY - EditCurve[0].fY; // first semidiameter - + else if (Mode==STATUS_SEEK_Third) { // angle between the major axis of the ellipse and the X axis double a = (EditCurve[1]-EditCurve[0]).Length(); - double phi = atan2f(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); + double phi = atan2(EditCurve[1].fY-EditCurve[0].fY,EditCurve[1].fX-EditCurve[0].fX); // This is the angle at cursor point double angleatpoint = acos((onSketchPos.fX-EditCurve[0].fX+(onSketchPos.fY-EditCurve[0].fY)*tan(phi))/(a*(cos(phi)+tan(phi)*sin(phi)))); @@ -2172,9 +2166,6 @@ class DrawSketchHandlerArcOfEllipse : public DrawSketchHandler } else if (Mode==STATUS_SEEK_Fourth) { // here we differ from ellipse creation - double rx0 = axisPoint.fX - centerPoint.fX; // first semidiameter - double ry0 = axisPoint.fY - centerPoint.fY; // first semidiameter - // angle between the major axis of the ellipse and the X axis double a = (axisPoint-centerPoint).Length(); double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); @@ -3119,9 +3110,11 @@ namespace SketcherGui { const Part::Geometry *geom = Sketch->getGeometry(GeoId); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() || geom->getTypeId() == Part::GeomCircle::getClassTypeId()|| - geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()|| + geom->getTypeId() == Part::GeomEllipse::getClassTypeId()|| + geom->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() + ) return true; - // TODO: ellipse } return false; } @@ -3201,9 +3194,9 @@ class DrawSketchHandlerTrimming: public DrawSketchHandler const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId); if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId() || geom->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || - geom->getTypeId() == Part::GeomCircle::getClassTypeId() - // TODO: ellipse - ) { + geom->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom->getTypeId() == Part::GeomEllipse::getClassTypeId()) { try { Gui::Command::openCommand("Trim edge"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.trim(%d,App.Vector(%f,%f,0))", diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 3ec78dbb17c5..ad443172c022 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -721,8 +721,14 @@ void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) // go through the selected subelements for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { // only handle edges - if (it->size() > 4 && it->substr(0,4) == "Edge") { - int GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; + if ( (it->size() > 4 && it->substr(0,4) == "Edge") || + (it->size() > 12 && it->substr(0,12) == "ExternalEdge")) { + int GeoId; + if(it->substr(0,4) == "Edge") + GeoId = std::atoi(it->substr(4,4000).c_str()) - 1; + else + GeoId = -std::atoi(it->substr(12,4000).c_str()) - 2; + const Part::Geometry *geo = Obj->getGeometry(GeoId); // Only for supported types if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { diff --git a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp index fb44ed3b5b78..9a8032f5d995 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp @@ -200,6 +200,18 @@ void SketcherValidation::on_findButton_clicked() id.v = segm->getEndPoint(); vertexIds.push_back(id); } + else if (g->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *segm = dynamic_cast(g); + VertexIds id; + id.GeoId = (int)i; + id.PosId = Sketcher::start; + id.v = segm->getStartPoint(); + vertexIds.push_back(id); + id.GeoId = (int)i; + id.PosId = Sketcher::end; + id.v = segm->getEndPoint(); + vertexIds.push_back(id); + } } std::set coincidences; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 197f5e6405a1..73641af6ad9c 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2149,6 +2149,34 @@ void ViewProviderSketch::updateColor(void) if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; index = edit->ActSketch.getPointId(constraint->Second, constraint->SecondPos) + 1; if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; + } else if (type == Sketcher::InternalAlignment) { + switch(constraint->AlignmentType) { + case EllipseMajorDiameter: + case EllipseMinorDiameter: + { + // color line + int CurvNum = edit->CurvesMaterials->diffuseColor.getNum(); + for (int i=0; i < CurvNum; i++) { + int cGeoId = edit->CurvIdToGeoId[i]; + + if(cGeoId == constraint->First) { + int indexes=(edit->CurveSet->numVertices[i]); + color[i] = SelectColor; + break; + } + } + } + break; + case EllipseFocus1: + case EllipseFocus2: + { + int index = edit->ActSketch.getPointId(constraint->First, constraint->FirstPos) + 1; + if (index >= 0 && index < PtNum) pcolor[index] = SelectColor; + } + break; + default: + break; + } } } else if (edit->PreselectConstraintSet.count(i)) { if (hasDatumLabel) { @@ -2208,7 +2236,7 @@ QString ViewProviderSketch::iconTypeFromConstraint(Constraint *constraint) case Equal: return QString::fromAscii("small/Constraint_EqualLength_sm"); case Symmetric: - return QString::fromAscii("small/Constraint_Symmetric_sm"); + return QString::fromAscii("small/Constraint_Symmetric_sm"); default: return QString(); } @@ -3117,10 +3145,18 @@ void ViewProviderSketch::draw(bool temp) r1 = ellipse->getMajorRadius(); angle1 = -ellipse->getAngleXU(); midpos1 = ellipse->getCenter(); + } else if (geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + // TODO: ellipse + const Part::GeomArcOfEllipse *aoe = dynamic_cast(geo1); + r1 = aoe->getMajorRadius(); + double startangle, endangle; + aoe->getRange(startangle, endangle); + angle1 = (startangle + endangle)/2-aoe->getAngleXU(); + midpos1 = aoe->getCenter(); } else break; - if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { // TODO: ellipse + if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast(geo2); r2 = circle->getRadius(); angle2 = M_PI/4; @@ -3138,6 +3174,14 @@ void ViewProviderSketch::draw(bool temp) r2 = ellipse->getMajorRadius(); angle2 = -ellipse->getAngleXU(); midpos2 = ellipse->getCenter(); + } else if (geo2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + // TODO: ellipse + const Part::GeomArcOfEllipse *aoe = dynamic_cast(geo2); + r2 = aoe->getMajorRadius(); + double startangle, endangle; + aoe->getRange(startangle, endangle); + angle1 = (startangle + endangle)/2-aoe->getAngleXU(); + midpos1 = aoe->getCenter(); } else break;