diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index bbac3a557..eb1e2e62b 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -81,6 +83,7 @@ void Sketch::clear(void) Circles.clear(); Ellipses.clear(); ArcsOfEllipse.clear(); + ArcsOfHyperbola.clear(); // deleting the doubles allocated with new for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it) @@ -172,6 +175,8 @@ const char* nameByType(Sketch::GeoType type) return "ellipse"; case Sketch::ArcOfEllipse: return "arcofellipse"; + case Sketch::ArcOfHyperbola: + return "arcofhyperbola"; case Sketch::None: default: return "unknown"; @@ -206,6 +211,10 @@ int Sketch::addGeometry(const Part::Geometry *geo, bool fixed) const GeomArcOfEllipse *aoe = static_cast(geo); // create the definition struct for that geom return addArcOfEllipse(*aoe, fixed); + } else if (geo->getTypeId() == GeomArcOfHyperbola::getClassTypeId()) { // add an arc of hyperbola + const GeomArcOfHyperbola *aoh = dynamic_cast(geo); + // create the definition struct for that geom + return addArcOfHyperbola(*aoh, fixed); } else { throw Base::TypeError("Sketch::addGeometry(): Unknown or unsupported type added to a sketch"); } @@ -377,8 +386,6 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed) return Geoms.size()-1; } - - int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool fixed) { std::vector ¶ms = fixed ? FixParameters : Parameters; @@ -435,8 +442,7 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f //Points.push_back(f1); - - // add the radius parameters + // add the radius parameters params.push_back(new double(radmin)); double *rmin = params[params.size()-1]; params.push_back(new double(startAngle)); @@ -444,8 +450,6 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f params.push_back(new double(endAngle)); double *a2 = params[params.size()-1]; - - // set the arc for later constraints GCS::ArcOfEllipse a; a.start = p1; @@ -470,6 +474,92 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f return Geoms.size()-1; } +int Sketch::addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, bool fixed) +{ + std::vector ¶ms = fixed ? FixParameters : Parameters; + + // create our own copy + GeomArcOfHyperbola *aoh = static_cast(hyperbolaSegment.clone()); + // create the definition struct for that geom + GeoDef def; + def.geo = aoh; + def.type = ArcOfHyperbola; + + Base::Vector3d center = aoh->getCenter(); + Base::Vector3d startPnt = aoh->getStartPoint(); + Base::Vector3d endPnt = aoh->getEndPoint(); + double radmaj = aoh->getMajorRadius(); + double radmin = aoh->getMinorRadius(); + double phi = aoh->getAngleXU(); + + double dist_C_F = sqrt(radmaj*radmaj+radmin*radmin); + // solver parameters + Base::Vector3d focus1 = center+dist_C_F*Vector3d(cos(phi), sin(phi),0); //+x + + double startAngle, endAngle; + aoh->getRange(startAngle, endAngle); + + GCS::Point p1, p2, p3; + + 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(center.x)); + params.push_back(new double(center.y)); + p3.x = params[params.size()-2]; + p3.y = params[params.size()-1]; + + params.push_back(new double(focus1.x)); + params.push_back(new double(focus1.y)); + double *f1X = params[params.size()-2]; + double *f1Y = 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(radmaj)); + double *rmaj = params[params.size()-1]; + 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::ArcOfHyperbola a; + a.start = p1; + a.end = p2; + a.center = p3; + a.focus.x = f1X; + a.focus.y = f1Y; + a.radmaj = rmaj; + a.startAngle = a1; + a.endAngle = a2; + def.index = ArcsOfHyperbola.size(); + ArcsOfHyperbola.push_back(a); + + // store complete set + Geoms.push_back(def); + + // arcs require an ArcRules constraint for the end points + /*if (!fixed) + GCSsys.addConstraintArcOfHyperbolaRules(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; @@ -607,8 +697,10 @@ Py::Tuple Sketch::getPyGeometry(void) const } else if (it->type == ArcOfEllipse) { GeomArcOfEllipse *ellipse = static_cast(it->geo->clone()); tuple[i] = Py::asObject(new ArcOfEllipsePy(ellipse)); - } - else { + } else if (it->type == ArcOfHyperbola) { + GeomArcOfHyperbola *aoh = dynamic_cast(it->geo->clone()); + tuple[i] = Py::asObject(new ArcOfHyperbolaPy(aoh)); + } else { // not implemented type in the sketch! } } @@ -2069,6 +2161,30 @@ bool Sketch::updateGeometry() ellipse->setMajorRadius(radmaj); } ellipse->setMajorAxisDir(fd); + } else if (it->type == ArcOfHyperbola) { + GCS::ArcOfHyperbola &myArc = ArcsOfHyperbola[it->index]; + + GeomArcOfHyperbola *aoh = dynamic_cast(it->geo); + + Base::Vector3d center = Vector3d(*Points[it->midPointId].x, *Points[it->midPointId].y, 0.0); + Base::Vector3d f1 = Vector3d(*myArc.focus.x, *myArc.focus.y, 0.0); + double radmaj = *myArc.radmaj; + + Base::Vector3d fd=f1-center; + double radmin = sqrt(fd*fd-radmaj*radmaj); + + double phi = atan2(fd.y,fd.x); + + aoh->setCenter(center); + if ( radmaj >= aoh->getMinorRadius() ){ + aoh->setMajorRadius(radmaj); + aoh->setMinorRadius(radmin); + } else { + aoh->setMinorRadius(radmin); + aoh->setMajorRadius(radmaj); + } + aoh->setAngleXU(phi); + aoh->setRange(*myArc.startAngle, *myArc.endAngle); } } catch (Base::Exception e) { Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n", @@ -2335,6 +2451,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) p0.y = &MoveParameters[1]; *p0.x = *center.x; *p0.y = *center.y; + GCSsys.addConstraintP2PCoincident(p0,center,-1); } } else if (Geoms[geoId].type == ArcOfEllipse) { @@ -2348,6 +2465,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) *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 @@ -2358,6 +2476,7 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) p0.y = &MoveParameters[1]; *p0.x = *p.x; *p0.y = *p.y; + GCSsys.addConstraintP2PCoincident(p0,p,-1); } @@ -2365,9 +2484,46 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) 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 == 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 == Arc) { GCS::Point ¢er = Points[Geoms[geoId].midPointId]; @@ -2466,7 +2622,12 @@ 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 == ArcOfHyperbola) { + 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 6d97df44f..f245bd915 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -128,6 +128,8 @@ public: int addEllipse(const Part::GeomEllipse &ellipse, bool fixed=false); /// add an arc of ellipse int addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool fixed=false); + /// add an arc of hyperbola + int addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, bool fixed=false); //@} @@ -317,7 +319,7 @@ public: //icstr should be the value returned by addXXXXConstraint //see more info in respective function in GCS. double calculateConstraintError(int icstr) { return GCSsys.calculateConstraintErrorByTag(icstr);} - + /// Returns the size of the Geometry int getGeometrySize(void) const {return Geoms.size();} @@ -328,7 +330,8 @@ public: Arc = 3, // 3 Points(start,end,mid), (4)+5 Parameters((x1,y1,x2,y2),x,y,r,a1,a2) 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 + ArcOfEllipse = 6, + ArcOfHyperbola = 7 }; float SolveTime; @@ -375,6 +378,7 @@ protected: std::vector Circles; std::vector Ellipses; std::vector ArcsOfEllipse; + std::vector ArcsOfHyperbola; bool isInitMove; bool isFine; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 8b027a848..9466ba520 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -32,6 +32,7 @@ # include # include # include +# include # include # include # include @@ -39,6 +40,7 @@ # include # include # include +# include # include # include # include @@ -494,6 +496,14 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const return aoc->getEndPoint(/*emulateCCW=*/true); else if (PosId == mid) return aoc->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *aoh = dynamic_cast(geo); + if (PosId == start) + return aoh->getStartPoint(); + else if (PosId == end) + return aoh->getEndPoint(); + else if (PosId == mid) + return aoh->getCenter(); } return Base::Vector3d(); @@ -1716,6 +1726,176 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) } } } + + } else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *aoh = dynamic_cast(geo); + Base::Vector3d center = aoh->getCenter(); + double startAngle, endAngle; + aoh->getRange(startAngle, endAngle); + double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1 + double arcLength = (endAngle - startAngle)*dir; + double theta0 = Base::fmod( + atan2(-aoh->getMajorRadius()*((point.x-center.x)*sin(aoh->getAngleXU())-(point.y-center.y)*cos(aoh->getAngleXU())), + aoh->getMinorRadius()*((point.x-center.x)*cos(aoh->getAngleXU())+(point.y-center.y)*sin(aoh->getAngleXU())) + )- startAngle, 2.f*M_PI); // x0 + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod( + atan2(-aoh->getMajorRadius()*((point1.x-center.x)*sin(aoh->getAngleXU())-(point1.y-center.y)*cos(aoh->getAngleXU())), + aoh->getMinorRadius()*((point1.x-center.x)*cos(aoh->getAngleXU())+(point1.y-center.y)*sin(aoh->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x1 + double theta2 = Base::fmod( + atan2(-aoh->getMajorRadius()*((point2.x-center.x)*sin(aoh->getAngleXU())-(point2.y-center.y)*cos(aoh->getAngleXU())), + aoh->getMinorRadius()*((point2.x-center.x)*cos(aoh->getAngleXU())+(point2.y-center.y)*sin(aoh->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x2 + + if (theta1 > theta2) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 >= 0.001*arcLength && theta2 <= 0.999*arcLength) { + // Trim Point between intersection points + if (theta1 < theta0 && theta2 > theta0) { + int newGeoId = addGeometry(geo); + // go through all constraints and replace the point (GeoId,end) with (newGeoId,end) + transferConstraints(GeoId, end, newGeoId, end); + + Part::GeomArcOfHyperbola *aoh1 = dynamic_cast(geomlist[GeoId]); + Part::GeomArcOfHyperbola *aoh2 = dynamic_cast(geomlist[newGeoId]); + aoh1->setRange(startAngle, startAngle + theta1); + aoh2->setRange(startAngle + theta2, endAngle); + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + + // Build Constraints associated with new pair of arcs + newConstr->Type = Sketcher::Equal; + newConstr->First = GeoId; + newConstr->Second = newGeoId; + addConstraint(newConstr); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && + (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if (secondPos2 == Sketcher::none && + (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + newConstr->Type = constrType2; + newConstr->First = newGeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + newConstr->Type = Sketcher::Coincident; + newConstr->First = GeoId; + newConstr->FirstPos = Sketcher::mid; + newConstr->Second = newGeoId; + newConstr->SecondPos = Sketcher::mid; + addConstraint(newConstr); + + delete newConstr; + + return 0; + } else + return -1; + } else if (theta1 < 0.001*arcLength) { // drop the second intersection point + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } else if (theta2 > 0.999*arcLength) { + } else + return -1; + } + + if (GeoId1 >= 0) { + + ConstraintType constrType = Sketcher::PointOnObject; + PointPos secondPos = Sketcher::none; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if ((constr->First == GeoId1 && constr->Second == GeoId)) { + constrType = Sketcher::Coincident; + secondPos = constr->FirstPos; + delConstraintOnPoint(GeoId1, constr->FirstPos, false); + break; + } + } + + double theta1 = Base::fmod( + atan2(-aoh->getMajorRadius()*((point1.x-center.x)*sin(aoh->getAngleXU())-(point1.y-center.y)*cos(aoh->getAngleXU())), + aoh->getMinorRadius()*((point1.x-center.x)*cos(aoh->getAngleXU())+(point1.y-center.y)*sin(aoh->getAngleXU())) + )- startAngle, 2.f*M_PI) * dir; // x1 + + if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) { + if (theta1 > theta0) { // trim arc start + delConstraintOnPoint(GeoId, start, false); + Part::GeomArcOfHyperbola *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle + theta1, endAngle); + // constrain the trimming point on the corresponding geometry + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + return 0; + } + else { // trim arc end + delConstraintOnPoint(GeoId, end, false); + Part::GeomArcOfHyperbola *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle, startAngle + theta1); + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + return 0; + } + } + } } return -1; @@ -3341,6 +3521,34 @@ void SketchObject::rebuildExternalGeometry(void) ExternalGeo.push_back(circle); } else { throw Base::Exception("BSpline: Not yet supported geometry for external geometry"); + } + } else if (projCurve.GetType() == GeomAbs_Hyperbola) { + gp_Hypr e = projCurve.Hyperbola(); + 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::GeomHyperbola* hyperbola = new Part::GeomHyperbola(); + hyperbola->setMajorRadius(e.MajorRadius()); + hyperbola->setMinorRadius(e.MinorRadius()); + hyperbola->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + hyperbola->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal)); + hyperbola->Construction = true; + ExternalGeo.push_back(hyperbola); + } + else { + Part::GeomArcOfHyperbola* aoh = new Part::GeomArcOfHyperbola(); + Handle_Geom_Curve curve = new Geom_Hyperbola(e); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(curve, projCurve.FirstParameter(), + projCurve.LastParameter()); + aoh->setHandle(tCurve); + aoh->Construction = true; + ExternalGeo.push_back(aoh); } } else if (projCurve.GetType() == GeomAbs_Ellipse) { @@ -3447,6 +3655,13 @@ void SketchObject::rebuildVertexIndex(void) VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::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); + } else if ((*it)->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { VertexId2GeoId.push_back(i); VertexId2PosId.push_back(start); VertexId2GeoId.push_back(i); diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index f7824e7aa..793f54cf1 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -112,6 +112,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { ret = this->getSketchObjectPtr()->addGeometry(geo,isConstruction); } @@ -163,6 +164,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { geoList.push_back(geo); } diff --git a/src/Mod/Sketcher/App/planegcs/Geo.cpp b/src/Mod/Sketcher/App/planegcs/Geo.cpp index ac774cab8..adca4308f 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.cpp +++ b/src/Mod/Sketcher/App/planegcs/Geo.cpp @@ -301,5 +301,59 @@ ArcOfEllipse* ArcOfEllipse::Copy() return crv; } +//---------------arc of hyperbola +int ArcOfHyperbola::PushOwnParams(VEC_pD &pvec) +{ + int cnt=0; + // hyperbola + pvec.push_back(center.x); cnt++; + pvec.push_back(center.y); cnt++; + pvec.push_back(focus.x); cnt++; + pvec.push_back(focus.y); cnt++; + pvec.push_back(radmaj); cnt++; + // arc + 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 ArcOfHyperbola::ReconstructOnNewPvec(VEC_pD &pvec, int &cnt) +{ + // hyperbola + center.x=pvec[cnt]; cnt++; + center.y=pvec[cnt]; cnt++; + focus.x=pvec[cnt]; cnt++; + focus.y=pvec[cnt]; cnt++; + radmaj=pvec[cnt]; cnt++; + //arc + 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++; +} +ArcOfHyperbola* ArcOfHyperbola::Copy() +{ + ArcOfHyperbola* crv = new ArcOfHyperbola(*this); + return crv; +} + +DeriVector2 ArcOfHyperbola::CalculateNormal(Point &p, double* derivparam) +{ + //fill some vectors in + DeriVector2 cv (center, derivparam); + DeriVector2 fv (focus, derivparam); + DeriVector2 pv (p, derivparam); + + DeriVector2 ret = fv; + + return ret; +} + }//namespace GCS diff --git a/src/Mod/Sketcher/App/planegcs/Geo.h b/src/Mod/Sketcher/App/planegcs/Geo.h index 9e03771ba..d3de7ea8a 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.h +++ b/src/Mod/Sketcher/App/planegcs/Geo.h @@ -184,6 +184,27 @@ namespace GCS virtual ArcOfEllipse* Copy(); }; + class ArcOfHyperbola: public Curve + { + public: + ArcOfHyperbola(){startAngle=0;endAngle=0;radmaj = 0;} + virtual ~ArcOfHyperbola(){} + // parameters + double *startAngle; + double *endAngle; + double *radmaj; + Point start; + Point end; + Point center; + Point focus; + // interface helpers + virtual int PushOwnParams(VEC_pD &pvec); + virtual void ReconstructOnNewPvec (VEC_pD &pvec, int &cnt); + virtual ArcOfHyperbola* Copy(); + // Curve interface + DeriVector2 CalculateNormal(Point &p, double* derivparam = 0); + }; + } //namespace GCS #endif // PLANEGCS_GEO_H diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index a2749e9e2..1e3eff4ec 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -3385,6 +3385,398 @@ bool CmdSketcherCreateArcOfEllipse::isActive(void) return isCreateGeoActive(getActiveGuiDocument()); } +/* XPM */ +static const char *cursor_createarcofhyperbola[]={ +"32 32 3 1", +"+ c white", +"# c red", +". c None", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"................................", +"+++++...+++++...................", +"................................", +"......+.........................", +"......+.........................", +"......+................##.......", +"......+..............##.........", +"......+............##...........", +"......+...........##............", +"................##..............", +"...............##...............", +"..............##................", +".............###................", +"..###.......##..................", +".#.#.......##...................", +"..###......##...................", +"..........##....................", +".........##.....................", +"........##......................", +"........##......................", +"........##......................", +"........#.....####..............", +"........######..................", +"................................", +"................................", +"................................", +"................................"}; + +class DrawSketchHandlerArcOfHyperbola : public DrawSketchHandler +{ +public: + DrawSketchHandlerArcOfHyperbola() : Mode(STATUS_SEEK_First),EditCurve(34){} + virtual ~DrawSketchHandlerArcOfHyperbola(){} + /// 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_createarcofhyperbola),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) { + double rx0 = onSketchPos.fX - centerPoint.fX; + double ry0 = onSketchPos.fY - centerPoint.fY; + + EditCurve[1]= onSketchPos; + + // Display radius for user + float radius = (onSketchPos - centerPoint).Length(); + + SbString text; + text.sprintf(" (%.1fR,%.1fR)", radius,radius); + setPositionText(onSketchPos, text); + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr2); + return; + } + } + else if (Mode==STATUS_SEEK_Third) { + // angle between the major axis of the hyperbola and the X axis + double a = (axisPoint-centerPoint).Length(); + double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); + + // This is the angle at cursor point + double angleatpoint = acosh(((onSketchPos.fX-centerPoint.fX)*cos(phi)+(onSketchPos.fY-centerPoint.fY)*sin(phi))/a); + double b=(onSketchPos.fY-centerPoint.fY-a*cosh(angleatpoint)*sin(phi))/(sinh(angleatpoint)*cos(phi)); + + if(!boost::math::isnan(b)){ + for (int i=15; i >= -15; i--) { + // P(U) = O + MajRad*Cosh(U)*XDir + MinRad*Sinh(U)*YDir + //double angle = i*M_PI/16.0; + double angle=i*angleatpoint/15; + double rx = a * cosh(angle) * cos(phi) - b * sinh(angle) * sin(phi); + double ry = a * cosh(angle) * sin(phi) + b * sinh(angle) * cos(phi); + EditCurve[15+i] = Base::Vector2D(centerPoint.fX + rx, centerPoint.fY + ry); + } + + // Display radius for user + SbString text; + text.sprintf(" (%.1fR,%.1fR)", a, b); + setPositionText(onSketchPos, text); + } + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr3); + return; + } + } + else if (Mode==STATUS_SEEK_Fourth) { + // angle between the major axis of the hyperbola and the X axis + double a = (axisPoint-centerPoint).Length(); + double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); + + // This is the angle at cursor point + double angleatstartingpoint = acosh(((startingPoint.fX-centerPoint.fX)*cos(phi)+(startingPoint.fY-centerPoint.fY)*sin(phi))/a); + double b=(startingPoint.fY-centerPoint.fY-a*cosh(angleatstartingpoint)*sin(phi))/(sinh(angleatstartingpoint)*cos(phi)); + + double startAngle = angleatstartingpoint; + + //double angleatpoint = acosh(((onSketchPos.fX-centerPoint.fX)*cos(phi)+(onSketchPos.fY-centerPoint.fY)*sin(phi))/a); + + double angleatpoint = atanh( (((onSketchPos.fY-centerPoint.fY)*cos(phi)-(onSketchPos.fX-centerPoint.fX)*sin(phi))*a) / + (((onSketchPos.fX-centerPoint.fX)*cos(phi)+(onSketchPos.fY-centerPoint.fY)*sin(phi))*b) ); + + /*double angle1 = angleatpoint - startAngle; + + double angle2 = angle1 + (angle1 < 0. ? 2 : -2) * M_PI ; + arcAngle = abs(angle1-arcAngle) < abs(angle2-arcAngle) ? angle1 : angle2;*/ + + arcAngle = angleatpoint - startAngle; + + //if(!boost::math::isnan(angle1) && !boost::math::isnan(angle2)){ + if(!boost::math::isnan(arcAngle)){ + for (int i=0; i < 33; i++) { + // P(U) = O + MajRad*Cosh(U)*XDir + MinRad*Sinh(U)*YDir + //double angle=i*angleatpoint/16; + double angle = startAngle+i*arcAngle/32.0; + double rx = a * cosh(angle) * cos(phi) - b * sinh(angle) * sin(phi); + double ry = a * cosh(angle) * sin(phi) + b * sinh(angle) * cos(phi); + EditCurve[i] = Base::Vector2D(centerPoint.fX + rx, centerPoint.fY + ry); + } + + // Display radius for user + SbString text; + text.sprintf(" (%.1fR,%.1fR)", a, b); + setPositionText(onSketchPos, text); + } + else + { + arcAngle=0.; + } + + sketchgui->drawEdit(EditCurve); + if (seekAutoConstraint(sugConstr4, onSketchPos, Base::Vector2D(0.f,0.f), + AutoConstraint::CURVE)) { + renderSuggestConstraintsCursor(sugConstr4); + return; + } + } + + + + applyCursor(); + } + + virtual bool pressButton(Base::Vector2D onSketchPos) + { + if (Mode==STATUS_SEEK_First){ + EditCurve[0] = onSketchPos; + centerPoint = 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(); + + + // angle between the major axis of the hyperbola and the X axis + double a = (axisPoint-centerPoint).Length(); + double phi = atan2(axisPoint.fY-centerPoint.fY,axisPoint.fX-centerPoint.fX); + + // This is the angle at cursor point + double angleatstartingpoint = acosh(((startingPoint.fX-centerPoint.fX)*cos(phi)+(startingPoint.fY-centerPoint.fY)*sin(phi))/a); + double b=(startingPoint.fY-centerPoint.fY-a*cosh(angleatstartingpoint)*sin(phi))/(sinh(angleatstartingpoint)*cos(phi)); + + double startAngle = angleatstartingpoint; + + //double angleatpoint = acosh(((onSketchPos.fX-centerPoint.fX)*cos(phi)+(onSketchPos.fY-centerPoint.fY)*sin(phi))/a); + + double endAngle = atanh( (((endPoint.fY-centerPoint.fY)*cos(phi)-(endPoint.fX-centerPoint.fX)*sin(phi))*a) / + (((endPoint.fX-centerPoint.fX)*cos(phi)+(endPoint.fY-centerPoint.fY)*sin(phi))*b) ); + + + + Base::Vector2D majAxisDir,minAxisDir,minAxisPoint,majAxisPoint; + // We always create a CCW ellipse, because we want our XY reference system to be in the +X +Y direction + // Our normal will then always be in the +Z axis (local +Z axis of the sketcher) + + if(a>b) + { + // force second semidiameter to be perpendicular to first semidiamater + majAxisDir = axisPoint - centerPoint; + Base::Vector2D perp(-majAxisDir.fY,majAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + minAxisPoint = centerPoint+perp; + majAxisPoint = centerPoint+majAxisDir; + } + else { + // force second semidiameter to be perpendicular to first semidiamater + minAxisDir = axisPoint - centerPoint; + Base::Vector2D perp(minAxisDir.fY,-minAxisDir.fX); + perp.Normalize(); + perp.Scale(abs(b)); + majAxisPoint = centerPoint+perp; + minAxisPoint = centerPoint+minAxisDir; + endAngle += M_PI/2; + startAngle += M_PI/2; + } + + /*startAngle=M_PI/4; + endAngle=-M_PI/4;*/ + /*majAxisPoint.fX=20; + majAxisPoint.fY=0; + minAxisPoint.fX=0; + minAxisPoint.fY=10; + centerPoint.fX=0; + centerPoint.fY=0;*/ + + + Base::Vector3d center = Base::Vector3d(centerPoint.fX,centerPoint.fY,0); + + Base::Vector3d majorpositiveend = center + a * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d majornegativeend = center - a * Base::Vector3d(cos(phi),sin(phi),0); + Base::Vector3d minorpositiveend = center + b * Base::Vector3d(-sin(phi),cos(phi),0); + Base::Vector3d minornegativeend = center - b * Base::Vector3d(-sin(phi),cos(phi),0); + + double cf = sqrt( abs(a*a - b*b) );//using abs, avoided using different formula for a>b/agetObject()->getNameInDocument(), + majAxisPoint.fX, majAxisPoint.fY, + minAxisPoint.fX, minAxisPoint.fY, + centerPoint.fX, centerPoint.fY, + startAngle, endAngle); + /* + currentgeoid++; + + try { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + sketchgui->getObject()->getNameInDocument(), + majorpositiveend.x,majorpositiveend.y,majornegativeend.x,majornegativeend.y); // create line for major axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+1); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMajorDiameter',%d,%d)) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+1,currentgeoid); // constrain major axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Line(App.Vector(%f,%f,0),App.Vector(%f,%f,0)))", + sketchgui->getObject()->getNameInDocument(), + minorpositiveend.x,minorpositiveend.y,minornegativeend.x,minornegativeend.y); // create line for minor axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.toggleConstruction(%d) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+2); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseMinorDiameter',%d,%d)) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+2,currentgeoid); // constrain minor axis + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + sketchgui->getObject()->getNameInDocument(), + focus1P.x,focus1P.y); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus1',%d,%d,%d)) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+3,Sketcher::start,currentgeoid); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + sketchgui->getObject()->getNameInDocument(), + focus2P.x,focus2P.y); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('InternalAlignment:EllipseFocus2',%d,%d,%d)) ", + sketchgui->getObject()->getNameInDocument(),currentgeoid+4,Sketcher::start,currentgeoid); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + Gui::Command::updateActive(); + return false; + } + */ + Gui::Command::commitCommand(); + Gui::Command::updateActive(); + + // add auto constraints for the center point + if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::mid); + sugConstr1.clear(); + } + + // add suggested constraints for circumference + if (sugConstr2.size() > 0) { + //createAutoConstraints(sugConstr2, getHighestCurveIndex(), Sketcher::none); + sugConstr2.clear(); + } + + EditCurve.clear(); + sketchgui->drawEdit(EditCurve); + sketchgui->purgeHandler(); // no code after this line, Handler get deleted in ViewProvider + } + return true; + } +protected: + SelectMode Mode; + std::vector EditCurve; + Base::Vector2D centerPoint, axisPoint, startingPoint, endPoint; + double rx, ry, startAngle, endAngle, arcAngle, arcAngle_t; + std::vector sugConstr1, sugConstr2, sugConstr3, sugConstr4; + +}; + +DEF_STD_CMD_A(CmdSketcherCreateArcOfHyperbola); + +CmdSketcherCreateArcOfHyperbola::CmdSketcherCreateArcOfHyperbola() + : Command("Sketcher_CreateArcOfHyperbola") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create an arc of hyperbola"); + sToolTipText = QT_TR_NOOP("Create an arc of hyperbola in the sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_hyperbolic_Arc"; + eType = ForEdit; +} + +void CmdSketcherCreateArcOfHyperbola::activated(int iMsg) +{ + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerArcOfHyperbola() ); +} + +bool CmdSketcherCreateArcOfHyperbola::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + /// @brief Macro that declares a new sketcher command class 'CmdSketcherCompCreateEllipse' DEF_STD_CMD_ACLU(CmdSketcherCompCreateConic); @@ -3415,6 +3807,8 @@ void CmdSketcherCompCreateConic::activated(int iMsg) ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerEllipse(iMsg)); } else if (iMsg == 2) { ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerArcOfEllipse()); + } else if (iMsg == 3) { + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerArcOfHyperbola()); } else { return; } @@ -3442,6 +3836,9 @@ Gui::Action * CmdSketcherCompCreateConic::createAction(void) QAction* arcofellipse = pcAction->addAction(QString()); arcofellipse->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Elliptical_Arc")); + + QAction* arcofhyperbola = pcAction->addAction(QString()); + arcofhyperbola->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Hyperbolic_Arc")); _pcAction = pcAction; languageChange(); @@ -3467,12 +3864,14 @@ void CmdSketcherCompCreateConic::updateAction(int mode) a[0]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateEllipse")); 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")); getAction()->setIcon(a[index]->icon()); break; case Construction: a[0]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateEllipse_Constr")); 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")); getAction()->setIcon(a[index]->icon()); break; } @@ -3499,6 +3898,10 @@ void CmdSketcherCompCreateConic::languageChange() arcofellipse->setText(QApplication::translate("CmdSketcherCompCreateConic","Arc of ellipse by center, major radius, endpoints")); arcofellipse->setToolTip(QApplication::translate("Sketcher_CreateArcOfEllipse","Create an arc of ellipse by its center, major radius, endpoints")); arcofellipse->setStatusTip(QApplication::translate("Sketcher_CreateArcOfEllipse","Create an arc of ellipse by its center, major radius, endpoints")); + QAction* arcofhyperbola = a[3]; + 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")); } bool CmdSketcherCompCreateConic::isActive(void) @@ -4767,6 +5170,7 @@ bool CmdSketcherExternal::isActive(void) return isCreateGeoActive(getActiveGuiDocument()); } + /* Create Slot =======================================================*/ /* XPM */ @@ -5570,6 +5974,7 @@ void CreateSketcherCommandsCreateGeo(void) rcCmdMgr.addCommand(new CmdSketcherCreateEllipseBy3Points()); rcCmdMgr.addCommand(new CmdSketcherCompCreateConic()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfEllipse()); + rcCmdMgr.addCommand(new CmdSketcherCreateArcOfHyperbola()); rcCmdMgr.addCommand(new CmdSketcherCreateLine()); rcCmdMgr.addCommand(new CmdSketcherCreatePolyline()); rcCmdMgr.addCommand(new CmdSketcherCreateRectangle()); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp index dea9357ba..904f1dd72 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp @@ -221,6 +221,18 @@ void SketcherValidation::on_findButton_clicked() id.v = segm->getEndPoint(/*emulateCCW=*/true); vertexIds.push_back(id); } + else if (g->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *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 1c7a9b31a..a101ab5c8 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -768,7 +768,8 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || geo->getTypeId() == Part::GeomCircle::getClassTypeId() || geo->getTypeId() == Part::GeomEllipse::getClassTypeId()|| - geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()|| + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { Gui::Command::openCommand("Drag Curve"); try { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.movePoint(%i,%i,App.Vector(%f,%f,0),%i)" @@ -2099,7 +2100,6 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); } } - } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { // Check if arc lies inside box selection const Part::GeomArcOfEllipse *aoe = static_cast(*it); @@ -2107,6 +2107,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & pnt0 = aoe->getStartPoint(/*emulateCCW=*/true); pnt1 = aoe->getEndPoint(/*emulateCCW=*/true); pnt2 = aoe->getCenter(); + VertexId += 3; Plm.multVec(pnt0, pnt0); @@ -2139,11 +2140,13 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & if (pnt0Inside && pnt1Inside) { double startangle, endangle; aoe->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))); + double segment = (range) / countSegments; // circumscribed polygon radius @@ -2157,6 +2160,85 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & double angle = (startangle) + segment/2; for (int i = 0; i < countSegments; ++i, angle += segment) { pnt = pnt0 + cos(angle)*a*majdir + sin(angle)*b*mindir; + + 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::GeomArcOfHyperbola::getClassTypeId()) { + // Check if arc lies inside box selection + const Part::GeomArcOfHyperbola *aoh = dynamic_cast(*it); + + pnt0 = aoh->getStartPoint(); + pnt1 = aoh->getEndPoint(); + pnt2 = aoh->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; + + aoh->getRange(startangle, endangle); + + 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; + + // circumscribed polygon radius + float a = float(aoh->getMajorRadius()) / cos(segment/2); + float b = float(aoh->getMinorRadius()) / cos(segment/2); + float phi = float(aoh->getAngleXU()); + + bool bpolyInside = true; + pnt0 = aoh->getCenter(); + float angle = float(startangle) + segment/2; + for (int i = 0; i < countSegments; ++i, angle += segment) { + pnt = Base::Vector3d(pnt0.x + a * cosh(angle) * cos(phi) - b * sinh(angle) * sin(phi), + pnt0.y + a * cosh(angle) * sin(phi) + b * sinh(angle) * cos(phi), + 0.f); + Plm.multVec(pnt, pnt); pnt = proj(pnt); if (!polygon.Contains(Base::Vector2d(pnt.x, pnt.y))) { @@ -3104,6 +3186,39 @@ void ViewProviderSketch::draw(bool temp) Points.push_back(end); Points.push_back(center); } + else if ((*it)->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *aoh = dynamic_cast(*it); + Handle_Geom_TrimmedCurve curve = Handle_Geom_TrimmedCurve::DownCast(aoh->handle()); + + double startangle, endangle; + aoh->getRange(startangle, endangle); + 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 = aoh->getCenter(); + Base::Vector3d start = aoh->getStartPoint(); + Base::Vector3d end = aoh->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); + Points.push_back(end); + Points.push_back(center); + } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline const Part::GeomBSplineCurve *spline = static_cast(*it); Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle()); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index e048ebc30..b5f56ac5d 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -139,7 +139,8 @@ inline void SketcherAddWorkspaceArcs(Gui::MenuItem& geom){ << "Sketcher_Create3PointCircle" << "Sketcher_CreateEllipseByCenter" << "Sketcher_CreateEllipseBy3Points" - << "Sketcher_CreateArcOfEllipse"; + << "Sketcher_CreateArcOfEllipse" + << "Sketcher_CreateArcOfHyperbola"; } template <> inline void SketcherAddWorkspaceArcs(Gui::ToolBarItem& geom){