diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index be7b389743..be49fb39c2 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -2322,9 +2322,61 @@ void GeomArcOfParabola::setFocal(double length) } } -void GeomArcOfParabola::getRange(double& u, double& v, bool /*emulateCCWXY*/) const +/*! + * \brief GeomArcOfParabola::getXAxisDir + * \return the direction vector (unit-length) of symmetry axis of the parabola. The + * direction also points to the focus. + */ +Base::Vector3d GeomArcOfParabola::getXAxisDir() const { -#if 0 + Handle_Geom_Parabola c = Handle_Geom_Parabola::DownCast( myCurve->BasisCurve() ); + assert(!c.IsNull()); + gp_Dir xdir = c->XAxis().Direction(); + return Base::Vector3d(xdir.X(), xdir.Y(), xdir.Z()); +} + +/*! + * \brief GeomArcOfParabola::setXAxisDir Rotates the parabola in its plane, so + * that its symmetry axis is as close as possible to the provided direction. + * \param newdir [in] is the new direction. If the vector is small, the + * orientation of the parabola will be preserved. If the vector is not small, + * but its projection onto plane of the parabola is small, an exception will be + * thrown. + */ +void GeomArcOfParabola::setXAxisDir(Base::Vector3d newdir) +{ + Handle_Geom_Parabola c = Handle_Geom_Parabola::DownCast( myCurve->BasisCurve() ); + assert(!c.IsNull()); + #if OCC_VERSION_HEX >= 0x060504 + if (newdir.Sqr() < Precision::SquareConfusion()) + #else + if (newdir.Length() < Precision::Confusion()) + #endif + return;//zero vector was passed. Keep the old orientation. + + try { + gp_Ax2 pos = c->Position(); + pos.SetXDirection(gp_Dir(newdir.x, newdir.y, newdir.z));//OCC should keep the old main Direction (Z), and change YDirection to accomodate the new XDirection. + c->SetPosition(pos); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + +Base::Vector3d GeomArcOfParabola::getFocus(void) const +{ + Handle_Geom_Parabola p = Handle_Geom_Parabola::DownCast(myCurve->BasisCurve()); + gp_Pnt gp = p->Focus(); + + return Base::Vector3d(gp.X(),gp.Y(),gp.Z()); +} + + +void GeomArcOfParabola::getRange(double& u, double& v, bool emulateCCWXY) const +{ +//#if 0 try { if (emulateCCWXY) { if (isReversed()) { @@ -2338,17 +2390,17 @@ void GeomArcOfParabola::getRange(double& u, double& v, bool /*emulateCCWXY*/) co Handle_Standard_Failure e = Standard_Failure::Caught(); throw Base::Exception(e->GetMessageString()); } -#endif +//#endif u = myCurve->FirstParameter(); v = myCurve->LastParameter(); } -void GeomArcOfParabola::setRange(double u, double v, bool /*emulateCCWXY*/) +void GeomArcOfParabola::setRange(double u, double v, bool emulateCCWXY) { try { myCurve->SetTrim(u, v); -#if 0 +//#if 0 if (emulateCCWXY) { if (isReversed()) { Handle_Geom_Parabola c = Handle_Geom_Parabola::DownCast(myCurve->BasisCurve()); @@ -2356,7 +2408,7 @@ void GeomArcOfParabola::setRange(double u, double v, bool /*emulateCCWXY*/) c->Reverse(); } } -#endif +//#endif } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); @@ -2408,7 +2460,7 @@ void GeomArcOfParabola::Restore(Base::XMLReader &reader) double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,Focal,AngleXU,StartAngle,EndAngle; // read my Element - reader.readElement("ArcOfHyperbola"); + reader.readElement("ArcOfParabola"); // get the value of my Attribute CenterX = reader.getAttributeAsFloat("CenterX"); CenterY = reader.getAttributeAsFloat("CenterY"); diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index 7652f324b6..8f2e8a1d54 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -497,6 +497,11 @@ public: double getFocal(void) const; void setFocal(double length); + Base::Vector3d getXAxisDir() const; + void setXAxisDir(Base::Vector3d newdir); + + Base::Vector3d getFocus(void) const; + virtual void getRange(double& u, double& v, bool emulateCCWXY) const; virtual void setRange(double u, double v, bool emulateCCWXY); diff --git a/src/Mod/Part/App/ParabolaPyImp.cpp b/src/Mod/Part/App/ParabolaPyImp.cpp index 039eb6be5c..e9686cddf3 100644 --- a/src/Mod/Part/App/ParabolaPyImp.cpp +++ b/src/Mod/Part/App/ParabolaPyImp.cpp @@ -24,6 +24,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +#include #endif #include @@ -36,6 +38,8 @@ using namespace Part; +extern const char* gce_ErrorStatusText(gce_ErrorType et); + // returns a string which represents the object e.g. when printed in python std::string ParabolaPy::representation(void) const { @@ -49,15 +53,65 @@ PyObject *ParabolaPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // P } // constructor method -int ParabolaPy::PyInit(PyObject* args, PyObject* /*kwd*/) +int ParabolaPy::PyInit(PyObject* args, PyObject* kwds) { - if (PyArg_ParseTuple(args, "")) { - Handle_Geom_Parabola c = Handle_Geom_Parabola::DownCast - (getGeometryPtr()->handle()); - c->SetFocal(1.0); + char* keywords_n[] = {NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "", keywords_n)) { + Handle_Geom_Parabola parabola = Handle_Geom_Parabola::DownCast(getGeomParabolaPtr()->handle()); + parabola->SetFocal(1.0); return 0; } + char* keywords_e[] = {"Parabola",NULL}; + PyErr_Clear(); + PyObject *pParab; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!",keywords_e, &(ParabolaPy::Type), &pParab)) { + ParabolaPy* pParabola = static_cast(pParab); + Handle_Geom_Parabola Parab1 = Handle_Geom_Parabola::DownCast + (pParabola->getGeomParabolaPtr()->handle()); + Handle_Geom_Parabola Parab2 = Handle_Geom_Parabola::DownCast + (this->getGeomParabolaPtr()->handle()); + Parab2->SetParab(Parab1->Parab()); + return 0; + } + + char* keywords_ssc[] = {"Focus","Center","Normal",NULL}; + PyErr_Clear(); + PyObject *pV1, *pV2, *pV3; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O!", keywords_ssc, + &(Base::VectorPy::Type), &pV1, + &(Base::VectorPy::Type), &pV2, + &(Base::VectorPy::Type), &pV3)) { + Base::Vector3d focus = static_cast(pV1)->value(); + Base::Vector3d center = static_cast(pV2)->value(); + Base::Vector3d normal = static_cast(pV3)->value(); + + Base::Vector3d xvect = focus-center; + + // set the geometry + gp_Pnt p1(center.x,center.y,center.z); + gp_Dir norm(normal.x,normal.y,normal.z); + gp_Dir xdiroce(xvect.x,xvect.y,xvect.z); + + gp_Ax2 xdir(p1, norm, xdiroce); + + gce_MakeParab mc(xdir, (Standard_Real) xvect.Length()); + + if (!mc.IsDone()) { + PyErr_SetString(PartExceptionOCCError, gce_ErrorStatusText(mc.Status())); + return -1; + } + + Handle_Geom_Parabola parabola = Handle_Geom_Parabola::DownCast(getGeomParabolaPtr()->handle()); + parabola->SetParab(mc.Value()); + return 0; + } + + PyErr_SetString(PyExc_TypeError, "Parabola constructor accepts:\n" + "-- empty parameter list\n" + "-- Parabola\n" + "-- Point, Point, Point"); + return -1; } diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index 30bcdcbfae..f7b78de9d8 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -66,7 +66,8 @@ enum InternalAlignmentType { EllipseFocus2 = 4, HyperbolaMajor = 5, HyperbolaMinor = 6, - HyperbolaFocus = 7 + HyperbolaFocus = 7, + ParabolaFocus = 8 }; /// define if you want to use the end or start point diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 0aa4971805..370f376f9d 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include @@ -84,6 +86,7 @@ void Sketch::clear(void) Ellipses.clear(); ArcsOfEllipse.clear(); ArcsOfHyperbola.clear(); + ArcsOfParabola.clear(); // deleting the doubles allocated with new for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it) @@ -177,6 +180,8 @@ const char* nameByType(Sketch::GeoType type) return "arcofellipse"; case Sketch::ArcOfHyperbola: return "arcofhyperbola"; + case Sketch::ArcOfParabola: + return "arcofparabola"; case Sketch::None: default: return "unknown"; @@ -215,7 +220,12 @@ int Sketch::addGeometry(const Part::Geometry *geo, bool fixed) const GeomArcOfHyperbola *aoh = static_cast(geo); // create the definition struct for that geom return addArcOfHyperbola(*aoh, fixed); - } else { + } else if (geo->getTypeId() == GeomArcOfParabola::getClassTypeId()) { // add an arc of parabola + const GeomArcOfParabola *aop = dynamic_cast(geo); + // create the definition struct for that geom + return addArcOfParabola(*aop, fixed); + } + else { throw Base::TypeError("Sketch::addGeometry(): Unknown or unsupported type added to a sketch"); } } @@ -560,6 +570,82 @@ int Sketch::addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, return Geoms.size()-1; } +int Sketch::addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, bool fixed) +{ + std::vector ¶ms = fixed ? FixParameters : Parameters; + + // create our own copy + GeomArcOfParabola *aop = static_cast(parabolaSegment.clone()); + // create the definition struct for that geom + GeoDef def; + def.geo = aop; + def.type = ArcOfParabola; + + Base::Vector3d vertex = aop->getCenter(); + Base::Vector3d startPnt = aop->getStartPoint(); + Base::Vector3d endPnt = aop->getEndPoint(); + Base::Vector3d focus = aop->getFocus(); + + double startAngle, endAngle; + aop->getRange(startAngle, endAngle,/*emulateCCW=*/true); + + GCS::Point p1, p2, p3, p4; + + params.push_back(new double(startPnt.x)); + params.push_back(new double(startPnt.y)); + p1.x = params[params.size()-2]; + p1.y = params[params.size()-1]; + + params.push_back(new double(endPnt.x)); + params.push_back(new double(endPnt.y)); + p2.x = params[params.size()-2]; + p2.y = params[params.size()-1]; + + params.push_back(new double(vertex.x)); + params.push_back(new double(vertex.y)); + p3.x = params[params.size()-2]; + p3.y = params[params.size()-1]; + + params.push_back(new double(focus.x)); + params.push_back(new double(focus.y)); + p4.x = params[params.size()-2]; + p4.y = params[params.size()-1]; + + def.startPointId = Points.size(); + Points.push_back(p1); + def.endPointId = Points.size(); + Points.push_back(p2); + def.midPointId = Points.size(); + Points.push_back(p3); + + // add the radius parameters + params.push_back(new double(startAngle)); + double *a1 = params[params.size()-1]; + params.push_back(new double(endAngle)); + double *a2 = params[params.size()-1]; + + // set the arc for later constraints + GCS::ArcOfParabola a; + a.start = p1; + a.end = p2; + a.vertex = p3; + a.focus1 = p4; + a.startAngle = a1; + a.endAngle = a2; + def.index = ArcsOfParabola.size(); + ArcsOfParabola.push_back(a); + + // store complete set + Geoms.push_back(def); + + // arcs require an ArcRules constraint for the end points + if (!fixed) + GCSsys.addConstraintArcOfParabolaRules(a); + + // return the position of the newly added geometry + return Geoms.size()-1; +} + int Sketch::addCircle(const Part::GeomCircle &cir, bool fixed) { std::vector ¶ms = fixed ? FixParameters : Parameters; @@ -700,6 +786,9 @@ Py::Tuple Sketch::getPyGeometry(void) const } else if (it->type == ArcOfHyperbola) { GeomArcOfHyperbola *aoh = dynamic_cast(it->geo->clone()); tuple[i] = Py::asObject(new ArcOfHyperbolaPy(aoh)); + } else if (it->type == ArcOfParabola) { + GeomArcOfParabola *aop = dynamic_cast(it->geo->clone()); + tuple[i] = Py::asObject(new ArcOfParabolaPy(aop)); } else { // not implemented type in the sketch! } @@ -737,7 +826,10 @@ GCS::Curve* Sketch::getGCSCurveByGeoId(int geoId) break; case ArcOfHyperbola: return &ArcsOfHyperbola[Geoms[geoId].index]; - break; + break; + case ArcOfParabola: + return &ArcsOfParabola[Geoms[geoId].index]; + break; default: return 0; }; @@ -1000,6 +1092,9 @@ int Sketch::addConstraint(const Constraint *constraint) case HyperbolaFocus: rtn = addInternalAlignmentHyperbolaFocus(constraint->First,constraint->Second); break; + case ParabolaFocus: + rtn = addInternalAlignmentParabolaFocus(constraint->First,constraint->Second); + break; default: break; } @@ -1730,6 +1825,16 @@ int Sketch::addEqualConstraint(int geoId1, int geoId2) } } + if (Geoms[geoId2].type == ArcOfParabola) { + if (Geoms[geoId1].type == ArcOfParabola) { + GCS::ArcOfParabola &a1 = ArcsOfParabola[Geoms[geoId1].index]; + GCS::ArcOfParabola &a2 = ArcsOfParabola[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintEqualFocus(a1, a2, tag); + return ConstraintsCounter; + } + } + if (Geoms[geoId1].type == Ellipse) { GCS::Ellipse &e1 = Ellipses[Geoms[geoId1].index]; if (Geoms[geoId2].type == ArcOfEllipse) { @@ -1791,7 +1896,13 @@ int Sketch::addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2) int tag = ++ConstraintsCounter; GCSsys.addConstraintPointOnHyperbolicArc(p1, a, tag); return ConstraintsCounter; - } + } + else if (Geoms[geoId2].type == ArcOfParabola) { + GCS::ArcOfParabola &a = ArcsOfParabola[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnParabolicArc(p1, a, tag); + return ConstraintsCounter; + } } return -1; } @@ -2157,6 +2268,32 @@ int Sketch::addInternalAlignmentHyperbolaFocus(int geoId1, int geoId2) return -1; } +int Sketch::addInternalAlignmentParabolaFocus(int geoId1, int geoId2) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != ArcOfParabola) + return -1; + if (Geoms[geoId2].type != Point) + return -1; + + int pointId1 = getPointId(geoId2, start); + + if (pointId1 >= 0 && pointId1 < int(Points.size())) { + GCS::Point &p1 = Points[pointId1]; + + GCS::ArcOfParabola &a1 = ArcsOfParabola[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentParabolaFocus(a1, p1, tag); + return ConstraintsCounter; + } + return -1; +} + double Sketch::calculateAngleViaPoint(int geoId1, int geoId2, double px, double py) { geoId1 = checkGeoId(geoId1); @@ -2300,6 +2437,23 @@ bool Sketch::updateGeometry() } aoh->setMajorAxisDir(fd); aoh->setRange(*myArc.startAngle, *myArc.endAngle, /*emulateCCW=*/true); + } else if (it->type == ArcOfParabola) { + GCS::ArcOfParabola &myArc = ArcsOfParabola[it->index]; + + GeomArcOfParabola *aop = dynamic_cast(it->geo); + + Base::Vector3d vertex = Vector3d(*Points[it->midPointId].x, *Points[it->midPointId].y, 0.0); + Base::Vector3d f1 = Vector3d(*myArc.focus1.x, *myArc.focus1.y, 0.0); + + Base::Vector3d fd=f1-vertex; + + aop->setXAxisDir(fd); + + aop->setCenter(vertex); + + aop->setFocal(fd.Length()); + + aop->setRange(*myArc.startAngle, *myArc.endAngle, /*emulateCCW=*/true); } } catch (Base::Exception e) { Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n", @@ -2607,6 +2761,41 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) } else if (Geoms[geoId].type == ArcOfHyperbola) { + GCS::Point ¢er = Points[Geoms[geoId].midPointId]; + GCS::Point p0,p1; + if (pos == mid || pos == none) { + MoveParameters.resize(2); // cx,cy + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *center.x; + *p0.y = *center.y; + + GCSsys.addConstraintP2PCoincident(p0,center,-1); + } else if (pos == start || pos == end) { + + MoveParameters.resize(4); // x,y,cx,cy + if (pos == start || pos == end) { + GCS::Point &p = (pos == start) ? Points[Geoms[geoId].startPointId] + : Points[Geoms[geoId].endPointId];; + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + *p0.x = *p.x; + *p0.y = *p.y; + + GCSsys.addConstraintP2PCoincident(p0,p,-1); + } + p1.x = &MoveParameters[2]; + p1.y = &MoveParameters[3]; + *p1.x = *center.x; + *p1.y = *center.y; + + int i=GCSsys.addConstraintP2PCoincident(p1,center,-1); + GCSsys.rescaleConstraint(i-1, 0.01); + GCSsys.rescaleConstraint(i, 0.01); + + } + } else if (Geoms[geoId].type == ArcOfParabola) { + GCS::Point ¢er = Points[Geoms[geoId].midPointId]; GCS::Point p0,p1; if (pos == mid || pos == none) { @@ -2742,6 +2931,11 @@ int Sketch::movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool rela MoveParameters[0] = toPoint.x; MoveParameters[1] = toPoint.y; } + } else if (Geoms[geoId].type == ArcOfParabola) { + if (pos == start || pos == end || pos == mid || pos == none) { + MoveParameters[0] = toPoint.x; + MoveParameters[1] = toPoint.y; + } } return solve(); diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 185f8085c8..77c06fc866 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -130,6 +130,8 @@ public: int addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool fixed=false); /// add an arc of hyperbola int addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, bool fixed=false); + /// add an arc of parabola + int addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, bool fixed=false); //@} @@ -309,6 +311,7 @@ public: int addInternalAlignmentHyperbolaMajorDiameter(int geoId1, int geoId2); int addInternalAlignmentHyperbolaMinorDiameter(int geoId1, int geoId2); int addInternalAlignmentHyperbolaFocus(int geoId1, int geoId2); + int addInternalAlignmentParabolaFocus(int geoId1, int geoId2); //@} public: //This func is to be used during angle-via-point constraint creation. It calculates @@ -335,7 +338,8 @@ public: Circle = 4, // 1 Point(mid), 3 Parameters(x,y,r) Ellipse = 5, // 1 Point(mid), 5 Parameters(x,y,r1,r2,phi) phi=angle xaxis of elipse with respect of sketch xaxis ArcOfEllipse = 6, - ArcOfHyperbola = 7 + ArcOfHyperbola = 7, + ArcOfParabola = 8 }; float SolveTime; @@ -383,6 +387,7 @@ protected: std::vector Ellipses; std::vector ArcsOfEllipse; std::vector ArcsOfHyperbola; + std::vector ArcsOfParabola; bool isInitMove; bool isFine; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 0c7e257fae..9a33e90b05 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -33,6 +33,7 @@ # include # include # include +# include # include # include # include @@ -41,6 +42,7 @@ # include # include # include +# include # include # include # include @@ -504,6 +506,14 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const return aoh->getEndPoint(); else if (PosId == mid) return aoh->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = dynamic_cast(geo); + if (PosId == start) + return aop->getStartPoint(); + else if (PosId == end) + return aop->getEndPoint(); + else if (PosId == mid) + return aop->getCenter(); } return Base::Vector3d(); @@ -560,6 +570,7 @@ bool SketchObject::isSupportedGeometry(const Part::Geometry *geo) const geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { return true; } @@ -2068,6 +2079,59 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, geosymaoe->setRange(theta1,theta2,true); isStartEndInverted.insert(std::make_pair(*it, true)); } + else if(geosym->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + Part::GeomArcOfHyperbola *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + Base::Vector3d majdir = geosymaoe->getMajorAxisDir(); + double majord=geosymaoe->getMajorRadius(); + double minord=geosymaoe->getMinorRadius(); + double df= sqrt(majord*majord+minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1); + Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp); + Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp); + Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep); + + geosymaoe->setMajorAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(sep,theta1); + geosymaoe->closestParameter(ssp,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, true)); + } + else if(geosym->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + Part::GeomArcOfParabola *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + //double df= geosymaoe->getFocal(); + Base::Vector3d f1 = geosymaoe->getFocus(); + + Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1); + Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp); + Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp); + Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep); + + geosymaoe->setXAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(sep,theta1); + geosymaoe->closestParameter(ssp,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, true)); + } else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){ Part::GeomPoint *geosympoint = static_cast(geosym); Base::Vector3d cp = geosympoint->getPoint(); @@ -2110,6 +2174,14 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); refpoint = geosymaoe->getStartPoint(true); } + else if(georef->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + const Part::GeomArcOfHyperbola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getStartPoint(true); + } + else if(georef->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + const Part::GeomArcOfParabola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getStartPoint(true); + } break; case Sketcher::end: if(georef->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ @@ -2124,6 +2196,14 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); refpoint = geosymaoe->getEndPoint(true); } + else if(georef->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + const Part::GeomArcOfHyperbola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getEndPoint(true); + } + else if(georef->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + const Part::GeomArcOfParabola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getEndPoint(true); + } break; case Sketcher::mid: if(georef->getTypeId() == Part::GeomCircle::getClassTypeId()){ @@ -2142,6 +2222,14 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); refpoint = geosymaoe->getCenter(); } + else if(georef->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + const Part::GeomArcOfHyperbola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getCenter(); + } + else if(georef->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + const Part::GeomArcOfParabola *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getCenter(); + } break; default: Base::Console().Error("Wrong PointPosId.\n"); @@ -2234,6 +2322,59 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, geosymaoe->setRange(theta1,theta2,true); isStartEndInverted.insert(std::make_pair(*it, false)); } + else if(geosym->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + Part::GeomArcOfHyperbola *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + Base::Vector3d majdir = geosymaoe->getMajorAxisDir(); + double majord=geosymaoe->getMajorRadius(); + double minord=geosymaoe->getMinorRadius(); + double df= sqrt(majord*majord+minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1); + Base::Vector3d scp = cp + 2.0*(refpoint-cp); + Base::Vector3d ssp = sp + 2.0*(refpoint-sp); + Base::Vector3d sep = ep + 2.0*(refpoint-ep); + + geosymaoe->setMajorAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(ssp,theta1); + geosymaoe->closestParameter(sep,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + Part::GeomArcOfParabola *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + /*double df= geosymaoe->getFocal();*/ + Base::Vector3d f1 = geosymaoe->getFocus(); + + Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1); + Base::Vector3d scp = cp + 2.0*(refpoint-cp); + Base::Vector3d ssp = sp + 2.0*(refpoint-sp); + Base::Vector3d sep = ep + 2.0*(refpoint-ep); + + geosymaoe->setXAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(ssp,theta1); + geosymaoe->closestParameter(sep,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, false)); + } else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){ Part::GeomPoint *geosympoint = static_cast(geosym); Base::Vector3d cp = geosympoint->getPoint(); @@ -2464,6 +2605,26 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 if(it == geoIdList.begin()) iterfirstpoint = geoaoe->getStartPoint(true); } + else if(geocopy->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + Part::GeomArcOfHyperbola *geoaoe = static_cast(geocopy); + Base::Vector3d cp = geoaoe->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geoaoe->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = geoaoe->getStartPoint(true); + } + else if(geocopy->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ + Part::GeomArcOfParabola *geoaoe = static_cast(geocopy); + Base::Vector3d cp = geoaoe->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geoaoe->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = geoaoe->getStartPoint(true); + } else if(geocopy->getTypeId() == Part::GeomPoint::getClassTypeId()){ Part::GeomPoint *geopoint = static_cast(geocopy); Base::Vector3d cp = geopoint->getPoint(); @@ -2717,7 +2878,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 if( newconstrVals.size() > constrvals.size() ) Constraints.setValues(newconstrVals); - return Geometry.getSize()-1; + return Geometry.getSize()-1; } @@ -3000,6 +3161,137 @@ int SketchObject::ExposeInternalGeometry(int GeoId) return incrgeo; //number of added elements } + else if(geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + // First we search what has to be restored + bool focus=false; + int focusgeoid=-1; + bool focus_to_vertex=false; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::ParabolaFocus: + focus=true; + focusgeoid=(*it)->First; + break; + default: + return -1; + } + } + } + + if(focus) { + // look for a line from focusgeoid:start to Geoid:mid_external + std::vector focusgeoidlistgeoidlist; + std::vector focusposidlist; + getDirectlyCoincidentPoints(focusgeoid, Sketcher::start, focusgeoidlistgeoidlist, + focusposidlist); + + std::vector parabgeoidlistgeoidlist; + std::vector parabposidlist; + getDirectlyCoincidentPoints(GeoId, Sketcher::mid, parabgeoidlistgeoidlist, + parabposidlist); + + if (!focusgeoidlistgeoidlist.empty() && !parabgeoidlistgeoidlist.empty()) { + + std::size_t i,j; + for(i=0;igetTypeId() == Part::GeomLineSegment::getClassTypeId()) { + + if((focusposidlist[i] == Sketcher::start && parabposidlist[j] == Sketcher::end) || + (focusposidlist[i] == Sketcher::end && parabposidlist[j] == Sketcher::start)) + + focus_to_vertex=true; + } + } + } + } + } + } + + int currentgeoid= getHighestCurveIndex(); + int incrgeo= 0; + + const Part::GeomArcOfParabola *aoh = static_cast(geo); + + Base::Vector3d center = aoh->getCenter(); + Base::Vector3d focusp = aoh->getFocus(); + + std::vector igeo; + std::vector icon; + + if(!focus) + { + Part::GeomPoint *pf1 = new Part::GeomPoint(); + pf1->setPoint(focusp); + + igeo.push_back(pf1); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::ParabolaFocus; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = GeoId; + + focusgeoid = currentgeoid+incrgeo+1; + + icon.push_back(newConstr); + incrgeo++; + } + + if(!focus_to_vertex) + { + Part::GeomLineSegment *paxis = new Part::GeomLineSegment(); + paxis->setPoints(center,focusp); + + igeo.push_back(paxis); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::Coincident; + newConstr->First = focusgeoid; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = currentgeoid+incrgeo+1; // just added line + newConstr->SecondPos = Sketcher::end; + + icon.push_back(newConstr); + + Sketcher::Constraint *newConstr2 = new Sketcher::Constraint(); + newConstr2->Type = Sketcher::Coincident; + newConstr2->First = GeoId; + newConstr2->FirstPos = Sketcher::mid; + newConstr2->Second = currentgeoid+incrgeo+1; // just added line + newConstr2->SecondPos = Sketcher::start; + + icon.push_back(newConstr2); + + incrgeo++; + } + + this->addGeometry(igeo,true); + this->addConstraints(icon); + + for (std::vector::iterator it=igeo.begin(); it != igeo.end(); ++it) + if (*it) + delete *it; + + for (std::vector::iterator it=icon.begin(); it != icon.end(); ++it) + if (*it) + delete *it; + + icon.clear(); + igeo.clear(); + + return incrgeo; //number of added elements + } else return -1; // not supported type } @@ -3011,8 +3303,10 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) const Part::Geometry *geo = getGeometry(GeoId); // Only for supported types - if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { - + if( geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + int majorelementindex=-1; int minorelementindex=-1; int focus1elementindex=-1; @@ -3026,12 +3320,15 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) { switch((*it)->AlignmentType){ case Sketcher::EllipseMajorDiameter: + case Sketcher::HyperbolaMajor: majorelementindex=(*it)->First; break; case Sketcher::EllipseMinorDiameter: + case Sketcher::HyperbolaMinor: minorelementindex=(*it)->First; break; - case Sketcher::EllipseFocus1: + case Sketcher::EllipseFocus1: + case Sketcher::HyperbolaFocus: focus1elementindex=(*it)->First; break; case Sketcher::EllipseFocus2: @@ -3088,6 +3385,100 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) return delgeometries.size(); //number of deleted elements } + else if( geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + // if the focus-to-vertex line is constrained, then never delete the focus + // if the line is unconstrained, then the line may be deleted, + // in this case the focus may be deleted if unconstrained. + int majorelementindex=-1; + int focus1elementindex=-1; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::ParabolaFocus: + focus1elementindex=(*it)->First; + break; + default: + return -1; + } + } + } + + if(focus1elementindex!=-1) { + // look for a line from focusgeoid:start to Geoid:mid_external + std::vector focusgeoidlistgeoidlist; + std::vector focusposidlist; + getDirectlyCoincidentPoints(focus1elementindex, Sketcher::start, focusgeoidlistgeoidlist, + focusposidlist); + + std::vector parabgeoidlistgeoidlist; + std::vector parabposidlist; + getDirectlyCoincidentPoints(GeoId, Sketcher::mid, parabgeoidlistgeoidlist, + parabposidlist); + + if (!focusgeoidlistgeoidlist.empty() && !parabgeoidlistgeoidlist.empty()) { + + std::size_t i,j; + for(i=0;igetTypeId() == Part::GeomLineSegment::getClassTypeId()) { + + if((focusposidlist[i] == Sketcher::start && parabposidlist[j] == Sketcher::end) || + (focusposidlist[i] == Sketcher::end && parabposidlist[j] == Sketcher::start)) + + majorelementindex = focusgeoidlistgeoidlist[i]; + } + } + } + } + } + } + + // Hide unused geometry here + int majorconstraints=0; // number of constraints associated to the geoid of the major axis other than the coincident ones + int focus1constraints=0; + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + + if( (*it)->Second == majorelementindex || + (*it)->First == majorelementindex || + (*it)->Third == majorelementindex) + majorconstraints++; + else if( (*it)->Second == focus1elementindex || + (*it)->First == focus1elementindex || + (*it)->Third == focus1elementindex) + focus1constraints++; + } + + std::vector delgeometries; + + if(majorelementindex !=-1 && majorconstraints<3) { // major as two coincidents to focus and vertex + delgeometries.push_back(majorelementindex); + majorelementindex = -1; + } + + if(majorelementindex == -1 && focus1elementindex !=-1 && focus1constraints<3) // focus has one coincident and one internal align + delgeometries.push_back(focus1elementindex); + + std::sort(delgeometries.begin(), delgeometries.end()); // indices over an erased element get automatically updated!! + + if(delgeometries.size()>0) + { + for (std::vector::reverse_iterator it=delgeometries.rbegin(); it!=delgeometries.rend(); ++it) { + delGeometry(*it); + } + } + + return delgeometries.size(); //number of deleted elements + } else return -1; // not supported type } @@ -3670,6 +4061,33 @@ void SketchObject::rebuildExternalGeometry(void) aoh->Construction = true; ExternalGeo.push_back(aoh); } + } else if (projCurve.GetType() == GeomAbs_Parabola) { + gp_Parab e = projCurve.Parabola(); + 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::GeomParabola* parabola = new Part::GeomParabola(); + parabola->setFocal(e.Focal()); + parabola->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + parabola->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal)); + parabola->Construction = true; + ExternalGeo.push_back(parabola); + } + else { + Part::GeomArcOfParabola* aop = new Part::GeomArcOfParabola(); + Handle_Geom_Curve curve = new Geom_Parabola(e); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(curve, projCurve.FirstParameter(), + projCurve.LastParameter()); + aop->setHandle(tCurve); + aop->Construction = true; + ExternalGeo.push_back(aop); + } } else if (projCurve.GetType() == GeomAbs_Ellipse) { gp_Elips e = projCurve.Ellipse(); @@ -3788,6 +4206,13 @@ void SketchObject::rebuildVertexIndex(void) VertexId2PosId.push_back(end); VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); } } } diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 793f54cf16..a66348aa73 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -113,6 +113,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { ret = this->getSketchObjectPtr()->addGeometry(geo,isConstruction); } @@ -165,6 +166,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { geoList.push_back(geo); } diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp index 387d526f1d..f17b89161a 100644 --- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp @@ -1423,6 +1423,82 @@ double ConstraintEqualMajorAxesConic::grad(double *param) return deriv * scale; } +// ConstraintEqualFocalDistance +ConstraintEqualFocalDistance:: ConstraintEqualFocalDistance(ArcOfParabola * a1, ArcOfParabola * a2) +{ + this->e1 = a1; + this->e1->PushOwnParams(pvec); + this->e2 = a2; + this->e2->PushOwnParams(pvec); + origpvec = pvec; + pvecChangedFlag = true; + rescale(); +} + +void ConstraintEqualFocalDistance::ReconstructGeomPointers() +{ + int i =0; + e1->ReconstructOnNewPvec(pvec, i); + e2->ReconstructOnNewPvec(pvec, i); + pvecChangedFlag = false; +} + +ConstraintType ConstraintEqualFocalDistance::getTypeId() +{ + return EqualFocalDistance; +} + +void ConstraintEqualFocalDistance::rescale(double coef) +{ + scale = coef * 1; +} + +void ConstraintEqualFocalDistance::errorgrad(double *err, double *grad, double *param) +{ + if (pvecChangedFlag) ReconstructGeomPointers(); + + DeriVector2 focus1(this->e1->focus1, param); + DeriVector2 vertex1(this->e1->vertex, param); + + DeriVector2 focalvect1 = vertex1.subtr(focus1); + + double focal1, dfocal1; + + focal1 = focalvect1.length(dfocal1); + + DeriVector2 focus2(this->e2->focus1, param); + DeriVector2 vertex2(this->e2->vertex, param); + + DeriVector2 focalvect2 = vertex2.subtr(focus2); + + double focal2, dfocal2; + + focal2 = focalvect2.length(dfocal2); + + if (err) + *err = focal2 - focal1; + if (grad) + *grad = dfocal2 - dfocal1; +} + +double ConstraintEqualFocalDistance::error() +{ + double err; + errorgrad(&err,0,0); + return scale * err; +} + +double ConstraintEqualFocalDistance::grad(double *param) +{ + //first of all, check that we need to compute anything. + if ( findParamInPvec(param) == -1 ) return 0.0; + + double deriv; + errorgrad(0, &deriv, param); + + return deriv * scale; +} + // ConstraintCurveValue ConstraintCurveValue::ConstraintCurveValue(Point &p, double* pcoord, Curve& crv, double *u) { @@ -1639,6 +1715,105 @@ double ConstraintPointOnHyperbola::grad(double *param) return scale * deriv; } +// ConstraintPointOnParabola +ConstraintPointOnParabola::ConstraintPointOnParabola(Point &p, Parabola &e) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + e.PushOwnParams(pvec); + this->parab = e.Copy(); + pvecChangedFlag = true; + origpvec = pvec; + rescale(); +} + +ConstraintPointOnParabola::ConstraintPointOnParabola(Point &p, ArcOfParabola &e) +{ + pvec.push_back(p.x); + pvec.push_back(p.y); + e.PushOwnParams(pvec); + this->parab = e.Copy(); + pvecChangedFlag = true; + origpvec = pvec; + rescale(); +} + +ConstraintPointOnParabola::~ConstraintPointOnParabola() +{ + delete this->parab; this->parab = 0; +} + +void ConstraintPointOnParabola::ReconstructGeomPointers() +{ + int i=0; + p.x=pvec[i]; i++; + p.y=pvec[i]; i++; + this->parab->ReconstructOnNewPvec(pvec, i); + pvecChangedFlag = false; +} + +ConstraintType ConstraintPointOnParabola::getTypeId() +{ + return PointOnParabola; +} + +void ConstraintPointOnParabola::rescale(double coef) +{ + scale = coef * 1; +} + +void ConstraintPointOnParabola::errorgrad(double *err, double *grad, double *param) +{ + if (pvecChangedFlag) ReconstructGeomPointers(); + + DeriVector2 focus(this->parab->focus1, param); + DeriVector2 vertex(this->parab->vertex, param); + + DeriVector2 point(this->p, param); //point to be constrained to parabola + + DeriVector2 focalvect = focus.subtr(vertex); + + DeriVector2 xdir = focalvect.getNormalized(); + + DeriVector2 point_to_focus = point.subtr(focus); + + double focal, dfocal; + + focal = focalvect.length(dfocal); + + double pf, dpf; + + pf = point_to_focus.length(dpf); + + double proj, dproj; + + proj = point_to_focus.scalarProd(xdir, &dproj); + + if (err) + *err = pf - 2*focal - proj; + if (grad) + *grad = dpf - 2*dfocal - dproj; + +} + +double ConstraintPointOnParabola::error() +{ + double err; + errorgrad(&err,0,0); + return scale * err; +} + +double ConstraintPointOnParabola::grad(double *param) +{ + //first of all, check that we need to compute anything. + if ( findParamInPvec(param) == -1 ) return 0.0; + + double deriv; + errorgrad(0, &deriv, param); + + return deriv*scale; +} + // ConstraintAngleViaPoint ConstraintAngleViaPoint::ConstraintAngleViaPoint(Curve &acrv1, Curve &acrv2, Point p, double* angle) { diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.h b/src/Mod/Sketcher/App/planegcs/Constraints.h index cafb554b92..31e993fa81 100644 --- a/src/Mod/Sketcher/App/planegcs/Constraints.h +++ b/src/Mod/Sketcher/App/planegcs/Constraints.h @@ -66,6 +66,8 @@ namespace GCS CurveValue = 20, PointOnHyperbola = 21, InternalAlignmentPoint2Hyperbola = 22, + PointOnParabola = 23, + EqualFocalDistance = 24 }; enum InternalAlignmentType { @@ -462,7 +464,22 @@ namespace GCS virtual double error(); virtual double grad(double *); }; - + + class ConstraintEqualFocalDistance : public Constraint + { + private: + ArcOfParabola * e1; + ArcOfParabola * e2; + void ReconstructGeomPointers(); //writes pointers in pvec to the parameters of crv1, crv2 and poa + void errorgrad(double* err, double* grad, double *param); //error and gradient combined. Values are returned through pointers. + public: + ConstraintEqualFocalDistance(ArcOfParabola * a1, ArcOfParabola * a2); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + class ConstraintCurveValue : public Constraint { private: @@ -511,6 +528,27 @@ namespace GCS virtual double error(); virtual double grad(double *); }; + + // PointOnParabola + class ConstraintPointOnParabola : public Constraint + { + private: + void errorgrad(double* err, double* grad, double *param); //error and gradient combined. Values are returned through pointers. + void ReconstructGeomPointers(); //writes pointers in pvec to the parameters of crv1, crv2 and poa + Parabola* parab; + Point p; + public: + ConstraintPointOnParabola(Point &p, Parabola &e); + ConstraintPointOnParabola(Point &p, ArcOfParabola &a); + ~ConstraintPointOnParabola(); + #ifdef _GCS_EXTRACT_SOLVER_SUBSYSTEM_ + inline ConstraintPointOnParabola(){} + #endif + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; class ConstraintAngleViaPoint : public Constraint { diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp index 312830ec71..89ece2d11d 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp @@ -582,6 +582,13 @@ int System::addConstraintPointOnHyperbolicArc(Point &p, ArcOfHyperbola &e, int t return addConstraint(constr); } +int System::addConstraintPointOnParabolicArc(Point &p, ArcOfParabola &e, int tagId) +{ + Constraint *constr = new ConstraintPointOnParabola(p, e); + constr->setTag(tagId); + return addConstraint(constr); +} + int System::addConstraintArcOfEllipseRules(ArcOfEllipse &a, int tagId) { addConstraintCurveValue(a.start,a,a.startAngle, tagId); @@ -604,6 +611,12 @@ int System::addConstraintArcOfHyperbolaRules(ArcOfHyperbola &a, int tagId) return addConstraintCurveValue(a.end,a,a.endAngle, tagId); } +int System::addConstraintArcOfParabolaRules(ArcOfParabola &a, int tagId) +{ + addConstraintCurveValue(a.start,a,a.startAngle, tagId); + return addConstraintCurveValue(a.end,a,a.endAngle, tagId); +} + int System::addConstraintPointOnArc(Point &p, Arc &a, int tagId) { return addConstraintP2PDistance(p, a.center, a.rad, tagId); @@ -750,7 +763,14 @@ int System::addConstraintEqualRadii(ArcOfHyperbola &a1, ArcOfHyperbola &a2, int Constraint *constr = new ConstraintEqualMajorAxesConic(&a1,&a2); constr->setTag(tagId); - return addConstraint(constr); + return addConstraint(constr); +} + +int System::addConstraintEqualFocus(ArcOfParabola &a1, ArcOfParabola &a2, int tagId) +{ + Constraint *constr = new ConstraintEqualFocalDistance(&a1,&a2); + constr->setTag(tagId); + return addConstraint(constr); } int System::addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId) @@ -981,6 +1001,12 @@ int System::addConstraintInternalAlignmentHyperbolaFocus(Hyperbola &e, Point &p1 return addConstraintEqual(e.focus1.y, p1.y, tagId); } +int System::addConstraintInternalAlignmentParabolaFocus(Parabola &e, Point &p1, int tagId) +{ + addConstraintEqual(e.focus1.x, p1.x, tagId); + return addConstraintEqual(e.focus1.y, p1.y, tagId); +} + //calculates angle between two curves at point of their intersection p. If two //points are supplied, p is used for first curve and p2 for second, yielding a diff --git a/src/Mod/Sketcher/App/planegcs/GCS.h b/src/Mod/Sketcher/App/planegcs/GCS.h index e6ee58ac46..1ff0778017 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.h +++ b/src/Mod/Sketcher/App/planegcs/GCS.h @@ -182,9 +182,11 @@ namespace GCS int addConstraintPointOnCircle(Point &p, Circle &c, int tagId=0); int addConstraintPointOnEllipse(Point &p, Ellipse &e, int tagId=0); int addConstraintPointOnHyperbolicArc(Point &p, ArcOfHyperbola &e, int tagId=0); + int addConstraintPointOnParabolicArc(Point &p, ArcOfParabola &e, int tagId=0); int addConstraintArcOfEllipseRules(ArcOfEllipse &a, int tagId=0); int addConstraintCurveValue(Point &p, Curve &a, double *u, int tagId=0); - int addConstraintArcOfHyperbolaRules(ArcOfHyperbola &a, int tagId=0); + int addConstraintArcOfHyperbolaRules(ArcOfHyperbola &a, int tagId=0); + int addConstraintArcOfParabolaRules(ArcOfParabola &a, int tagId=0); int addConstraintPointOnArc(Point &p, Arc &a, int tagId=0); int addConstraintPerpendicularLine2Arc(Point &p1, Point &p2, Arc &a, int tagId=0); @@ -211,6 +213,7 @@ namespace GCS int addConstraintEqualRadii(ArcOfHyperbola &a1, ArcOfHyperbola &a2, int tagId=0); int addConstraintEqualRadius(Circle &c1, Arc &a2, int tagId=0); int addConstraintEqualRadius(Arc &a1, Arc &a2, int tagId=0); + int addConstraintEqualFocus(ArcOfParabola &a1, ArcOfParabola &a2, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); int addConstraintP2PSymmetric(Point &p1, Point &p2, Point &p, int tagId=0); int addConstraintSnellsLaw(Curve &ray1, Curve &ray2, @@ -229,6 +232,7 @@ namespace GCS int addConstraintInternalAlignmentHyperbolaMajorDiameter(Hyperbola &e, Point &p1, Point &p2, int tagId=0); int addConstraintInternalAlignmentHyperbolaMinorDiameter(Hyperbola &e, Point &p1, Point &p2, int tagId=0); int addConstraintInternalAlignmentHyperbolaFocus(Hyperbola &e, Point &p1, int tagId=0); + int addConstraintInternalAlignmentParabolaFocus(Parabola &e, Point &p1, int tagId=0); double calculateAngleViaPoint(Curve &crv1, Curve &crv2, Point &p); double calculateAngleViaPoint(Curve &crv1, Curve &crv2, Point &p1, Point &p2); diff --git a/src/Mod/Sketcher/App/planegcs/Geo.cpp b/src/Mod/Sketcher/App/planegcs/Geo.cpp index 3ac1c9610d..66cb59d479 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.cpp +++ b/src/Mod/Sketcher/App/planegcs/Geo.cpp @@ -504,4 +504,107 @@ ArcOfHyperbola* ArcOfHyperbola::Copy() return crv; } +//---------------parabola + +DeriVector2 Parabola::CalculateNormal(Point &p, double* derivparam) +{ + //fill some vectors in + DeriVector2 cv (vertex, derivparam); + DeriVector2 f1v (focus1, derivparam); + DeriVector2 pv (p, derivparam); + + // the normal is the vector from the focus to the intersection of ano thru the point p and direction + // of the symetry axis of the parabola with the directrix. + // As both point to directrix and point to focus are of equal magnitude, we can work with unitary vectors + // to calculate the normal, substraction of those vectors. + + DeriVector2 ret = cv.subtr(f1v).getNormalized().subtr(f1v.subtr(pv).getNormalized()); + + return ret; +} + +DeriVector2 Parabola::Value(double u, double du, double* derivparam) +{ + + //In local coordinate system, value() of parabola is: + //P(U) = O + U*U/(4.*F)*XDir + U*YDir + + DeriVector2 c(this->vertex, derivparam); + DeriVector2 f1(this->focus1, derivparam); + + DeriVector2 fv = f1.subtr(c); + + double f,df; + + f = fv.length(df); + + DeriVector2 xdir = fv.getNormalized(); + DeriVector2 ydir = xdir.rotate90ccw(); + + DeriVector2 dirx = xdir.multD(u,du).multD(u,du).divD(4*f,4*df); + DeriVector2 diry = ydir.multD(u,du); + + DeriVector2 dir = dirx.sum(diry); + + DeriVector2 ret; //point of parabola at parameter value of u, in global coordinates + + ret = c.sum( dir ); + + return ret; +} + +int Parabola::PushOwnParams(VEC_pD &pvec) +{ + int cnt=0; + pvec.push_back(vertex.x); cnt++; + pvec.push_back(vertex.y); cnt++; + pvec.push_back(focus1.x); cnt++; + pvec.push_back(focus1.y); cnt++; + return cnt; +} + +void Parabola::ReconstructOnNewPvec(VEC_pD &pvec, int &cnt) +{ + vertex.x=pvec[cnt]; cnt++; + vertex.y=pvec[cnt]; cnt++; + focus1.x=pvec[cnt]; cnt++; + focus1.y=pvec[cnt]; cnt++; +} + +Parabola* Parabola::Copy() +{ + Parabola* crv = new Parabola(*this); + return crv; +} + +//--------------- arc of hyperbola +int ArcOfParabola::PushOwnParams(VEC_pD &pvec) +{ + int cnt=0; + cnt += Parabola::PushOwnParams(pvec); + pvec.push_back(start.x); cnt++; + pvec.push_back(start.y); cnt++; + pvec.push_back(end.x); cnt++; + pvec.push_back(end.y); cnt++; + pvec.push_back(startAngle); cnt++; + pvec.push_back(endAngle); cnt++; + return cnt; + +} +void ArcOfParabola::ReconstructOnNewPvec(VEC_pD &pvec, int &cnt) +{ + Parabola::ReconstructOnNewPvec(pvec,cnt); + start.x=pvec[cnt]; cnt++; + start.y=pvec[cnt]; cnt++; + end.x=pvec[cnt]; cnt++; + end.y=pvec[cnt]; cnt++; + startAngle=pvec[cnt]; cnt++; + endAngle=pvec[cnt]; cnt++; +} +ArcOfParabola* ArcOfParabola::Copy() +{ + ArcOfParabola* crv = new ArcOfParabola(*this); + return crv; +} + }//namespace GCS diff --git a/src/Mod/Sketcher/App/planegcs/Geo.h b/src/Mod/Sketcher/App/planegcs/Geo.h index 04e871447b..b717904002 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.h +++ b/src/Mod/Sketcher/App/planegcs/Geo.h @@ -239,6 +239,36 @@ namespace GCS virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt); virtual ArcOfHyperbola* Copy(); }; + + class Parabola: public Curve + { + public: + Parabola(){ } + virtual ~Parabola(){} + Point vertex; + Point focus1; + DeriVector2 CalculateNormal(Point &p, double* derivparam = 0); + virtual DeriVector2 Value(double u, double du, double* derivparam = 0); + virtual int PushOwnParams(VEC_pD &pvec); + virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt); + virtual Parabola* Copy(); + }; + + class ArcOfParabola: public Parabola + { + public: + ArcOfParabola(){startAngle=0;endAngle=0;} + virtual ~ArcOfParabola(){} + // parameters + double *startAngle; + double *endAngle; + Point start; + Point end; + // interface helpers + virtual int PushOwnParams(VEC_pD &pvec); + virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt); + virtual ArcOfParabola* Copy(); + }; } //namespace GCS diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 398136d0a5..b1cfc047b1 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -552,6 +552,102 @@ void SketcherGui::makeTangentToArcOfHyperbolaviaNewPoint(const Sketcher::SketchO Gui::Command::updateActive(); } +/// Makes a simple tangency constraint using extra point + tangent via point +/// geom1 => an arc of parabola +/// geom2 => any of an arc of parabola, an arc of hyperbola an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void SketcherGui::makeTangentToArcOfParabolaviaNewPoint(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 +) +{ + const Part::GeomArcOfParabola *aop = static_cast(geom1); + + //Base::Vector3d center=aop->getCenter(); + + //Base::Vector3d dirx = aop->getXAxisDir(); + //double phi=atan2(dirx.y, dirx.x); + //double df = aop->getFocal(); + Base::Vector3d focus = aop->getFocus(); + + Base::Vector3d center2; + + if( geom2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) + center2= (static_cast(geom2))->getFocus(); + else if( geom2->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()){ + const Part::GeomArcOfHyperbola *aoh2 = static_cast(geom2); + Base::Vector3d dirmaj2 = aoh2->getMajorAxisDir(); + double majord2 = aoh2->getMajorRadius(); + double minord2 = aoh2->getMinorRadius(); + double df2 = sqrt(majord2*majord2+minord2*minord2); + center2 = aoh2->getCenter()+df2*dirmaj2; // positive focus + } + else if( geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + center2= (static_cast(geom2))->getCenter(); + else if( geom2->getTypeId() == Part::GeomEllipse::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(); + else if( geom2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *l2 = static_cast(geom2); + center2= (l2->getStartPoint() + l2->getEndPoint())/2; + } + + Base::Vector3d direction = center2-focus; + /*double angle = atan2(direction.y,direction.x)-phi; + double tapprox = 4*df*tan(angle);*/ + + Base::Vector3d PoP = focus + direction / 2; + + + /*Base::Vector3d(center.x + tapprox * tapprox / 4 / df * cos(phi) - tapprox * sin(phi), + center.y + tapprox * tapprox / 4 / df * sin(phi) + tapprox * cos(phi), 0);*/ + + try { + // Add a point + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), PoP.x,PoP.y); + int GeoIdPoint = Obj->getHighestCurveIndex(); + + // Point on first object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoIdPoint,Sketcher::start,geoId1); // constrain major axis + // Point on second object + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoIdPoint,Sketcher::start,geoId2); // constrain major axis + // tangent via point + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('TangentViaPoint',%d,%d,%d,%d))", + Obj->getNameInDocument(), geoId1, geoId2 ,GeoIdPoint, Sketcher::start); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) // toggling does not modify the DoF of the solver, however it may affect features depending on the sketch + Gui::Command::updateActive(); + + return; + } + + Gui::Command::commitCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); +} + namespace SketcherGui { @@ -1916,10 +2012,12 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) if( geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || - geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { Base::Vector3d center; Base::Vector3d majdir; + Base::Vector3d focus; double majord = 0; double minord = 0; double phi = 0; @@ -1943,31 +2041,43 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) phi=atan2(majdir.y, majdir.x); } else - if( geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ){ - const Part::GeomArcOfHyperbola *aoh = static_cast(geo1); - - center=aoh->getCenter(); - majord=aoh->getMajorRadius(); - minord=aoh->getMinorRadius(); - majdir=aoh->getMajorAxisDir(); - phi=atan2(majdir.y, majdir.x); - } + if( geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ){ + const Part::GeomArcOfHyperbola *aoh = static_cast(geo1); + + center=aoh->getCenter(); + majord=aoh->getMajorRadius(); + minord=aoh->getMinorRadius(); + majdir=aoh->getMajorAxisDir(); + phi=atan2(majdir.y, majdir.x); + } + else + if( geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ){ + const Part::GeomArcOfParabola *aop = static_cast(geo1); + + center=aop->getCenter(); + focus=aop->getFocus(); + } const Part::GeomLineSegment *line = static_cast(geo2); Base::Vector3d point1=line->getStartPoint(); Base::Vector3d PoO; - if( geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ) { double df=sqrt(majord*majord+minord*minord); Base::Vector3d direction=point1-(center+majdir*df); // towards the focus double tapprox=atan2(direction.y,direction.x)-phi; - + PoO = Base::Vector3d(center.x+majord*cosh(tapprox)*cos(phi)-minord*sinh(tapprox)*sin(phi), center.y+majord*cosh(tapprox)*sin(phi)+minord*sinh(tapprox)*cos(phi), 0); } - else { + else if( geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + Base::Vector3d direction=point1-focus; // towards the focus + + PoO = point1 + direction / 2; + } + else + { Base::Vector3d direction=point1-center; double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar @@ -1998,24 +2108,24 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); Gui::Command::abortCommand(); - + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); - + if(autoRecompute) // toggling does not modify the DoF of the solver, however it may affect features depending on the sketch Gui::Command::updateActive(); - + return; } commitCommand(); - + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); - + if(autoRecompute) Gui::Command::updateActive(); - + getSelection().clearSelection(); return; @@ -2266,6 +2376,12 @@ void CmdSketcherConstrainTangent::activated(int iMsg) getSelection().clearSelection(); return; } + else if( geom2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + Gui::Command::openCommand("add tangent constraint point"); + makeTangentToArcOfParabolaviaNewPoint(Obj,geom2,geom1,GeoId2,GeoId1); + getSelection().clearSelection(); + return; + } } else if( geom1 && geom2 && ( geom1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || @@ -2289,8 +2405,38 @@ void CmdSketcherConstrainTangent::activated(int iMsg) getSelection().clearSelection(); return; } + else if( geom2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + Gui::Command::openCommand("add tangent constraint point"); + makeTangentToArcOfParabolaviaNewPoint(Obj,geom2,geom1,GeoId2,GeoId1); + getSelection().clearSelection(); + return; + } } + else if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomArcOfParabola::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId1 is the arc of hyperbola + geom1 = Obj->getGeometry(GeoId1); + geom2 = Obj->getGeometry(GeoId2); + + if( geom2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geom2->getTypeId() == Part::GeomCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || + geom2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) { + + Gui::Command::openCommand("add tangent constraint point"); + makeTangentToArcOfParabolaviaNewPoint(Obj,geom1,geom2,GeoId1,GeoId2); + getSelection().clearSelection(); + return; + } + } openCommand("add tangent constraint"); Gui::Command::doCommand( diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.h b/src/Mod/Sketcher/Gui/CommandConstraints.h index 3fe2f11f0a..2b25ac95f6 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.h +++ b/src/Mod/Sketcher/Gui/CommandConstraints.h @@ -66,6 +66,18 @@ void makeTangentToArcOfHyperbolaviaNewPoint(const Sketcher::SketchObject* Obj, int geoId2 ); +/// Makes a simple tangency constraint using extra point + tangent via point +/// geom1 => an arc of parabola +/// geom2 => any of an arc of parabola, an arc of hyperbola an arc of ellipse, a circle, or an arc (of circle) +/// NOTE: A command must be opened before calling this function, which this function +/// commits or aborts as appropriate. The reason is for compatibility reasons with +/// other code e.g. "Autoconstraints" in DrawSketchHandler.cpp +void makeTangentToArcOfParabolaviaNewPoint(const Sketcher::SketchObject* Obj, + const Part::Geometry *geom1, + const Part::Geometry *geom2, + int geoId1, + int geoId2 +); } #endif // SKETCHERGUI_DrawSketchHandler_H diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 55642d5db8..aac9ec8ddc 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -3779,6 +3779,357 @@ bool CmdSketcherCreateArcOfHyperbola::isActive(void) return isCreateGeoActive(getActiveGuiDocument()); } +/* XPM */ +static const char *cursor_createarcofparabola[]={ +"32 32 3 1", +"+ c white", +"# c red", +". c None", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"................................", +"+++++...+++++...................", +"................................", +"......+.........................", +"......+.........................", +"......+................##.......", +"......+..............##.........", +"......+............##...........", +"......+...........##............", +"................##..............", +"...............##...............", +"..............##................", +".............###................", +"............##......###.........", +"...........##......#.#..........", +"...........##.....###...........", +"..........##....................", +".........##.....................", +"........##......................", +"........##......................", +"........##......................", +"........#.....####..............", +"........######..................", +"................................", +"................................", +"................................", +"................................"}; + +class DrawSketchHandlerArcOfParabola : public DrawSketchHandler +{ +public: + DrawSketchHandlerArcOfParabola() : Mode(STATUS_SEEK_First),EditCurve(34){} + virtual ~DrawSketchHandlerArcOfParabola(){} + /// mode table + enum SelectMode { + STATUS_SEEK_First, /**< enum value ----. */ + STATUS_SEEK_Second, /**< enum value ----. */ + STATUS_SEEK_Third, /**< enum value ----. */ + STATUS_SEEK_Fourth, /**< enum value ----. */ + STATUS_Close + }; + + virtual void activated(ViewProviderSketch * /*sketchgui*/) + { + setCursor(QPixmap(cursor_createarcofparabola),7,7); + } + + virtual void mouseMove(Base::Vector2d onSketchPos) + { + if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); + if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr1); + return; + } + } + else if (Mode==STATUS_SEEK_Second) { + EditCurve[1]= onSketchPos; + + // Display radius for user + float radius = (onSketchPos - focusPoint).Length(); + + SbString text; + text.sprintf(" (F%.1f)", radius); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } + } + else if (Mode==STATUS_SEEK_Third) { + double focal = (axisPoint-focusPoint).Length(); + double phi = atan2(focusPoint.y-axisPoint.y,focusPoint.x-axisPoint.x); + + // P(U) = O + U*U/(4.*F)*XDir + U*YDir + // + // pnt = Base::Vector3d(pnt0.x + angle * angle / 4 / focal * cos(phi) - angle * sin(phi), + // pnt0.y + angle * angle / 4 / focal * sin(phi) + angle * cos(phi), + // 0.f); + + // This is the angle at cursor point + double u = + ( cos(phi) * (onSketchPos.y - axisPoint.y) - (onSketchPos.x - axisPoint.x) * sin(phi)); + + for (int i=15; i >= -15; i--) { + double angle=i*u/15; + double rx = angle * angle / 4 / focal * cos(phi) - angle * sin(phi); + double ry = angle * angle / 4 / focal * sin(phi) + angle * cos(phi); + EditCurve[15+i] = Base::Vector2d(axisPoint.x + rx, axisPoint.y + ry); + } + + // Display radius for user + SbString text; + text.sprintf(" (F%.1f)", focal); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr3); + return; + } + } + else if (Mode==STATUS_SEEK_Fourth) { + double focal = (axisPoint-focusPoint).Length(); + double phi = atan2(focusPoint.y-axisPoint.y,focusPoint.x-axisPoint.x); + + // P(U) = O + U*U/(4.*F)*XDir + U*YDir + // + // pnt = Base::Vector3d(pnt0.x + angle * angle / 4 / focal * cos(phi) - angle * sin(phi), + // pnt0.y + angle * angle / 4 / focal * sin(phi) + angle * cos(phi), + // 0.f); + + // This is the angle at starting point + double ustartpoint = + ( cos(phi) * (startingPoint.y - axisPoint.y) - (startingPoint.x - axisPoint.x) * sin(phi)); + + double startAngle = ustartpoint; + + double u = + ( cos(phi) * (onSketchPos.y - axisPoint.y) - (onSketchPos.x - axisPoint.x) * sin(phi)); + + + arcAngle = u - startAngle; + + if(!boost::math::isnan(arcAngle)){ + for (int i=0; i < 33; i++) { + double angle = startAngle+i*arcAngle/32.0; + double rx = angle * angle / 4 / focal * cos(phi) - angle * sin(phi); + double ry = angle * angle / 4 / focal * sin(phi) + angle * cos(phi); + EditCurve[i] = Base::Vector2d(axisPoint.x + rx, axisPoint.y + ry); + } + + SbString text; + text.sprintf(" (F%.1f)", focal); + setPositionText(onSketchPos, text); + } + else + { + arcAngle=0.; + } + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr4); + return; + } + } + + applyCursor(); + } + + virtual bool pressButton(Base::Vector2d onSketchPos) + { + if (Mode==STATUS_SEEK_First){ + EditCurve[0] = onSketchPos; + focusPoint = onSketchPos; + EditCurve.resize(2); + Mode = STATUS_SEEK_Second; + } + else if(Mode==STATUS_SEEK_Second) { + EditCurve[1] = onSketchPos; + axisPoint = onSketchPos; + EditCurve.resize(31); + Mode = STATUS_SEEK_Third; + } + else if(Mode==STATUS_SEEK_Third) { + startingPoint = onSketchPos; + arcAngle = 0.; + arcAngle_t= 0.; + Mode = STATUS_SEEK_Fourth; + } + else { // Fourth + endPoint = onSketchPos; + Mode = STATUS_Close; + } + return true; + } + + virtual bool releaseButton(Base::Vector2d /*onSketchPos*/) + { + if (Mode==STATUS_Close) { + unsetCursor(); + resetPositionText(); + + double phi = atan2(focusPoint.y-axisPoint.y,focusPoint.x-axisPoint.x); + + double ustartpoint = + ( cos(phi) * (startingPoint.y - axisPoint.y) - (startingPoint.x - axisPoint.x) * sin(phi)); + + double uendpoint = + ( cos(phi) * (endPoint.y - axisPoint.y) - (endPoint.x - axisPoint.x) * sin(phi)); + + double startAngle = ustartpoint; + + double endAngle = uendpoint; + + bool isOriginalArcCCW=true; + + if (arcAngle > 0) + endAngle = startAngle + arcAngle; + else { + endAngle = startAngle; + startAngle += arcAngle; + isOriginalArcCCW=false; + } + + int currentgeoid = getHighestCurveIndex(); + + try { + + Gui::Command::openCommand("Add sketch arc of Parabola"); + + //Add arc of parabola + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.addGeometry(Part.ArcOfParabola" + "(Part.Parabola(App.Vector(%f,%f,0),App.Vector(%f,%f,0),App.Vector(0,0,1))," + "%f,%f),%s)", + sketchgui->getObject()->getNameInDocument(), + focusPoint.x, focusPoint.y, + axisPoint.x, axisPoint.y, + startAngle, endAngle, + geometryCreationMode==Construction?"True":"False"); + + currentgeoid++; + + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", + sketchgui->getObject()->getNameInDocument(), + currentgeoid); + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + else + static_cast(sketchgui->getObject())->solve(); + + return false; + } + + Gui::Command::commitCommand(); + + // add auto constraints for the focus point + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, currentgeoid+1, Sketcher::start); + sugConstr1.clear(); + } + + // add suggested constraints for vertex point + if (sugConstr2.size() > 0) { + createAutoConstraints(sugConstr2, currentgeoid, Sketcher::mid); + sugConstr2.clear(); + } + + // add suggested constraints for start of arc + if (sugConstr3.size() > 0) { + createAutoConstraints(sugConstr3, currentgeoid, isOriginalArcCCW?Sketcher::start:Sketcher::end); + sugConstr3.clear(); + } + + // add suggested constraints for start of arc + if (sugConstr4.size() > 0) { + createAutoConstraints(sugConstr4, currentgeoid, isOriginalArcCCW?Sketcher::end:Sketcher::start); + sugConstr4.clear(); + } + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + else + static_cast(sketchgui->getObject())->solve(); + + bool continuousMode = hGrp->GetBool("ContinuousCreationMode",true); + + if(continuousMode){ + // This code enables the continuous creation mode. + Mode = STATUS_SEEK_First; + EditCurve.clear(); + sketchgui->drawEdit(EditCurve); + EditCurve.resize(34); + applyCursor(); + /* It is ok not to call to purgeHandler + * in continuous creation mode because the + * handler is destroyed by the quit() method on pressing the + * right button of the mouse */ + } + else{ + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + } + return true; + } +protected: + SelectMode Mode; + std::vector EditCurve; + Base::Vector2d focusPoint, axisPoint, startingPoint, endPoint; + double rx, ry, startAngle, endAngle, arcAngle, arcAngle_t; + std::vector sugConstr1, sugConstr2, sugConstr3, sugConstr4; + +}; + +DEF_STD_CMD_A(CmdSketcherCreateArcOfParabola); + +CmdSketcherCreateArcOfParabola::CmdSketcherCreateArcOfParabola() + : Command("Sketcher_CreateArcOfParabola") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create an arc of parabola"); + sToolTipText = QT_TR_NOOP("Create an arc of parabola in the sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_Parabolic_Arc"; + eType = ForEdit; +} + +void CmdSketcherCreateArcOfParabola::activated(int /*iMsg*/) +{ + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerArcOfParabola() ); +} + +bool CmdSketcherCreateArcOfParabola::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + + + + /// @brief Macro that declares a new sketcher command class 'CmdSketcherCompCreateEllipse' DEF_STD_CMD_ACLU(CmdSketcherCompCreateConic); @@ -3811,6 +4162,8 @@ void CmdSketcherCompCreateConic::activated(int iMsg) ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerArcOfEllipse()); } else if (iMsg == 3) { ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerArcOfHyperbola()); + } else if (iMsg == 4) { + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerArcOfParabola()); } else { return; } @@ -3841,6 +4194,9 @@ Gui::Action * CmdSketcherCompCreateConic::createAction(void) QAction* arcofhyperbola = pcAction->addAction(QString()); arcofhyperbola->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Hyperbolic_Arc")); + + QAction* arcofparabola = pcAction->addAction(QString()); + arcofparabola->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Parabolic_Arc")); _pcAction = pcAction; languageChange(); @@ -3867,6 +4223,7 @@ void CmdSketcherCompCreateConic::updateAction(int mode) a[1]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateEllipse_3points")); a[2]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Elliptical_Arc")); a[3]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Hyperbolic_Arc")); + a[4]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Parabolic_Arc")); getAction()->setIcon(a[index]->icon()); break; case Construction: @@ -3874,6 +4231,7 @@ void CmdSketcherCompCreateConic::updateAction(int mode) a[1]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateEllipse_3points_Constr")); a[2]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Elliptical_Arc_Constr")); a[3]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Hyperbolic_Arc_Constr")); + a[4]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Parabolic_Arc_Constr")); getAction()->setIcon(a[index]->icon()); break; } @@ -3904,6 +4262,10 @@ void CmdSketcherCompCreateConic::languageChange() arcofhyperbola->setText(QApplication::translate("CmdSketcherCompCreateConic","Arc of hyperbola by center, major radius, endpoints")); arcofhyperbola->setToolTip(QApplication::translate("Sketcher_CreateArcOfHyperbola","Create an arc of hyperbola by its center, major radius, endpoints")); arcofhyperbola->setStatusTip(QApplication::translate("Sketcher_CreateArcOfHyperbola","Create an arc of hyperbola by its center, major radius, endpoints")); + QAction* arcofparabola = a[4]; + arcofparabola->setText(QApplication::translate("CmdSketcherCompCreateConic","Arc of parabola by focus, vertex, endpoints")); + arcofparabola->setToolTip(QApplication::translate("Sketcher_CreateArcOfParabola","Create an arc of parabola by its focus, vertex, endpoints")); + arcofparabola->setStatusTip(QApplication::translate("Sketcher_CreateArcOfParabola","Create an arc of parabola by its focus, vertex, endpoints")); } bool CmdSketcherCompCreateConic::isActive(void) @@ -5977,6 +6339,7 @@ void CreateSketcherCommandsCreateGeo(void) rcCmdMgr.addCommand(new CmdSketcherCompCreateConic()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfEllipse()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfHyperbola()); + rcCmdMgr.addCommand(new CmdSketcherCreateArcOfParabola()); rcCmdMgr.addCommand(new CmdSketcherCreateLine()); rcCmdMgr.addCommand(new CmdSketcherCreatePolyline()); rcCmdMgr.addCommand(new CmdSketcherCreateRectangle()); diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 0b5ff9adc0..e129176bd2 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -762,226 +762,57 @@ void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) const Part::Geometry *geo = Obj->getGeometry(GeoId); // Only for supported types - if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { - // First we search what has to be restored - bool major=false; - bool minor=false; - bool focus1=false; - bool focus2=false; - - int majorelementindex=-1; - int minorelementindex=-1; - int focus1elementindex=-1; - int focus2elementindex=-1; - - const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); - - for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); - it != vals.end(); ++it) { - if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) - { - switch((*it)->AlignmentType){ - case Sketcher::EllipseMajorDiameter: - major=true; - majorelementindex=(*it)->First; - break; - case Sketcher::EllipseMinorDiameter: - minor=true; - minorelementindex=(*it)->First; - break; - case Sketcher::EllipseFocus1: - focus1=true; - focus1elementindex=(*it)->First; - break; - case Sketcher::EllipseFocus2: - focus2=true; - focus2elementindex=(*it)->First; - break; - default: - break; - } - } - } - - if(major && minor && focus1 && focus2) - { - // Hide unused geometry here - int majorconstraints=0; // number of constraints associated to the geoid of the major axis - int minorconstraints=0; - int focus1constraints=0; - int focus2constraints=0; - - for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); - it != vals.end(); ++it) { - - if((*it)->Second == majorelementindex || (*it)->First == majorelementindex || (*it)->Third == majorelementindex) - majorconstraints++; - else if((*it)->Second == minorelementindex || (*it)->First == minorelementindex || (*it)->Third == minorelementindex) - minorconstraints++; - else if((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex || (*it)->Third == focus1elementindex) - focus1constraints++; - else if((*it)->Second == focus2elementindex || (*it)->First == focus2elementindex || (*it)->Third == focus2elementindex) - focus2constraints++; - } - // those with less than 2 constraints must be removed - if(majorconstraints>=2 && minorconstraints>=2 && focus1constraints>=2 && focus2constraints>=2) - return; // nothing to delete - - App::Document* doc = App::GetApplication().getActiveDocument(); - - if (!doc) return; - - doc->openTransaction("Delete"); - - if(majorconstraints<2) { - ss.str(std::string()); - ss << "Edge" << majorelementindex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); - } - - if(minorconstraints<2) { - ss.str(std::string()); - ss << "Edge" << minorelementindex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); - } - - if(focus1constraints<2) { - ss.str(std::string()); - int vertex = Obj->getVertexIndexGeoPos(focus1elementindex,Sketcher::start); - if(vertex>-1){ - ss << "Vertex" << vertex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); - } - } - - if(focus2constraints<2) { - ss.str(std::string()); - int vertex = Obj->getVertexIndexGeoPos(focus2elementindex,Sketcher::start); - if(vertex>-1){ - ss << "Vertex" << vertex + 1; - Gui::Selection().addSelection(doc_name.c_str(), obj_name.c_str(), ss.str().c_str()); - } - } - - SketcherGui::ViewProviderSketch* vp = dynamic_cast(getActiveGuiDocument()->getInEdit()); + if( geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { - if (vp) { - std::vector sel = Gui::Selection().getSelectionEx(doc->getName()); - vp->onDelete(sel[0].getSubNames()); - } - - - doc->commitTransaction(); - return; - } - - Gui::Command::openCommand("Expose ellipse internal geometry"); - - int currentgeoid= Obj->getHighestCurveIndex(); - int incrgeo= 0; - - Base::Vector3d center; - double majord; - double minord; - Base::Vector3d majdir; - - if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()){ - const Part::GeomEllipse *ellipse = static_cast(geo); - - center=ellipse->getCenter(); - majord=ellipse->getMajorRadius(); - minord=ellipse->getMinorRadius(); - majdir=ellipse->getMajorAxisDir(); - } - else { - const Part::GeomArcOfEllipse *aoe = static_cast(geo); - - center=aoe->getCenter(); - majord=aoe->getMajorRadius(); - minord=aoe->getMinorRadius(); - majdir=aoe->getMajorAxisDir(); - } + int currentgeoid = Obj->getHighestCurveIndex(); - Base::Vector3d mindir = Base::Vector3d(-majdir.y, majdir.x, 0.0); - - Base::Vector3d majorpositiveend = center + majord * majdir; - Base::Vector3d majornegativeend = center - majord * majdir; - Base::Vector3d minorpositiveend = center + minord * mindir; - Base::Vector3d minornegativeend = center - minord * mindir; - - double df= sqrt(majord*majord-minord*minord); - - Base::Vector3d focus1P = center + df * majdir; - Base::Vector3d focus2P = center - df * majdir; - - try{ - if(!major) - { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)),True)", - Obj->getNameInDocument(), - majorpositiveend.x,majorpositiveend.y,majornegativeend.x,majornegativeend.y); // create line for major axis - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", - selection[0].getFeatName(),currentgeoid+incrgeo+1,GeoId); // constrain major axis - incrgeo++; - } - if(!minor) - { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)),True)", - Obj->getNameInDocument(), - minorpositiveend.x,minorpositiveend.y,minornegativeend.x,minornegativeend.y); // create line for minor axis - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", - selection[0].getFeatName(),currentgeoid+incrgeo+1,GeoId); // constrain minor axis - incrgeo++; - } - if(!focus1) - { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - Obj->getNameInDocument(), - focus1P.x,focus1P.y); - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", - selection[0].getFeatName(),currentgeoid+incrgeo+1,Sketcher::start,GeoId); // constrain major axis - incrgeo++; - } - if(!focus2) - { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", - Obj->getNameInDocument(), - focus2P.x,focus2P.y); - - Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", - Obj->getNameInDocument(),currentgeoid+incrgeo+1,Sketcher::start,GeoId); // constrain major axis - } - - Gui::Command::commitCommand(); - - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool autoRecompute = hGrp->GetBool("AutoRecompute",false); - - if(autoRecompute) - Gui::Command::updateActive(); - - } - catch (const Base::Exception& e) { - Base::Console().Error("%s\n", e.what()); - Gui::Command::abortCommand(); - - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); - bool autoRecompute = hGrp->GetBool("AutoRecompute",false); - - if(autoRecompute) - Gui::Command::updateActive(); - } - - } // if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) - else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Currently internal geometry is only supported for ellipse and arc of ellipse. The last selected element must be an ellipse or an arc of ellipse.")); - } + try { + Gui::Command::openCommand("Exposing Internal Geometry"); - } + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", + Obj->getNameInDocument(), + GeoId); + + int aftergeoid = Obj->getHighestCurveIndex(); + + if(aftergeoid == currentgeoid) { // if we did not expose anything, deleteunused + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.DeleteUnusedInternalGeometry(%d)", + Obj->getNameInDocument(), + GeoId); + } + + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + else + static_cast(Obj)->solve(); + + return; + } + + Gui::Command::commitCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + else + static_cast(Obj)->solve(); + } + } } } diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index db139b8d42..b7639491bd 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -118,6 +118,10 @@ icons/Sketcher_Element_Line_Edge.svg icons/Sketcher_Element_Line_EndPoint.svg icons/Sketcher_Element_Line_StartingPoint.svg + icons/Sketcher_Element_Parabolic_Arc_Centre_Point.svg + icons/Sketcher_Element_Parabolic_Arc_Edge.svg + icons/Sketcher_Element_Parabolic_Arc_End_Point.svg + icons/Sketcher_Element_Parabolic_Arc_Start_Point.svg icons/Sketcher_Element_Point_StartingPoint.svg icons/Sketcher_Element_SelectionTypeInvalid.svg icons/Sketcher_Elliptical_Arc.svg @@ -130,6 +134,8 @@ icons/Sketcher_MergeSketch.svg icons/Sketcher_MirrorSketch.svg icons/Sketcher_NewSketch.svg + icons/Sketcher_Parabolic_Arc.svg + icons/Sketcher_Parabolic_Arc_Constr.svg icons/Sketcher_ProfilesHexagon1.svg icons/Sketcher_RectangularArray.svg icons/Sketcher_SelectConflictingConstraints.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Centre_Point.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Centre_Point.svg new file mode 100644 index 0000000000..cf22b46bdd --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Centre_Point.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Edge.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Edge.svg new file mode 100644 index 0000000000..562ab6f702 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Edge.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_End_Point.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_End_Point.svg new file mode 100644 index 0000000000..014e9ce614 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_End_Point.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Start_Point.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Start_Point.svg new file mode 100644 index 0000000000..f92298d82d --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_Parabolic_Arc_Start_Point.svg @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc.svg new file mode 100644 index 0000000000..70fedb6a83 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc_Constr.svg new file mode 100644 index 0000000000..7f99dbd3da --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Parabolic_Arc_Constr.svg @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 310ec161b5..1a3e38021a 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2014 Abdullah Tahiri * * * * This file is part of the FreeCAD CAx development system. * * * @@ -648,6 +648,10 @@ void TaskSketcherElements::slotElementsChanged(void) QIcon Sketcher_Element_ArcOfHyperbola_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_Centre_Point") ); QIcon Sketcher_Element_ArcOfHyperbola_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_Start_Point") ); QIcon Sketcher_Element_ArcOfHyperbola_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_End_Point") ); + QIcon Sketcher_Element_ArcOfParabola_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Edge") ); + QIcon Sketcher_Element_ArcOfParabola_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Centre_Point") ); + QIcon Sketcher_Element_ArcOfParabola_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Start_Point") ); + QIcon Sketcher_Element_ArcOfParabola_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_End_Point") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); assert(sketchView); @@ -682,7 +686,11 @@ void TaskSketcherElements::slotElementsChanged(void) (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge : (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint : (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint : none, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): @@ -705,6 +713,9 @@ void TaskSketcherElements::slotElementsChanged(void) type == Part::GeomArcOfHyperbola::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Hyperbolic Arc") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Hyperbolic Arc"))) : + type == Part::GeomArcOfParabola::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("Parabolic Arc") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("Parabolic Arc"))) : ( isNamingBoxChecked ? (tr("Other") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Other"))), @@ -889,6 +900,10 @@ void TaskSketcherElements::updateIcons(int element) QIcon Sketcher_Element_ArcOfHyperbola_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_Centre_Point") ); QIcon Sketcher_Element_ArcOfHyperbola_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_Start_Point") ); QIcon Sketcher_Element_ArcOfHyperbola_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Hyperbolic_Arc_End_Point") ); + QIcon Sketcher_Element_ArcOfParabola_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Edge") ); + QIcon Sketcher_Element_ArcOfParabola_MidPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Centre_Point") ); + QIcon Sketcher_Element_ArcOfParabola_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_Start_Point") ); + QIcon Sketcher_Element_ArcOfParabola_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_End_Point") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); for (int i=0;ilistWidgetElements->count(); i++) { @@ -914,7 +929,11 @@ void TaskSketcherElements::updateIcons(int element) (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfHyperbola_Edge : (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfHyperbola_StartingPoint : (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfHyperbola_EndPoint : - (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : + (type == Part::GeomArcOfHyperbola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfHyperbola_MidPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==0) ? Sketcher_Element_ArcOfParabola_Edge : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==1) ? Sketcher_Element_ArcOfParabola_StartingPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==2) ? Sketcher_Element_ArcOfParabola_EndPoint : + (type == Part::GeomArcOfParabola::getClassTypeId() && element==3) ? Sketcher_Element_ArcOfParabola_MidPoint : none); } } diff --git a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp index 59f6a58697..aba66511bd 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp @@ -233,6 +233,18 @@ void SketcherValidation::on_findButton_clicked() id.v = segm->getEndPoint(); vertexIds.push_back(id); } + else if (g->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *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 e07ef454f3..c3d16c3690 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -779,6 +779,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe geo->getTypeId() == Part::GeomCircle::getClassTypeId() || geo->getTypeId() == Part::GeomEllipse::getClassTypeId()|| geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()|| + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()|| geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { Gui::Command::openCommand("Drag Curve"); try { @@ -2264,6 +2265,84 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } } + } else if ((*it)->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + // Check if arc lies inside box selection + const Part::GeomArcOfParabola *aop = dynamic_cast(*it); + + pnt0 = aop->getStartPoint(); + pnt1 = aop->getEndPoint(); + pnt2 = aop->getCenter(); + + VertexId += 3; + + Plm.multVec(pnt0, pnt0); + Plm.multVec(pnt1, pnt1); + Plm.multVec(pnt2, pnt2); + pnt0 = proj(pnt0); + pnt1 = proj(pnt1); + pnt2 = proj(pnt2); + + bool pnt0Inside = polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y)); + if (pnt0Inside) { + std::stringstream ss; + ss << "Vertex" << VertexId - 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + + bool pnt1Inside = polygon.Contains(Base::Vector2d(pnt1.x, pnt1.y)); + if (pnt1Inside) { + std::stringstream ss; + ss << "Vertex" << VertexId; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + + if (polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y))) { + std::stringstream ss; + ss << "Vertex" << VertexId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + + if (pnt0Inside && pnt1Inside) { + double startangle, endangle; + + aop->getRange(startangle, endangle, /*emulateCCW=*/true); + + if (startangle > endangle) // if arc is reversed + std::swap(startangle, endangle); + + double range = endangle-startangle; + int countSegments = std::max(2, int(12.0 * range / (2 * M_PI))); + + float segment = float(range) / countSegments; + //In local coordinate system, value() of parabola is: + //P(U) = O + U*U/(4.*F)*XDir + U*YDir + // circumscribed polygon radius + float focal = float(aop->getFocal()) / cos(segment/2); + float phi = float(aop->getAngleXU()); + + bool bpolyInside = true; + pnt0 = aop->getCenter(); + float angle = float(startangle) + segment/2; + for (int i = 0; i < countSegments; ++i, angle += segment) { + pnt = Base::Vector3d(pnt0.x + angle * angle / 4 / focal * cos(phi) - angle * sin(phi), + pnt0.y + angle * angle / 4 / focal * sin(phi) + angle * cos(phi), + 0.f); + + Plm.multVec(pnt, pnt); + pnt = proj(pnt); + if (!polygon.Contains(Base::Vector2d(pnt.x, pnt.y))) { + bpolyInside = false; + break; + } + } + + if (bpolyInside) { + std::stringstream ss; + ss << "Edge" << GeoId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + } + } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { const Part::GeomBSplineCurve *spline = static_cast(*it); std::vector poles = spline->getPoles(); @@ -3224,6 +3303,39 @@ void ViewProviderSketch::draw(bool temp) gp_Pnt pnt = curve->Value(endangle); Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + Index.push_back(countSegments+1); + edit->CurvIdToGeoId.push_back(GeoId); + Points.push_back(start); + Points.push_back(end); + Points.push_back(center); + } + else if ((*it)->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = dynamic_cast(*it); + Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(aop->handle()); + + double startangle, endangle; + aop->getRange(startangle, endangle, /*emulateCCW=*/true); + if (startangle > endangle) // if arc is reversed + std::swap(startangle, endangle); + + double range = endangle-startangle; + int countSegments = std::max(6, int(50.0 * range / (2 * M_PI))); + double segment = range / countSegments; + + Base::Vector3d center = aop->getCenter(); + Base::Vector3d start = aop->getStartPoint(); + Base::Vector3d end = aop->getEndPoint(); + + for (int i=0; i < countSegments; i++) { + gp_Pnt pnt = curve->Value(startangle); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + startangle += segment; + } + + // end point + gp_Pnt pnt = curve->Value(endangle); + Coords.push_back(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z())); + Index.push_back(countSegments+1); edit->CurvIdToGeoId.push_back(GeoId); Points.push_back(start); @@ -3524,7 +3636,16 @@ Restart: angle1 = atan2(majdir.y, majdir.x); angle1plus = (startangle + endangle)/2; midpos1 = aoh->getCenter(); - }else + } else if (geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = dynamic_cast(geo1); + r1a = aop->getFocal(); + double startangle, endangle; + aop->getRange(startangle, endangle, /*emulateCCW=*/true); + Base::Vector3d majdir = - aop->getXAxisDir(); + angle1 = atan2(majdir.y, majdir.x); + angle1plus = (startangle + endangle)/2; + midpos1 = aop->getFocus(); + } else break; if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { @@ -3567,6 +3688,15 @@ Restart: angle2 = atan2(majdir.y, majdir.x); angle2plus = (startangle + endangle)/2; midpos2 = aoh->getCenter(); + } else if (geo2->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = dynamic_cast(geo2); + r2a = aop->getFocal(); + double startangle, endangle; + aop->getRange(startangle, endangle, /*emulateCCW=*/true); + Base::Vector3d majdir = -aop->getXAxisDir(); + angle2 = atan2(majdir.y, majdir.x); + angle2plus = (startangle + endangle)/2; + midpos2 = aop->getFocus(); } else break; diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index b5f56ac5d8..42928aac8e 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -140,7 +140,8 @@ inline void SketcherAddWorkspaceArcs(Gui::MenuItem& geom){ << "Sketcher_CreateEllipseByCenter" << "Sketcher_CreateEllipseBy3Points" << "Sketcher_CreateArcOfEllipse" - << "Sketcher_CreateArcOfHyperbola"; + << "Sketcher_CreateArcOfHyperbola" + << "Sketcher_CreateArcOfParabola"; } template <> inline void SketcherAddWorkspaceArcs(Gui::ToolBarItem& geom){