From b277620138eea91353850993e717021a9559df2c Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 4 Jan 2017 23:47:15 +0100 Subject: [PATCH 01/38] Part: GeomBSpline extension for basic BSPline Sketcher support ============================================================== 1) Basic set/get interface for poles, weights, knots and multiplicities 2) Introduction of GeomBoundedCurve class replicating OCC hierarchy. Why? To provide seamless start/end point interface for any bounded curve, i.e. Bezier, BSpline, Note: The ArcOfConic start/end point interface relies on GeomTrimmedCurve, and introduces CCW/CW correcting code which relies on Axis. Axis are introduced in GeomConic and are not part of GeomBounded. Note 2: In the future, it may be thought to make GeomArcOfConic (the equivalent of GeomTrimmedCurve) deriving from GeomBoundedCurve, as to fully replicate OCC hierarchy. GeomBoundedCurve defines the functions as virtual to allow seamless integration. --- src/Mod/Part/App/AppPart.cpp | 1 + src/Mod/Part/App/Geometry.cpp | 155 +++++++++++++++++++++++++++++++++- src/Mod/Part/App/Geometry.h | 27 +++++- 3 files changed, 179 insertions(+), 4 deletions(-) diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index bc4c86d7b..fa8392328 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -460,6 +460,7 @@ PyMODINIT_FUNC initPart() Part::Geometry ::init(); Part::GeomPoint ::init(); Part::GeomCurve ::init(); + Part::GeomBoundedCurve ::init(); Part::GeomBezierCurve ::init(); Part::GeomBSplineCurve ::init(); Part::GeomConic ::init(); diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 71d8843fb..ffa57ec42 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -421,10 +421,37 @@ bool GeomCurve::closestParameterToBasicCurve(const Base::Vector3d& point, double } } +// ------------------------------------------------- +TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomBoundedCurve, Part::GeomCurve) + +GeomBoundedCurve::GeomBoundedCurve() +{ +} + +GeomBoundedCurve::~GeomBoundedCurve() +{ +} + +Base::Vector3d GeomBoundedCurve::getStartPoint() const +{ + Handle_Geom_BoundedCurve curve = Handle_Geom_BoundedCurve::DownCast(handle()); + gp_Pnt pnt = curve->StartPoint(); + + return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()); +} + +Base::Vector3d GeomBoundedCurve::getEndPoint() const +{ + Handle_Geom_BoundedCurve curve = Handle_Geom_BoundedCurve::DownCast(handle()); + gp_Pnt pnt = curve->EndPoint(); + + return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()); +} + // ------------------------------------------------- -TYPESYSTEM_SOURCE(Part::GeomBezierCurve,Part::GeomCurve) +TYPESYSTEM_SOURCE(Part::GeomBezierCurve,Part::GeomBoundedCurve) GeomBezierCurve::GeomBezierCurve() { @@ -473,7 +500,7 @@ PyObject *GeomBezierCurve::getPyObject(void) // ------------------------------------------------- -TYPESYSTEM_SOURCE(Part::GeomBSplineCurve,Part::GeomCurve) +TYPESYSTEM_SOURCE(Part::GeomBSplineCurve,Part::GeomBoundedCurve) GeomBSplineCurve::GeomBSplineCurve() { @@ -538,6 +565,27 @@ void GeomBSplineCurve::setPole(int index, const Base::Vector3d& pole, double wei } } +void GeomBSplineCurve::setPoles(const std::vector& poles, const std::vector& weights) +{ + Standard_Integer index=0; + + std::vector::const_iterator it1; + std::vector::const_iterator it2; + + for(it1 = poles.begin(), it2 = weights.begin(); it1 != poles.end() && it2 != weights.end(); ++it1, ++it2, index++){ + setPole(index, (*it1), (*it2) ); + } +} + +void GeomBSplineCurve::setPoles(const std::vector& poles) +{ + Standard_Integer index=0; + + for(std::vector::const_iterator it1 = poles.begin(); it1 != poles.end(); ++it1, index++){ + setPole(index, (*it1)); + } +} + std::vector GeomBSplineCurve::getPoles() const { std::vector poles; @@ -552,6 +600,109 @@ std::vector GeomBSplineCurve::getPoles() const return poles; } +std::vector GeomBSplineCurve::getWeights() const +{ + std::vector weights; + weights.reserve(myCurve->NbPoles()); + TColStd_Array1OfReal w(1,myCurve->NbPoles()); + myCurve->Weights(w); + + for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) { + const Standard_Real& real = w(i); + weights.push_back(real); + } + return weights; +} + + +void GeomBSplineCurve::setWeights(const std::vector& weights) +{ + try { + Standard_Integer index=0; + + for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it, index++){ + myCurve->SetWeight(index,(*it)); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + std::cout << e->GetMessageString() << std::endl; + } +} + +void GeomBSplineCurve::setKnot(int index, const double val, int mult) +{ + try { + if (mult < 0) + myCurve->SetKnot(index+1, val); + else + myCurve->SetKnot(index+1, val, mult); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + std::cout << e->GetMessageString() << std::endl; + } +} + +void GeomBSplineCurve::setKnots(const std::vector& knots) +{ + Standard_Integer index=0; + + for(std::vector::const_iterator it1 = knots.begin(); it1 != knots.end(); ++it1, index++){ + setKnot(index, (*it1)); + } +} + +void GeomBSplineCurve::setKnots(const std::vector& knots, const std::vector multiplicities) +{ + Standard_Integer index=0; + + std::vector::const_iterator it1; + std::vector::const_iterator it2; + + for(it1 = knots.begin(), it2 = multiplicities.begin(); it1 != knots.end() && it2 != multiplicities.end(); ++it1, ++it2, index++){ + setKnot(index, (*it1), (*it2) ); + } +} + +std::vector GeomBSplineCurve::getKnots() const +{ + std::vector knots; + knots.reserve(myCurve->NbKnots()); + TColStd_Array1OfReal k(1,myCurve->NbKnots()); + myCurve->Knots(k); + + for (Standard_Integer i=k.Lower(); i<=k.Upper(); i++) { + const Standard_Real& real = k(i); + knots.push_back(real); + } + return knots; +} + +std::vector GeomBSplineCurve::getMultiplicities() const +{ + std::vector mults; + mults.reserve(myCurve->NbKnots()); + TColStd_Array1OfInteger m(1,myCurve->NbKnots()); + myCurve->Multiplicities(m); + + for (Standard_Integer i=m.Lower(); i<=m.Upper(); i++) { + const Standard_Integer& nm = m(i); + mults.push_back(nm); + } + return mults; +} + +int GeomBSplineCurve::getDegree() const +{ + return myCurve->Degree(); +} + +bool GeomBSplineCurve::IsPeriodic() const +{ + return myCurve->IsPeriodic()==Standard_True; +} + bool GeomBSplineCurve::join(const Handle_Geom_BSplineCurve& spline) { GeomConvert_CompCurveToBSplineCurve ccbc(this->myCurve); diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index 391b1e783..b650ecc01 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -130,7 +130,19 @@ public: bool closestParameterToBasicCurve(const Base::Vector3d& point, double &u) const; }; -class PartExport GeomBezierCurve : public GeomCurve +class PartExport GeomBoundedCurve : public GeomCurve +{ + TYPESYSTEM_HEADER(); +public: + GeomBoundedCurve(); + virtual ~GeomBoundedCurve(); + + // Geometry helper + virtual Base::Vector3d getStartPoint() const; + virtual Base::Vector3d getEndPoint() const; +}; + +class PartExport GeomBezierCurve : public GeomBoundedCurve { TYPESYSTEM_HEADER(); public: @@ -153,7 +165,7 @@ private: Handle_Geom_BezierCurve myCurve; }; -class PartExport GeomBSplineCurve : public GeomCurve +class PartExport GeomBSplineCurve : public GeomBoundedCurve { TYPESYSTEM_HEADER(); public: @@ -183,7 +195,18 @@ public: int countPoles() const; void setPole(int index, const Base::Vector3d&, double weight=-1); + void setPoles(const std::vector& poles, const std::vector& weights); + void setPoles(const std::vector& poles); + void setWeights(const std::vector& weights); + void setKnot(int index, const double val, int mult=-1); + void setKnots(const std::vector& knots); + void setKnots(const std::vector& knots, const std::vector multiplicities); std::vector getPoles() const; + std::vector getWeights() const; + std::vector getKnots() const; + std::vector getMultiplicities() const; + int getDegree() const; + bool IsPeriodic() const; bool join(const Handle_Geom_BSplineCurve&); void makeC1Continuous(double, double); std::list toBiArcs(double tolerance) const; From 80adf30da373daf648e047a8d78b45ad5507ff25 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 4 Jan 2017 01:19:18 +0100 Subject: [PATCH 02/38] Sketcher: BSpline FreeGCS geometry definition ============================================= multiplicities, degree and periodic are left as non-parameters of the solver, while still allowing certain manipulations to be effected from the solver in certain situations (for example modifying the multiplicity of start/end nodes when applying G1,G2,G3 constraints between BSplines). --- src/Mod/Sketcher/App/planegcs/Geo.cpp | 71 +++++++++++++++++++++++++++ src/Mod/Sketcher/App/planegcs/Geo.h | 28 +++++++++++ 2 files changed, 99 insertions(+) diff --git a/src/Mod/Sketcher/App/planegcs/Geo.cpp b/src/Mod/Sketcher/App/planegcs/Geo.cpp index 66cb59d47..ab30b0b23 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.cpp +++ b/src/Mod/Sketcher/App/planegcs/Geo.cpp @@ -607,4 +607,75 @@ ArcOfParabola* ArcOfParabola::Copy() return crv; } +// bspline +DeriVector2 BSpline::CalculateNormal(Point& p, double* derivparam) +{ + // place holder + DeriVector2 ret = DeriVector2(); + + return ret; +} + +DeriVector2 BSpline::Value(double u, double du, double* derivparam) +{ + + // place holder + DeriVector2 ret = DeriVector2(); + + return ret; +} + +int BSpline::PushOwnParams(VEC_pD &pvec) +{ + int cnt=0; + + for(VEC_P::const_iterator it = poles.begin(); it != poles.end(); ++it) { + pvec.push_back( (*it).x ); + pvec.push_back( (*it).y ); + } + + cnt = cnt + poles.size() * 2; + + pvec.insert(pvec.end(), weights.begin(), weights.end()); + cnt = cnt + weights.size(); + + pvec.insert(pvec.end(), knots.begin(), knots.end()); + cnt = cnt + knots.size(); + + pvec.push_back(start.x); cnt++; + pvec.push_back(start.y); cnt++; + pvec.push_back(end.x); cnt++; + pvec.push_back(end.y); cnt++; + + return cnt; +} + +void BSpline::ReconstructOnNewPvec(VEC_pD &pvec, int &cnt) +{ + for(VEC_P::iterator it = poles.begin(); it != poles.end(); ++it) { + (*it).x = pvec[cnt]; cnt++; + (*it).y = pvec[cnt]; cnt++; + } + + for(VEC_pD::iterator it = weights.begin(); it != weights.end(); ++it) { + (*it) = pvec[cnt]; cnt++; + } + + for(VEC_pD::iterator it = knots.begin(); it != knots.end(); ++it) { + (*it) = pvec[cnt]; cnt++; + } + + start.x=pvec[cnt]; cnt++; + start.y=pvec[cnt]; cnt++; + end.x=pvec[cnt]; cnt++; + end.y=pvec[cnt]; cnt++; + +} + +BSpline* BSpline::Copy() +{ + BSpline* crv = new BSpline(*this); + return crv; +} + }//namespace GCS diff --git a/src/Mod/Sketcher/App/planegcs/Geo.h b/src/Mod/Sketcher/App/planegcs/Geo.h index b71790400..0855f7534 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.h +++ b/src/Mod/Sketcher/App/planegcs/Geo.h @@ -36,6 +36,8 @@ namespace GCS double *y; }; + typedef std::vector VEC_P; + ///Class DeriVector2 holds a vector value and its derivative on the ///parameter that the derivatives are being calculated for now. x,y is the ///actual vector (v). dx,dy is a derivative of the vector by a parameter @@ -270,6 +272,32 @@ namespace GCS virtual ArcOfParabola* Copy(); }; + class BSpline: public Curve + { + public: + BSpline(){periodic=false;degree=2;} + virtual ~BSpline(){} + // parameters + VEC_P poles; + VEC_pD weights; + VEC_pD knots; + // dependent parameters (depends on previous parameters, + // but an "arcrules" constraint alike would be required to gain the commodity of simple coincident + // with endpoint constraints) + Point start; + Point end; + // not solver parameters + VEC_I mult; + int degree; + bool periodic; + // interface helpers + 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 BSpline* Copy(); + }; + } //namespace GCS #endif // PLANEGCS_GEO_H From 6c456e91823144a15b5a5dfc49698a94f2e7643b Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 4 Jan 2017 01:44:12 +0100 Subject: [PATCH 03/38] Sketcher: BSpline solver sketch basic implementation ==================================================== Creation of solver geometry definitions from Part::BSpline geometries and update of solved geometry back. --- src/Mod/Sketcher/App/Sketch.cpp | 133 ++++++++++++++++++++++++++++++++ src/Mod/Sketcher/App/Sketch.h | 6 +- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 370f376f9..22c2f86a3 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,7 @@ void Sketch::clear(void) ArcsOfEllipse.clear(); ArcsOfHyperbola.clear(); ArcsOfParabola.clear(); + BSplines.clear(); // deleting the doubles allocated with new for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it) @@ -182,6 +184,8 @@ const char* nameByType(Sketch::GeoType type) return "arcofhyperbola"; case Sketch::ArcOfParabola: return "arcofparabola"; + case Sketch::BSpline: + return "bspline"; case Sketch::None: default: return "unknown"; @@ -224,6 +228,10 @@ int Sketch::addGeometry(const Part::Geometry *geo, bool fixed) const GeomArcOfParabola *aop = dynamic_cast(geo); // create the definition struct for that geom return addArcOfParabola(*aop, fixed); + } else if (geo->getTypeId() == GeomBSplineCurve::getClassTypeId()) { // add a bspline + const GeomBSplineCurve *bsp = static_cast(geo); + // create the definition struct for that geom + return addBSpline(*bsp, fixed); } else { throw Base::TypeError("Sketch::addGeometry(): Unknown or unsupported type added to a sketch"); @@ -646,6 +654,94 @@ int Sketch::addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, boo return Geoms.size()-1; } +int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) +{ + std::vector ¶ms = fixed ? FixParameters : Parameters; + + // create our own copy + GeomBSplineCurve *bsp = static_cast(bspline.clone()); + // create the definition struct for that geom + GeoDef def; + def.geo = bsp; + def.type = BSpline; + + std::vector poles = bsp->getPoles(); + std::vector weights = bsp->getWeights(); + std::vector knots = bsp->getKnots(); + std::vector mult = bsp->getMultiplicities(); + int degree = bsp->getDegree(); + bool periodic = bsp->IsPeriodic(); + + Base::Vector3d startPnt = bsp->getStartPoint(); + Base::Vector3d endPnt = bsp->getEndPoint(); + + std::vector spoles; + + for(std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it){ + params.push_back(new double( (*it).x )); + params.push_back(new double( (*it).y )); + + GCS::Point p; + p.x = params[params.size()-2]; + p.y = params[params.size()-1]; + + spoles.push_back(p); + } + + std::vector sweights; + + for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it) { + params.push_back(new double( (*it) )); + sweights.push_back(params[params.size()-1]); + } + + std::vector sknots; + + for(std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it) { + params.push_back(new double( (*it) )); + sknots.push_back(params[params.size()-1]); + } + + GCS::Point p1, p2; + + 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]; + + def.startPointId = Points.size(); + Points.push_back(p1); + def.endPointId = Points.size(); + Points.push_back(p2); + + GCS::BSpline bs; + bs.start = p1; + bs.end = p2; + bs.poles = spoles; + bs.weights = sweights; + bs.knots = sknots; + bs.mult = mult; + bs.degree = degree; + bs.periodic = periodic; + def.index = BSplines.size(); + BSplines.push_back(bs); + + // store complete set + Geoms.push_back(def); + + // arcs require an rule constraint for the end points + /*if (!fixed) + GCSsys.addConstraintArcOfParabolaRules(bs);*/ + + // 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; @@ -789,6 +885,9 @@ Py::Tuple Sketch::getPyGeometry(void) const } else if (it->type == ArcOfParabola) { GeomArcOfParabola *aop = dynamic_cast(it->geo->clone()); tuple[i] = Py::asObject(new ArcOfParabolaPy(aop)); + } else if (it->type == BSpline) { + GeomBSplineCurve *bsp = dynamic_cast(it->geo->clone()); + tuple[i] = Py::asObject(new BSplineCurvePy(bsp)); } else { // not implemented type in the sketch! } @@ -830,6 +929,9 @@ GCS::Curve* Sketch::getGCSCurveByGeoId(int geoId) case ArcOfParabola: return &ArcsOfParabola[Geoms[geoId].index]; break; + case BSpline: + return &BSplines[Geoms[geoId].index]; + break; default: return 0; }; @@ -2454,6 +2556,37 @@ bool Sketch::updateGeometry() aop->setFocal(fd.Length()); aop->setRange(*myArc.startAngle, *myArc.endAngle, /*emulateCCW=*/true); + } else if (it->type == BSpline) { + GCS::BSpline &mybsp = BSplines[it->index]; + + GeomBSplineCurve *bsp = dynamic_cast(it->geo); + + std::vector poles; + std::vector weights; + + std::vector::const_iterator it1; + std::vector::const_iterator it2; + + for( it1 = mybsp.poles.begin(), it2 = mybsp.weights.begin(); it1 != mybsp.poles.end() && it2 != mybsp.weights.end(); ++it1, ++it2) { + poles.push_back(Vector3d( *(*it1).x , *(*it1).y , 0.0)); + weights.push_back(*(*it2)); + } + + bsp->setPoles(poles, weights); + + std::vector knots; + std::vector mult; + + std::vector::const_iterator it3; + std::vector::const_iterator it4; + + for( it3 = mybsp.knots.begin(), it4 = mybsp.mult.begin(); it3 != mybsp.knots.end() && it4 != mybsp.mult.end(); ++it3, ++it4) { + knots.push_back(*(*it3)); + mult.push_back((*it4)); + } + + bsp->setKnots(knots,mult); + } } catch (Base::Exception e) { Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n", diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 7ff73c9cd..4ac6bc519 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -132,6 +132,8 @@ public: int addArcOfHyperbola(const Part::GeomArcOfHyperbola &hyperbolaSegment, bool fixed=false); /// add an arc of parabola int addArcOfParabola(const Part::GeomArcOfParabola ¶bolaSegment, bool fixed=false); + /// add a BSpline + int addBSpline(const Part::GeomBSplineCurve &spline, bool fixed=false); //@} @@ -339,7 +341,8 @@ public: 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, - ArcOfParabola = 8 + ArcOfParabola = 8, + BSpline = 9 }; float SolveTime; @@ -388,6 +391,7 @@ protected: std::vector ArcsOfEllipse; std::vector ArcsOfHyperbola; std::vector ArcsOfParabola; + std::vector BSplines; bool isInitMove; bool isFine; From d60613364b6cd9bf55337ee14f89b04bd4b73751 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 5 Jan 2017 21:45:47 +0100 Subject: [PATCH 04/38] Sketcher: BSpline basic SketchObject support --- src/Mod/Sketcher/App/SketchObject.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 9a33e90b0..6d45e60c4 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -43,6 +43,7 @@ # include # include # include +# include # include # include # include @@ -514,6 +515,12 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const return aop->getEndPoint(); else if (PosId == mid) return aop->getCenter(); + } else if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + const Part::GeomBSplineCurve *bsp = static_cast(geo); + if (PosId == start) + return bsp->getStartPoint(); + else if (PosId == end) + return bsp->getEndPoint(); } return Base::Vector3d(); @@ -571,6 +578,7 @@ bool SketchObject::isSupportedGeometry(const Part::Geometry *geo) const geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { return true; } @@ -4213,6 +4221,11 @@ void SketchObject::rebuildVertexIndex(void) VertexId2PosId.push_back(end); VertexId2GeoId.push_back(i); VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); } } } From 36a5d5f9b60fa08467a5235075f2fbbe4aff3326 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 5 Jan 2017 21:52:35 +0100 Subject: [PATCH 05/38] Sketcher: Enable BSpline creation in SketchObjectPy --- src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index a66348aa7..de7a3f52a 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -114,6 +114,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { ret = this->getSketchObjectPtr()->addGeometry(geo,isConstruction); } @@ -167,6 +168,7 @@ PyObject* SketchObjectPy::addGeometry(PyObject *args) geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { geoList.push_back(geo); } From 6fc4ade7c6f45879d8092a136259f146cdc13215 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 5 Jan 2017 22:10:31 +0100 Subject: [PATCH 06/38] Sketcher: Validation of BSpline --- src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp index aba66511b..b6a89b81a 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherValidation.cpp @@ -245,6 +245,18 @@ void SketcherValidation::on_findButton_clicked() id.v = segm->getEndPoint(); vertexIds.push_back(id); } + else if (g->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + const Part::GeomBSplineCurve *segm = static_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; From cb687b8e746d201b694e945791781f3f3072bfbf Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 6 Jan 2017 00:08:30 +0100 Subject: [PATCH 07/38] Sketcher: ViewProvider BSpline Representation --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index c3d16c369..0fe679e6e 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -780,7 +780,8 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe geo->getTypeId() == Part::GeomEllipse::getClassTypeId()|| geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()|| geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()|| - geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()|| + geo->getTypeId() == Part::GeomBSplineCurve::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)" @@ -3346,6 +3347,9 @@ void ViewProviderSketch::draw(bool temp) const Part::GeomBSplineCurve *spline = static_cast(*it); Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle()); + Base::Vector3d startp = spline->getStartPoint(); + Base::Vector3d endp = spline->getEndPoint(); + double first = curve->FirstParameter(); double last = curve->LastParameter(); if (first > last) // if arc is reversed @@ -3365,13 +3369,16 @@ void ViewProviderSketch::draw(bool temp) gp_Pnt end = curve->Value(last); Coords.push_back(Base::Vector3d(end.X(), end.Y(), end.Z())); - std::vector poles = spline->getPoles(); + // abdullah: Poles thought as internal geometry + /*std::vector poles = spline->getPoles(); for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it) { Points.push_back(*it); - } + }*/ Index.push_back(countSegments+1); edit->CurvIdToGeoId.push_back(GeoId); + Points.push_back(startp); + Points.push_back(endp); } else { } From 8ea8699d14b1706a8a3f96665b0e654f965683af Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 7 Jan 2017 02:00:12 +0100 Subject: [PATCH 08/38] Part: Enable BSpline creation from poles --- src/Mod/Part/App/BSplineCurvePyImp.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Mod/Part/App/BSplineCurvePyImp.cpp b/src/Mod/Part/App/BSplineCurvePyImp.cpp index ab16b4b9e..e58f5ddba 100644 --- a/src/Mod/Part/App/BSplineCurvePyImp.cpp +++ b/src/Mod/Part/App/BSplineCurvePyImp.cpp @@ -71,7 +71,16 @@ int BSplineCurvePy::PyInit(PyObject* args, PyObject* /*kwd*/) return 0; } + PyObject* obj; + // poles, [ periodic, degree, interpolate ] + + obj = buildFromPoles(args); + + if (obj != 0) + return 0; + PyErr_SetString(PyExc_TypeError, "B-Spline constructor accepts:\n" + "-- poles, [ periodic, degree, interpolate ]\n" "-- empty parameter list\n"); return -1; } From e7daf5a90ef7067f64d6fc9e7edc7af040c05774 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 7 Jan 2017 14:35:43 +0100 Subject: [PATCH 09/38] Sketcher: BSpline icons courtesy of Jim --- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 5 + .../icons/Sketcher_CreateBSpline.svg | 539 ++++++++++++++++++ .../icons/Sketcher_CreateBSpline_Constr.svg | 539 ++++++++++++++++++ .../icons/Sketcher_Element_BSpline_Edge.svg | 396 +++++++++++++ .../Sketcher_Element_BSpline_EndPoint.svg | 385 +++++++++++++ .../Sketcher_Element_BSpline_StartPoint.svg | 396 +++++++++++++ 6 files changed, 2260 insertions(+) create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline_Constr.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_Edge.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_EndPoint.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_StartPoint.svg diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index b7639491b..18b4ed798 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -62,6 +62,8 @@ icons/Sketcher_Create3PointCircle_Constr.svg icons/Sketcher_CreateArc.svg icons/Sketcher_CreateArc_Constr.svg + icons/Sketcher_CreateBSpline.svg + icons/Sketcher_CreateBSpline_Constr.svg icons/Sketcher_CreateCircle.svg icons/Sketcher_CreateCircle_Constr.svg icons/Sketcher_CreateEllipse.svg @@ -97,6 +99,9 @@ icons/Sketcher_Element_Arc_EndPoint.svg icons/Sketcher_Element_Arc_MidPoint.svg icons/Sketcher_Element_Arc_StartingPoint.svg + icons/Sketcher_Element_BSpline_Edge.svg + icons/Sketcher_Element_BSpline_EndPoint.svg + icons/Sketcher_Element_BSpline_StartPoint.svg icons/Sketcher_Element_Circle_Edge.svg icons/Sketcher_Element_Circle_MidPoint.svg icons/Sketcher_Element_Ellipse_All.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline.svg new file mode 100644 index 000000000..515b50e49 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline.svg @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline_Constr.svg new file mode 100644 index 000000000..04c6f5b33 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_CreateBSpline_Constr.svg @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_Edge.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_Edge.svg new file mode 100644 index 000000000..a8f5f6690 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_Edge.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_EndPoint.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_EndPoint.svg new file mode 100644 index 000000000..14d2cf083 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_EndPoint.svg @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_StartPoint.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_StartPoint.svg new file mode 100644 index 000000000..2ba3d8b41 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Element_BSpline_StartPoint.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c20b17f72163b00dbc87227753be3af0d3490b68 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 7 Jan 2017 20:21:19 +0100 Subject: [PATCH 10/38] Sketxher: Basic creation method =============================== For non-periodic case. No autoconstraints or internal geometry at this point. --- src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp | 1 + src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 261 ++++++++++++++++++ src/Mod/Sketcher/Gui/Workbench.cpp | 6 +- 3 files changed, 266 insertions(+), 2 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp index 43aec54be..00e01ba98 100644 --- a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp +++ b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp @@ -88,6 +88,7 @@ CmdSketcherToggleConstruction::CmdSketcherToggleConstruction() rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateConic"); rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateCircle"); rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateRegularPolygon"); + rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CreateBSpline"); } void CmdSketcherToggleConstruction::activated(int iMsg) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index dbbdb6198..deace1c96 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4273,6 +4273,266 @@ bool CmdSketcherCompCreateConic::isActive(void) return isCreateGeoActive(getActiveGuiDocument()); } +// ====================================================================================== + +/* XPM */ +static const char *cursor_createbspline[]={ +"32 32 3 1", +"+ c white", +"# c red", +". c None", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"......+.........................", +"................................", +"+++++...+++++...................", +"................................", +"......+...............###.......", +"......+...............#.#.......", +"......+...............###.......", +"......+..............#..#.......", +"......+.............#....#......", +"....................#.+..#......", +"..................+#+..+..#...+.", +"................++#.....+.#..+..", +"......+........+..#......++#+...", +".......+......+..#.........#....", +"........++..++..#..........###..", +"..........++....#..........#.#..", +"......#........#...........###..", +".......#......#.................", +"........#.....#.................", +".........#...#..................", +"..........###...................", +"..........#.#...................", +"..........###...................", +"................................", +"................................", +"................................", +"................................", +"................................"}; + +class DrawSketchHandlerBSpline: public DrawSketchHandler +{ +public: + DrawSketchHandlerBSpline() + : Mode(STATUS_SEEK_FIRST_CONTROLPOINT) + , EditCurve(2) + { + } + + virtual ~DrawSketchHandlerBSpline() {} + /// modes + enum SELECT_MODE { + STATUS_SEEK_FIRST_CONTROLPOINT, + STATUS_SEEK_ADDITIONAL_CONTROLPOINTS, + STATUS_CLOSE + }; + + virtual void activated(ViewProviderSketch *) + { + setCursor(QPixmap(cursor_createbspline),7,7); + } + + virtual void mouseMove(Base::Vector2d onSketchPos) + { + if (Mode==STATUS_SEEK_FIRST_CONTROLPOINT) { + setPositionText(onSketchPos); + /*if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr1); + return; + }*/ + } + else if (Mode==STATUS_SEEK_ADDITIONAL_CONTROLPOINTS){ + + EditCurve[EditCurve.size()-1] = onSketchPos; + + sketchgui->drawEdit(EditCurve); + + float length = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).Length(); + float angle = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).GetAngle(Base::Vector2d(1.f,0.f)); + + SbString text; + text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); + setPositionText(EditCurve[EditCurve.size()-1], text); + + } + applyCursor(); + } + + virtual bool pressButton(Base::Vector2d onSketchPos) + { + if (Mode == STATUS_SEEK_FIRST_CONTROLPOINT) { + + EditCurve[0] = onSketchPos; + + Mode = STATUS_SEEK_ADDITIONAL_CONTROLPOINTS; + } + else if (Mode == STATUS_SEEK_ADDITIONAL_CONTROLPOINTS) { + + EditCurve[EditCurve.size()-1] = onSketchPos; + + // finish adding controlpoints on double click + if (EditCurve[EditCurve.size()-2] == EditCurve[EditCurve.size()-1]) { + EditCurve.pop_back(); + Mode = STATUS_CLOSE; + } + else { + EditCurve.resize(EditCurve.size() + 1); // add one place for a pole + } + + } + return true; + } + + virtual bool releaseButton(Base::Vector2d /*onSketchPos*/) + { + if (Mode==STATUS_CLOSE) { + unsetCursor(); + resetPositionText(); + + std::stringstream stream; + + for (std::vector::const_iterator it=EditCurve.begin(); + it != EditCurve.end(); ++it) { + stream << "App.Vector(" << (*it).x << "," << (*it).y << "),"; + } + + std::string controlpoints = stream.str(); + + // remove last comma and add brackets + int index = controlpoints.rfind(','); + controlpoints.resize(index); + + controlpoints.insert(0,1,'['); + controlpoints.append(1,']'); + + int currentgeoid = getHighestCurveIndex(); + + try { + + Gui::Command::openCommand("Add sketch BSplineCurve"); + + //Add arc of parabola + Gui::Command::doCommand(Gui::Command::Doc, + "App.ActiveDocument.%s.addGeometry(Part.BSplineCurve" + "(%s)," + "%s)", + sketchgui->getObject()->getNameInDocument(), + controlpoints.c_str(), + 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 + /*if (sugConstr1.size() > 0) { + createAutoConstraints(sugConstr1, currentgeoid+1, Sketcher::start); + sugConstr1.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_CONTROLPOINT; + EditCurve.clear(); + sketchgui->drawEdit(EditCurve); + EditCurve.resize(2); + 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: + SELECT_MODE Mode; + + std::vector EditCurve; + + std::vector sugConstr1, sugConstr2; + +}; + +DEF_STD_CMD_AU(CmdSketcherCreateBSpline); + +CmdSketcherCreateBSpline::CmdSketcherCreateBSpline() + : Command("Sketcher_CreateBSpline") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create B-Spline"); + sToolTipText = QT_TR_NOOP("Create a B-Spline via control point in the sketch."); + sWhatsThis = "Sketcher_CreateBSpline"; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_CreateBSpline"; + eType = ForEdit; +} + +void CmdSketcherCreateBSpline::activated(int iMsg) +{ + Q_UNUSED(iMsg); + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerBSpline() ); +} + +void CmdSketcherCreateBSpline::updateAction(int mode) +{ + switch (mode) { + case Normal: + if (getAction()) + getAction()->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline")); + break; + case Construction: + if (getAction()) + getAction()->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline_Constr")); + break; + } +} + +bool CmdSketcherCreateBSpline::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + + // ====================================================================================== /* XPM */ @@ -6340,6 +6600,7 @@ void CreateSketcherCommandsCreateGeo(void) rcCmdMgr.addCommand(new CmdSketcherCreateArcOfEllipse()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfHyperbola()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfParabola()); + rcCmdMgr.addCommand(new CmdSketcherCreateBSpline()); rcCmdMgr.addCommand(new CmdSketcherCreateLine()); rcCmdMgr.addCommand(new CmdSketcherCreatePolyline()); rcCmdMgr.addCommand(new CmdSketcherCreateRectangle()); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 7943a0121..818b539d2 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -141,13 +141,15 @@ inline void SketcherAddWorkspaceArcs(Gui::MenuItem& geom){ << "Sketcher_CreateEllipseBy3Points" << "Sketcher_CreateArcOfEllipse" << "Sketcher_CreateArcOfHyperbola" - << "Sketcher_CreateArcOfParabola"; + << "Sketcher_CreateArcOfParabola" + << "Sketcher_CreateBSpline"; } template <> inline void SketcherAddWorkspaceArcs(Gui::ToolBarItem& geom){ geom << "Sketcher_CompCreateArc" << "Sketcher_CompCreateCircle" - << "Sketcher_CompCreateConic"; + << "Sketcher_CompCreateConic" + << "Sketcher_CreateBSpline"; } template void SketcherAddWorkspaceRegularPolygon(T& geom); From 61b685fd53e43a39132bafde4f309a89ccc91864 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 8 Jan 2017 00:42:30 +0100 Subject: [PATCH 11/38] Part: BSpline serialization =========================== It stores a rational BSpline even if non-rational. It should be extended to store in addition whether it is periodic or not, i.e. to support periodic BSplines. --- src/Mod/Part/App/Geometry.cpp | 127 +++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index ffa57ec42..ff5459493 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -802,9 +802,130 @@ void GeomBSplineCurve::makeC1Continuous(double tol, double ang_tol) } // Persistence implementer -unsigned int GeomBSplineCurve::getMemSize (void) const {assert(0); return 0;/* not implemented yet */} -void GeomBSplineCurve::Save (Base::Writer &/*writer*/) const {assert(0); /* not implemented yet */} -void GeomBSplineCurve::Restore (Base::XMLReader &/*reader*/) {assert(0); /* not implemented yet */} +unsigned int GeomBSplineCurve::getMemSize (void) const +{ + return sizeof(Geom_BSplineCurve); +} + +void GeomBSplineCurve::Save(Base::Writer& writer) const +{ + // save the attributes of the father class + GeomCurve::Save(writer); + + std::vector poles = this->getPoles(); + std::vector weights = this->getWeights(); + std::vector knots = this->getKnots(); + std::vector mults = this->getMultiplicities(); + int degree = this->getDegree(); + + writer.Stream() + << writer.ind() + << "" << endl; + + writer.incInd(); + for(std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it){ + writer.Stream() + << writer.ind() + << "" << endl; + } + for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it){ + writer.Stream() + << writer.ind() + << "" << endl; + } + for(std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it){ + writer.Stream() + << writer.ind() + << "" << endl; + } + for(std::vector::const_iterator it = mults.begin(); it != mults.end(); ++it){ + writer.Stream() + << writer.ind() + << "" << endl; + } + writer.decInd(); + writer.Stream() << writer.ind() << "" << endl ; +} + +void GeomBSplineCurve::Restore(Base::XMLReader& reader) +{ + // read the attributes of the father class + GeomCurve::Restore(reader); + + reader.readElement("BSplineCurve"); + // get the value of my attribute + int polescount = reader.getAttributeAsInteger("PolesCount"); + int knotscount = reader.getAttributeAsInteger("KnotsCount"); + int degree = reader.getAttributeAsInteger("Degree"); + + // You are here!! + // Handle_Geom_BSplineCurve spline = new + // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree, + // PyObject_IsTrue(periodic) ? Standard_True : Standard_False, + // PyObject_IsTrue(CheckRational) ? Standard_True : Standard_False); + + TColgp_Array1OfPnt p(1,polescount); + TColStd_Array1OfReal w(1,polescount); + TColStd_Array1OfReal k(1,knotscount); + TColStd_Array1OfInteger m(1,knotscount); + + for (int i = 1; i <= polescount; i++) { + reader.readElement("Pole"); + double X = reader.getAttributeAsFloat("X"); + double Y = reader.getAttributeAsFloat("Y"); + double Z = reader.getAttributeAsFloat("Z"); + p.SetValue(i, gp_Pnt(X,Y,Z)); + } + + for (int i = 1; i <= polescount; i++) { + reader.readElement("Weight"); + double val = reader.getAttributeAsFloat("value"); + w.SetValue(i, val); + } + + for (int i = 1; i <= knotscount; i++) { + reader.readElement("Knot"); + double val = reader.getAttributeAsFloat("value"); + k.SetValue(i, val); + } + + for (int i = 1; i <= knotscount; i++) { + reader.readElement("Mult"); + double val = reader.getAttributeAsInteger("value"); + m.SetValue(i, val); + } + + reader.readEndElement("BSplineCurve"); + // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,periodic,CheckRational + + try { + Handle_Geom_BSplineCurve spline = new Geom_BSplineCurve(p, w, k, m, degree, Standard_False, Standard_False); + + if (!spline.IsNull()) + this->myCurve = spline; + else + throw Base::Exception("BSpline restore failed"); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } +} + PyObject *GeomBSplineCurve::getPyObject(void) { From e7dacb9178dab1d5df2e3276b884d6ebf36987bd Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 10 Jan 2017 14:44:43 +0100 Subject: [PATCH 12/38] Part: Bezier serialization support extension to periodic ======================================================= Extension for periodic + suggestions by Werner. --- src/Mod/Part/App/Geometry.cpp | 91 ++++++++++++++++------------------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index ff5459493..89ecd1adc 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -813,10 +813,11 @@ void GeomBSplineCurve::Save(Base::Writer& writer) const GeomCurve::Save(writer); std::vector poles = this->getPoles(); - std::vector weights = this->getWeights(); - std::vector knots = this->getKnots(); - std::vector mults = this->getMultiplicities(); - int degree = this->getDegree(); + std::vector weights = this->getWeights(); + std::vector knots = this->getKnots(); + std::vector mults = this->getMultiplicities(); + int degree = this->getDegree(); + bool isperiodic = this->IsPeriodic(); writer.Stream() << writer.ind() @@ -824,39 +825,37 @@ void GeomBSplineCurve::Save(Base::Writer& writer) const << "PolesCount=\"" << poles.size() << "\" KnotsCount=\"" << knots.size() << "\" Degree=\"" << degree << + "\" IsPeriodic=\"" << (int) isperiodic << "\">" << endl; writer.incInd(); - for(std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it){ + + std::vector::const_iterator itp; + std::vector::const_iterator itw; + + for(itp = poles.begin(), itw = weights.begin(); itp != poles.end() && itw != weights.end(); ++itp, ++itw){ writer.Stream() << writer.ind() << "" << endl; } - for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it){ - writer.Stream() - << writer.ind() - << "" << endl; - } - for(std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it){ + + std::vector::const_iterator itk; + std::vector::const_iterator itm; + + for(itk = knots.begin(), itm = mults.begin(); itk != knots.end() && itm != mults.end(); ++itk, ++itm){ writer.Stream() << writer.ind() << "" << endl; - } - for(std::vector::const_iterator it = mults.begin(); it != mults.end(); ++it){ - writer.Stream() - << writer.ind() - << "" << endl; } + writer.decInd(); writer.Stream() << writer.ind() << "" << endl ; } @@ -871,8 +870,8 @@ void GeomBSplineCurve::Restore(Base::XMLReader& reader) int polescount = reader.getAttributeAsInteger("PolesCount"); int knotscount = reader.getAttributeAsInteger("KnotsCount"); int degree = reader.getAttributeAsInteger("Degree"); - - // You are here!! + bool isperiodic = (bool) reader.getAttributeAsInteger("IsPeriodic"); + // Handle_Geom_BSplineCurve spline = new // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree, // PyObject_IsTrue(periodic) ? Standard_True : Standard_False, @@ -882,39 +881,31 @@ void GeomBSplineCurve::Restore(Base::XMLReader& reader) TColStd_Array1OfReal w(1,polescount); TColStd_Array1OfReal k(1,knotscount); TColStd_Array1OfInteger m(1,knotscount); - + for (int i = 1; i <= polescount; i++) { reader.readElement("Pole"); - double X = reader.getAttributeAsFloat("X"); - double Y = reader.getAttributeAsFloat("Y"); - double Z = reader.getAttributeAsFloat("Z"); - p.SetValue(i, gp_Pnt(X,Y,Z)); + double X = reader.getAttributeAsFloat("X"); + double Y = reader.getAttributeAsFloat("Y"); + double Z = reader.getAttributeAsFloat("Z"); + double W = reader.getAttributeAsFloat("Weight"); + p.SetValue(i, gp_Pnt(X,Y,Z)); + w.SetValue(i, W); } - - for (int i = 1; i <= polescount; i++) { - reader.readElement("Weight"); - double val = reader.getAttributeAsFloat("value"); - w.SetValue(i, val); - } - + for (int i = 1; i <= knotscount; i++) { reader.readElement("Knot"); - double val = reader.getAttributeAsFloat("value"); - k.SetValue(i, val); + double val = reader.getAttributeAsFloat("Value"); + Standard_Integer mult = reader.getAttributeAsInteger("Mult"); + k.SetValue(i, val); + m.SetValue(i, mult); } - - for (int i = 1; i <= knotscount; i++) { - reader.readElement("Mult"); - double val = reader.getAttributeAsInteger("value"); - m.SetValue(i, val); - } - + reader.readEndElement("BSplineCurve"); // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,periodic,CheckRational - + try { - Handle_Geom_BSplineCurve spline = new Geom_BSplineCurve(p, w, k, m, degree, Standard_False, Standard_False); - + Handle_Geom_BSplineCurve spline = new Geom_BSplineCurve(p, w, k, m, degree, isperiodic==true?Standard_True:Standard_False, Standard_False); + if (!spline.IsNull()) this->myCurve = spline; else From 609c80b71a949688f999f9fb4d1bc0f98212fe71 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 10 Jan 2017 20:05:18 +0100 Subject: [PATCH 13/38] Part: Fixes triggered by Werner's comments on my branch --- src/Mod/Part/App/Geometry.cpp | 6 +++--- src/Mod/Part/App/Geometry.h | 4 ++-- src/Mod/Sketcher/App/Sketch.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 89ecd1adc..4758687a6 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -653,7 +653,7 @@ void GeomBSplineCurve::setKnots(const std::vector& knots) } } -void GeomBSplineCurve::setKnots(const std::vector& knots, const std::vector multiplicities) +void GeomBSplineCurve::setKnots(const std::vector& knots, const std::vector& multiplicities) { Standard_Integer index=0; @@ -698,7 +698,7 @@ int GeomBSplineCurve::getDegree() const return myCurve->Degree(); } -bool GeomBSplineCurve::IsPeriodic() const +bool GeomBSplineCurve::isPeriodic() const { return myCurve->IsPeriodic()==Standard_True; } @@ -817,7 +817,7 @@ void GeomBSplineCurve::Save(Base::Writer& writer) const std::vector knots = this->getKnots(); std::vector mults = this->getMultiplicities(); int degree = this->getDegree(); - bool isperiodic = this->IsPeriodic(); + bool isperiodic = this->isPeriodic(); writer.Stream() << writer.ind() diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index b650ecc01..aa0eeee88 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -200,13 +200,13 @@ public: void setWeights(const std::vector& weights); void setKnot(int index, const double val, int mult=-1); void setKnots(const std::vector& knots); - void setKnots(const std::vector& knots, const std::vector multiplicities); + void setKnots(const std::vector& knots, const std::vector& multiplicities); std::vector getPoles() const; std::vector getWeights() const; std::vector getKnots() const; std::vector getMultiplicities() const; int getDegree() const; - bool IsPeriodic() const; + bool isPeriodic() const; bool join(const Handle_Geom_BSplineCurve&); void makeC1Continuous(double, double); std::list toBiArcs(double tolerance) const; diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 22c2f86a3..93744efe2 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -670,7 +670,7 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) std::vector knots = bsp->getKnots(); std::vector mult = bsp->getMultiplicities(); int degree = bsp->getDegree(); - bool periodic = bsp->IsPeriodic(); + bool periodic = bsp->isPeriodic(); Base::Vector3d startPnt = bsp->getStartPoint(); Base::Vector3d endPnt = bsp->getEndPoint(); From 07eebb1c522e8f2b282367df503d5398de1c31c7 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 10 Jan 2017 23:22:21 +0100 Subject: [PATCH 14/38] Sketcher: Constraint Third Redefinition for internal geometry ============================================================= Internal alignment of BSplines requires an extra index for unbounded same-type internal geometry (poles, probably also in the future knots). Value shall not be used, as it interferes with the update mechanism for constraint values. An alternative solution would be to add another int to all the constraints just for this case. As internal geometry does not use Third, it seems reasonable to reuse it for this indexing purpose. --- src/Mod/Sketcher/App/Constraint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index f7b78de9d..470ee8027 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -110,7 +110,7 @@ public: PointPos FirstPos; int Second; PointPos SecondPos; - int Third; + int Third; // Note: for InternalAlignment Type this index indexes equal internal geometry elements (e.g. index of pole in a bspline), thirdpos remains unused. It is not a GeoId. PointPos ThirdPos; float LabelDistance; float LabelPosition; From d949f528781e75631ec23e5e44faeabfb6ec4a7f Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 10 Jan 2017 22:14:13 +0100 Subject: [PATCH 15/38] Sketcher: BSpline solver Internal Geometry for poles --- src/Mod/Sketcher/App/Constraint.h | 3 ++- src/Mod/Sketcher/App/Sketch.cpp | 28 +++++++++++++++++++++++++++ src/Mod/Sketcher/App/Sketch.h | 1 + src/Mod/Sketcher/App/planegcs/GCS.cpp | 6 ++++++ src/Mod/Sketcher/App/planegcs/GCS.h | 1 + 5 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index 470ee8027..bc897198f 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -67,7 +67,8 @@ enum InternalAlignmentType { HyperbolaMajor = 5, HyperbolaMinor = 6, HyperbolaFocus = 7, - ParabolaFocus = 8 + ParabolaFocus = 8, + BSplineControlPoint = 9 // in this constraint "Third" is used to indicate the index of the control point (0-poles), it is not a GeoId }; /// 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 93744efe2..c48db28cc 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -1197,6 +1197,8 @@ int Sketch::addConstraint(const Constraint *constraint) case ParabolaFocus: rtn = addInternalAlignmentParabolaFocus(constraint->First,constraint->Second); break; + case BSplineControlPoint: + rtn = addInternalAlignmentBSplineControlPoint(constraint->First,constraint->Second, constraint->Third); default: break; } @@ -2396,6 +2398,32 @@ int Sketch::addInternalAlignmentParabolaFocus(int geoId1, int geoId2) return -1; } +int Sketch::addInternalAlignmentBSplineControlPoint(int geoId1, int geoId2, int poleindex) +{ + std::swap(geoId1, geoId2); + + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + if (Geoms[geoId1].type != BSpline) + return -1; + if (Geoms[geoId2].type != Circle) + return -1; + + int pointId1 = getPointId(geoId2, mid); + + if (pointId1 >= 0 && pointId1 < int(Points.size())) { + GCS::Circle &c = Circles[Geoms[geoId2].index]; + + GCS::BSpline &b = BSplines[Geoms[geoId1].index]; + + int tag = ++ConstraintsCounter; + GCSsys.addConstraintInternalAlignmentBSplineControlPoint(b, c, poleindex, tag); + return ConstraintsCounter; + } + return -1; +} + double Sketch::calculateAngleViaPoint(int geoId1, int geoId2, double px, double py) { geoId1 = checkGeoId(geoId1); diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 4ac6bc519..812088ccb 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -314,6 +314,7 @@ public: int addInternalAlignmentHyperbolaMinorDiameter(int geoId1, int geoId2); int addInternalAlignmentHyperbolaFocus(int geoId1, int geoId2); int addInternalAlignmentParabolaFocus(int geoId1, int geoId2); + int addInternalAlignmentBSplineControlPoint(int geoId1, int geoId2, int poleindex); //@} public: //This func is to be used during angle-via-point constraint creation. It calculates diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp index 89ece2d11..46dd6096b 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp @@ -1007,6 +1007,12 @@ int System::addConstraintInternalAlignmentParabolaFocus(Parabola &e, Point &p1, return addConstraintEqual(e.focus1.y, p1.y, tagId); } +int System::addConstraintInternalAlignmentBSplineControlPoint(BSpline &b, Circle &c, int poleindex, int tagId) +{ + addConstraintEqual(b.poles[poleindex].x, c.center.x, tagId); + return addConstraintEqual(b.poles[poleindex].y, c.center.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 7674e8a85..193cfb08e 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.h +++ b/src/Mod/Sketcher/App/planegcs/GCS.h @@ -233,6 +233,7 @@ namespace GCS 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); + int addConstraintInternalAlignmentBSplineControlPoint(BSpline &b, Circle &c, int poleindex, int tag=0); double calculateAngleViaPoint(Curve &crv1, Curve &crv2, Point &p); double calculateAngleViaPoint(Curve &crv1, Curve &crv2, Point &p1, Point &p2); From 6bd801d36336b5b27e9c070e2f1ff1ca4363a8cf Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 10 Jan 2017 23:13:50 +0100 Subject: [PATCH 16/38] Sketcher: expose Bspline pole internal geometry --- src/Mod/Sketcher/App/SketchObject.cpp | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 6d45e60c4..2c7af4f3e 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3300,6 +3300,86 @@ int SketchObject::ExposeInternalGeometry(int GeoId) return incrgeo; //number of added elements } + else if(geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + + const Part::GeomBSplineCurve *bsp = static_cast(geo); + // First we search what has to be restored + std::vector controlpoints(bsp->countPoles()); + std::vector controlpointgeoids(bsp->countPoles()); + + std::vector::iterator itb; + std::vector::iterator it; + + for(it=controlpointgeoids.begin(), itb=controlpoints.begin(); it!=controlpointgeoids.end() && itb!=controlpoints.end(); ++it, ++itb) { + (*it)=-1; + (*itb)=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::BSplineControlPoint: + controlpoints[(*it)->Third] = true; + controlpointgeoids[(*it)->Third] = (*it)->First; + break; + default: + return -1; + } + } + } + + int currentgeoid = getHighestCurveIndex(); + int incrgeo = 0; + + std::vector igeo; + std::vector icon; + + std::vector poles = bsp->getPoles(); + + int index=0; + + for(it=controlpointgeoids.begin(), itb=controlpoints.begin(); it!=controlpointgeoids.end() && itb!=controlpoints.end(); ++it, ++itb, index++) { + + if(!(*itb)) // if controlpoint not existing + { + Part::GeomCircle *pc = new Part::GeomCircle(); + pc->setCenter(poles[index]); + + igeo.push_back(pc); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = Sketcher::BSplineControlPoint; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::mid; + newConstr->Second = GeoId; + newConstr->Third = index; + + icon.push_back(newConstr); + 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 } From 1155022a825707674f20a01accf8f9c50ec8faab Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 11 Jan 2017 01:15:44 +0100 Subject: [PATCH 17/38] Sketcher: BSpline Weights internal geometry support --- src/Mod/Sketcher/App/SketchObject.cpp | 45 +++++++++++++++++++++++ src/Mod/Sketcher/App/planegcs/GCS.cpp | 3 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 4 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 2c7af4f3e..f5660eb67 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3307,6 +3307,8 @@ int SketchObject::ExposeInternalGeometry(int GeoId) std::vector controlpoints(bsp->countPoles()); std::vector controlpointgeoids(bsp->countPoles()); + bool isfirstweightconstrained = false; + std::vector::iterator itb; std::vector::iterator it; @@ -3317,6 +3319,7 @@ int SketchObject::ExposeInternalGeometry(int GeoId) const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + // search for existing poles for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); it != vals.end(); ++it) { if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) @@ -3331,6 +3334,16 @@ int SketchObject::ExposeInternalGeometry(int GeoId) } } } + + if(controlpoints[0]) { + // search for first pole weight constraint + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::Radius && (*it)->First == controlpointgeoids[0]) { + isfirstweightconstrained = true ; + } + } + } int currentgeoid = getHighestCurveIndex(); int incrgeo = 0; @@ -3340,6 +3353,8 @@ int SketchObject::ExposeInternalGeometry(int GeoId) std::vector poles = bsp->getPoles(); + double distance_p0_p1 = (poles[1]-poles[0]).Length(); // for visual purposes only + int index=0; for(it=controlpointgeoids.begin(), itb=controlpoints.begin(); it!=controlpointgeoids.end() && itb!=controlpoints.end(); ++it, ++itb, index++) { @@ -3348,6 +3363,7 @@ int SketchObject::ExposeInternalGeometry(int GeoId) { Part::GeomCircle *pc = new Part::GeomCircle(); pc->setCenter(poles[index]); + pc->setRadius(distance_p0_p1/6); igeo.push_back(pc); @@ -3360,9 +3376,38 @@ int SketchObject::ExposeInternalGeometry(int GeoId) newConstr->Third = index; icon.push_back(newConstr); + + if(it != controlpointgeoids.begin()) { + // if pole-weight newly created make it equal to first weight by default + Sketcher::Constraint *newConstr2 = new Sketcher::Constraint(); + newConstr2->Type = Sketcher::Equal; + newConstr2->First = currentgeoid+incrgeo+1; + newConstr2->FirstPos = Sketcher::none; + newConstr2->Second = controlpointgeoids[0]; + newConstr2->SecondPos = Sketcher::none; + + icon.push_back(newConstr2); + } + else { + controlpointgeoids[0] = currentgeoid+incrgeo+1; + } + incrgeo++; } } + + // constraint the first weight to allow for seamless weight modification and proper visualization + if(!isfirstweightconstrained) { + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::Radius; + newConstr->First = controlpointgeoids[0]; + newConstr->FirstPos = Sketcher::none; + newConstr->setValue( round(distance_p0_p1/6)); // 1/6 is just an estimation for acceptable general visualization + + icon.push_back(newConstr); + + } this->addGeometry(igeo,true); this->addConstraints(icon); diff --git a/src/Mod/Sketcher/App/planegcs/GCS.cpp b/src/Mod/Sketcher/App/planegcs/GCS.cpp index 46dd6096b..3272e882c 100644 --- a/src/Mod/Sketcher/App/planegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/planegcs/GCS.cpp @@ -1010,7 +1010,8 @@ int System::addConstraintInternalAlignmentParabolaFocus(Parabola &e, Point &p1, int System::addConstraintInternalAlignmentBSplineControlPoint(BSpline &b, Circle &c, int poleindex, int tagId) { addConstraintEqual(b.poles[poleindex].x, c.center.x, tagId); - return addConstraintEqual(b.poles[poleindex].y, c.center.y, tagId); + addConstraintEqual(b.poles[poleindex].y, c.center.y, tagId); + return addConstraintEqual(b.weights[poleindex], c.rad, tagId); } diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index deace1c96..3313d0b17 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4426,10 +4426,10 @@ public: currentgeoid++; - /*Gui::Command::doCommand(Gui::Command::Doc, + Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", sketchgui->getObject()->getNameInDocument(), - currentgeoid);*/ + currentgeoid); } catch (const Base::Exception& e) { From d66242bd089a3b3cd3fb3f44399a1c919b42a368 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 11 Jan 2017 23:00:43 +0100 Subject: [PATCH 18/38] Sketcher: Contraint class extension =================================== An additional index for internal geometry elements is introduced, to be stored only Internal Aligment constraint and backwards compatible. --- src/Mod/Sketcher/App/Constraint.cpp | 44 ++++++++++++++++----------- src/Mod/Sketcher/App/Constraint.h | 3 +- src/Mod/Sketcher/App/Sketch.cpp | 2 +- src/Mod/Sketcher/App/SketchObject.cpp | 6 ++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/Mod/Sketcher/App/Constraint.cpp b/src/Mod/Sketcher/App/Constraint.cpp index 1f846b740..cd32c1e98 100644 --- a/src/Mod/Sketcher/App/Constraint.cpp +++ b/src/Mod/Sketcher/App/Constraint.cpp @@ -56,7 +56,8 @@ Constraint::Constraint() ThirdPos(none), LabelDistance(10.f), LabelPosition(0.f), - isDriving(true) + isDriving(true), + InternalAlignmentIndex(-1) { // Initialize a random number generator, to avoid Valgrind false positives. static boost::mt19937 ran; @@ -85,7 +86,8 @@ Constraint::Constraint(const Constraint& from) LabelDistance(from.LabelDistance), LabelPosition(from.LabelPosition), isDriving(from.isDriving), - tag(from.tag) + tag(from.tag), + InternalAlignmentIndex(from.InternalAlignmentIndex) { } @@ -114,6 +116,7 @@ Constraint *Constraint::copy(void) const temp->LabelDistance = this->LabelDistance; temp->LabelPosition = this->LabelPosition; temp->isDriving = this->isDriving; + temp->InternalAlignmentIndex = this->InternalAlignmentIndex; // Do not copy tag, otherwise it is considered a clone, and a "rename" by the expression engine. return temp; } @@ -172,22 +175,24 @@ unsigned int Constraint::getMemSize (void) const void Constraint::Save (Writer &writer) const { writer.Stream() << writer.ind() << "Type==InternalAlignment) writer.Stream() - << "InternalAlignmentType=\"" << (int)AlignmentType << "\" "; + << "InternalAlignmentType=\"" << (int)AlignmentType << "\" " + << "InternalAlignmentIndex=\"" << InternalAlignmentIndex << "\" "; writer.Stream() - << "Value=\"" << Value << "\" " - << "First=\"" << First << "\" " - << "FirstPos=\"" << (int) FirstPos << "\" " - << "Second=\"" << Second << "\" " - << "SecondPos=\"" << (int) SecondPos << "\" " - << "Third=\"" << Third << "\" " - << "ThirdPos=\"" << (int) ThirdPos << "\" " - << "LabelDistance=\"" << LabelDistance << "\" " - << "LabelPosition=\"" << LabelPosition << "\" " - << "IsDriving=\"" << (int)isDriving << "\" />" + << "Value=\"" << Value << "\" " + << "First=\"" << First << "\" " + << "FirstPos=\"" << (int) FirstPos << "\" " + << "Second=\"" << Second << "\" " + << "SecondPos=\"" << (int) SecondPos << "\" " + << "Third=\"" << Third << "\" " + << "ThirdPos=\"" << (int) ThirdPos << "\" " + << "LabelDistance=\"" << LabelDistance << "\" " + << "LabelPosition=\"" << LabelPosition << "\" " + << "IsDriving=\"" << (int)isDriving << "\" />" + << std::endl; } @@ -202,10 +207,15 @@ void Constraint::Restore(XMLReader &reader) Second = reader.getAttributeAsInteger("Second"); SecondPos = (PointPos) reader.getAttributeAsInteger("SecondPos"); - if(this->Type==InternalAlignment) + if(this->Type==InternalAlignment) { AlignmentType = (InternalAlignmentType) reader.getAttributeAsInteger("InternalAlignmentType"); - else + + if (reader.hasAttribute("InternalAlignmentIndex")) + InternalAlignmentIndex = reader.getAttributeAsInteger("InternalAlignmentIndex"); + } + else { AlignmentType = Undef; + } // read the third geo group if present if (reader.hasAttribute("Third")) { diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index bc897198f..e46691d07 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -111,11 +111,12 @@ public: PointPos FirstPos; int Second; PointPos SecondPos; - int Third; // Note: for InternalAlignment Type this index indexes equal internal geometry elements (e.g. index of pole in a bspline), thirdpos remains unused. It is not a GeoId. + int Third; PointPos ThirdPos; float LabelDistance; float LabelPosition; bool isDriving; + int InternalAlignmentIndex; // Note: for InternalAlignment Type this index indexes equal internal geometry elements (e.g. index of pole in a bspline). It is not a GeoId!! protected: boost::uuids::uuid tag; diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index c48db28cc..6aad91d61 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -1198,7 +1198,7 @@ int Sketch::addConstraint(const Constraint *constraint) rtn = addInternalAlignmentParabolaFocus(constraint->First,constraint->Second); break; case BSplineControlPoint: - rtn = addInternalAlignmentBSplineControlPoint(constraint->First,constraint->Second, constraint->Third); + rtn = addInternalAlignmentBSplineControlPoint(constraint->First,constraint->Second, constraint->InternalAlignmentIndex); default: break; } diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index f5660eb67..149330cae 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3326,8 +3326,8 @@ int SketchObject::ExposeInternalGeometry(int GeoId) { switch((*it)->AlignmentType){ case Sketcher::BSplineControlPoint: - controlpoints[(*it)->Third] = true; - controlpointgeoids[(*it)->Third] = (*it)->First; + controlpoints[(*it)->InternalAlignmentIndex] = true; + controlpointgeoids[(*it)->InternalAlignmentIndex] = (*it)->First; break; default: return -1; @@ -3373,7 +3373,7 @@ int SketchObject::ExposeInternalGeometry(int GeoId) newConstr->First = currentgeoid+incrgeo+1; newConstr->FirstPos = Sketcher::mid; newConstr->Second = GeoId; - newConstr->Third = index; + newConstr->InternalAlignmentIndex = index; icon.push_back(newConstr); From 2a4353a940b8d3d588290d1bb3810b9e9d000a27 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 11 Jan 2017 23:44:45 +0100 Subject: [PATCH 19/38] Sketcher: BSpline delete internal geo on deletion --- src/Mod/Sketcher/App/SketchObject.cpp | 93 ++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 149330cae..b83ec3f79 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3612,7 +3612,98 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) return delgeometries.size(); //number of deleted elements } - else + else if( geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + + const Part::GeomBSplineCurve *bsp = static_cast(geo); + + // First we search existing IA + std::vector controlpointgeoids(bsp->countPoles()); + std::vector associatedcontraints(bsp->countPoles()); + + std::vector::iterator it; + std::vector::iterator ita; + + for(it=controlpointgeoids.begin(), ita=associatedcontraints.begin(); it!=controlpointgeoids.end() && ita!=associatedcontraints.end(); ++it, ++ita) { + (*it) = -1; + (*ita) = 0; + } + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + // search for existing poles + 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::BSplineControlPoint: + controlpointgeoids[(*it)->InternalAlignmentIndex] = (*it)->First; + break; + default: + return -1; + } + } + } + + std::vector delgeometries; + bool firstpoledeleted = false; + + for( it=controlpointgeoids.begin(), ita=associatedcontraints.begin(); it!=controlpointgeoids.end() && ita!=associatedcontraints.end(); ++it, ++ita) { + if((*it) != -1) { + // look for a circle at geoid index + for (std::vector< Sketcher::Constraint * >::const_iterator itc= vals.begin(); + itc != vals.end(); ++itc) { + + if((*itc)->Second == (*it) || (*itc)->First == (*it) || (*itc)->Third == (*it)) + (*ita)++; + } + + if((*ita)<3 ) { // IA + Weight + delgeometries.push_back((*it)); + + if (it == controlpointgeoids.begin()) + firstpoledeleted = true; + } + } + } + + 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); + } + } + + // retest the first pole after removal of equality constraints from other poles + associatedcontraints[0] = 0; + delgeometries.clear(); + + if(controlpointgeoids[0] != -1 && !firstpoledeleted) { + // look for a circle at geoid index + for (std::vector< Sketcher::Constraint * >::const_iterator itc= vals.begin(); + itc != vals.end(); ++itc) { + + if((*itc)->Second == controlpointgeoids[0] || (*itc)->First == controlpointgeoids[0] || (*itc)->Third == controlpointgeoids[0]) + associatedcontraints[0]++; + } + + if(associatedcontraints[0]<4 ) // IA + Weight + Radius + delgeometries.push_back(controlpointgeoids[0]); + } + + 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 } From c9de3687af1f557c7b55e63ce8862adafdd301f1 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 11 Jan 2017 23:51:06 +0100 Subject: [PATCH 20/38] Sketcher: BSpline restore internal geometry --- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index e129176bd..bbe94719f 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -765,7 +765,8 @@ void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) if( geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || - geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() || + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ) { int currentgeoid = Obj->getHighestCurveIndex(); From 1076b70056c0b1de605812bb96af02ef14c2e0cb Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 12 Jan 2017 22:44:07 +0100 Subject: [PATCH 21/38] Part: BSpline creation method corrected as per Werner's indication ================================================================== http://forum.freecadweb.org/viewtopic.php?f=10&t=19700 --- src/Mod/Part/App/BSplineCurvePyImp.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Mod/Part/App/BSplineCurvePyImp.cpp b/src/Mod/Part/App/BSplineCurvePyImp.cpp index e58f5ddba..fd5de9641 100644 --- a/src/Mod/Part/App/BSplineCurvePyImp.cpp +++ b/src/Mod/Part/App/BSplineCurvePyImp.cpp @@ -75,9 +75,14 @@ int BSplineCurvePy::PyInit(PyObject* args, PyObject* /*kwd*/) // poles, [ periodic, degree, interpolate ] obj = buildFromPoles(args); - - if (obj != 0) + + if (obj) { + Py_DECREF(obj); return 0; + } + else if (PyErr_ExceptionMatches(PartExceptionOCCError)) { + return -1; + } PyErr_SetString(PyExc_TypeError, "B-Spline constructor accepts:\n" "-- poles, [ periodic, degree, interpolate ]\n" From b255ada03af730e7116625304572e13e8ae19125 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 12 Jan 2017 22:55:31 +0100 Subject: [PATCH 22/38] Sketcher: Sketcher Elements support for BSpline --- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 1a3e38021..3d6262ecc 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -652,6 +652,9 @@ void TaskSketcherElements::slotElementsChanged(void) 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 Sketcher_Element_BSpline_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_Edge") ); + QIcon Sketcher_Element_BSpline_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_StartPoint") ); + QIcon Sketcher_Element_BSpline_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_EndPoint") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); assert(sketchView); @@ -691,6 +694,9 @@ void TaskSketcherElements::slotElementsChanged(void) (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 : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint : none, type == Part::GeomPoint::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Point") + QString::fromLatin1("(Edge%1)").arg(i)): @@ -716,6 +722,9 @@ void TaskSketcherElements::slotElementsChanged(void) type == Part::GeomArcOfParabola::getClassTypeId() ? ( isNamingBoxChecked ? (tr("Parabolic Arc") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Parabolic Arc"))) : + type == Part::GeomBSplineCurve::getClassTypeId() ? ( isNamingBoxChecked ? + (tr("BSpline") + QString::fromLatin1("(Edge%1)").arg(i)): + (QString::fromLatin1("%1-").arg(i)+tr("BSpline"))) : ( isNamingBoxChecked ? (tr("Other") + QString::fromLatin1("(Edge%1)").arg(i)): (QString::fromLatin1("%1-").arg(i)+tr("Other"))), @@ -903,7 +912,10 @@ void TaskSketcherElements::updateIcons(int element) 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 Sketcher_Element_ArcOfParabola_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_Parabolic_Arc_End_Point") ); + QIcon Sketcher_Element_BSpline_Edge( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_Edge") ); + QIcon Sketcher_Element_BSpline_StartingPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_StartPoint") ); + QIcon Sketcher_Element_BSpline_EndPoint( Gui::BitmapFactory().pixmap("Sketcher_Element_BSpline_EndPoint") ); QIcon none( Gui::BitmapFactory().pixmap("Sketcher_Element_SelectionTypeInvalid") ); for (int i=0;ilistWidgetElements->count(); i++) { @@ -934,6 +946,9 @@ void TaskSketcherElements::updateIcons(int element) (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 : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==0) ? Sketcher_Element_BSpline_Edge : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==1) ? Sketcher_Element_BSpline_StartingPoint : + (type == Part::GeomBSplineCurve::getClassTypeId() && element==2) ? Sketcher_Element_BSpline_EndPoint : none); } } From 671e588739dc3edb02eb70c50dc50cc324b1b435 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Thu, 12 Jan 2017 23:45:03 +0100 Subject: [PATCH 23/38] Sketcher: BSpline autoconstraints on creation --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 73 ++++++++++++++--------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 3313d0b17..eeb44b8c1 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4022,7 +4022,6 @@ public: "App.ActiveDocument.%s.ExposeInternalGeometry(%d)", sketchgui->getObject()->getNameInDocument(), currentgeoid); - } catch (const Base::Exception& e) { Base::Console().Error("%s\n", e.what()); @@ -4320,7 +4319,10 @@ public: DrawSketchHandlerBSpline() : Mode(STATUS_SEEK_FIRST_CONTROLPOINT) , EditCurve(2) + , CurrentConstraint(0) { + std::vector sugConstr1; + sugConstr.push_back(sugConstr1); } virtual ~DrawSketchHandlerBSpline() {} @@ -4340,23 +4342,28 @@ public: { if (Mode==STATUS_SEEK_FIRST_CONTROLPOINT) { setPositionText(onSketchPos); - /*if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f,0.f))) { - renderSuggestConstraintsCursor(sugConstr1); + if (seekAutoConstraint(sugConstr[CurrentConstraint], onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr[CurrentConstraint]); return; - }*/ + } } else if (Mode==STATUS_SEEK_ADDITIONAL_CONTROLPOINTS){ - EditCurve[EditCurve.size()-1] = onSketchPos; + EditCurve[EditCurve.size()-1] = onSketchPos; - sketchgui->drawEdit(EditCurve); + sketchgui->drawEdit(EditCurve); - float length = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).Length(); - float angle = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).GetAngle(Base::Vector2d(1.f,0.f)); + float length = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).Length(); + float angle = (EditCurve[EditCurve.size()-1] - EditCurve[EditCurve.size()-2]).GetAngle(Base::Vector2d(1.f,0.f)); - SbString text; - text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); - setPositionText(EditCurve[EditCurve.size()-1], text); + SbString text; + text.sprintf(" (%.1f,%.1fdeg)", length, angle * 180 / M_PI); + setPositionText(EditCurve[EditCurve.size()-1], text); + + if (seekAutoConstraint(sugConstr[CurrentConstraint], onSketchPos, Base::Vector2d(0.f,0.f))) { + renderSuggestConstraintsCursor(sugConstr[CurrentConstraint]); + return; + } } applyCursor(); @@ -4368,20 +4375,27 @@ public: EditCurve[0] = onSketchPos; - Mode = STATUS_SEEK_ADDITIONAL_CONTROLPOINTS; + Mode = STATUS_SEEK_ADDITIONAL_CONTROLPOINTS; + + std::vector sugConstrN; + sugConstr.push_back(sugConstrN); + CurrentConstraint++; } else if (Mode == STATUS_SEEK_ADDITIONAL_CONTROLPOINTS) { - EditCurve[EditCurve.size()-1] = onSketchPos; - - // finish adding controlpoints on double click + EditCurve[EditCurve.size()-1] = onSketchPos; + + // finish adding controlpoints on double click if (EditCurve[EditCurve.size()-2] == EditCurve[EditCurve.size()-1]) { - EditCurve.pop_back(); - Mode = STATUS_CLOSE; + EditCurve.pop_back(); + Mode = STATUS_CLOSE; } else { - EditCurve.resize(EditCurve.size() + 1); // add one place for a pole - } + EditCurve.resize(EditCurve.size() + 1); // add one place for a pole + std::vector sugConstrN; + sugConstr.push_back(sugConstrN); + CurrentConstraint++; + } } return true; @@ -4397,10 +4411,10 @@ public: for (std::vector::const_iterator it=EditCurve.begin(); it != EditCurve.end(); ++it) { - stream << "App.Vector(" << (*it).x << "," << (*it).y << "),"; + stream << "App.Vector(" << (*it).x << "," << (*it).y << "),"; } - std::string controlpoints = stream.str(); + std::string controlpoints = stream.str(); // remove last comma and add brackets int index = controlpoints.rfind(','); @@ -4449,11 +4463,14 @@ public: Gui::Command::commitCommand(); - // add auto constraints - /*if (sugConstr1.size() > 0) { - createAutoConstraints(sugConstr1, currentgeoid+1, Sketcher::start); - sugConstr1.clear(); - }*/ + int poleindex=0; + for(std::vector>::iterator it=sugConstr.begin(); it != sugConstr.end(); it++, poleindex++) { + // add auto constraints + if ((*it).size() > 0) { + createAutoConstraints((*it), currentgeoid+1+poleindex, Sketcher::mid); + (*it).clear(); + } + } ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); bool autoRecompute = hGrp->GetBool("AutoRecompute",false); @@ -4488,7 +4505,9 @@ protected: std::vector EditCurve; - std::vector sugConstr1, sugConstr2; + std::vector> sugConstr; + + int CurrentConstraint; }; From 348d4cf320349a5a561624b7aa719ec562ba26cd Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 13 Jan 2017 22:24:55 +0100 Subject: [PATCH 24/38] Sketcher: Periodic bspline icons --- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 2 + .../Sketcher_Create_Periodic_BSpline.svg | 488 ++++++++++++++++++ ...ketcher_Create_Periodic_BSpline_Constr.svg | 484 +++++++++++++++++ 3 files changed, 974 insertions(+) create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline_Constr.svg diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 18b4ed798..a4141ec79 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -93,6 +93,8 @@ icons/Sketcher_CreateText.svg icons/Sketcher_CreateTriangle.svg icons/Sketcher_CreateTriangle_Constr.svg + icons/Sketcher_Create_Periodic_BSpline.svg + icons/Sketcher_Create_Periodic_BSpline_Constr.svg icons/Sketcher_DraftLine.svg icons/Sketcher_EditSketch.svg icons/Sketcher_Element_Arc_Edge.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline.svg new file mode 100644 index 000000000..be7873673 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline.svg @@ -0,0 +1,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline_Constr.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline_Constr.svg new file mode 100644 index 000000000..851eed083 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Create_Periodic_BSpline_Constr.svg @@ -0,0 +1,484 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0ef082bcd4ca5eac5d6ff1711e75d3dff37d5473 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 13 Jan 2017 22:25:10 +0100 Subject: [PATCH 25/38] Sketcher: Construction of periodic BSplines --- src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp | 2 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 158 +++++++++++++++++- src/Mod/Sketcher/Gui/Workbench.cpp | 5 +- 3 files changed, 156 insertions(+), 9 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp index 00e01ba98..c97b0aef3 100644 --- a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp +++ b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp @@ -88,7 +88,7 @@ CmdSketcherToggleConstruction::CmdSketcherToggleConstruction() rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateConic"); rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateCircle"); rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateRegularPolygon"); - rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CreateBSpline"); + rcCmdMgr.addCommandMode("ToggleConstruction", "Sketcher_CompCreateBSpline"); } void CmdSketcherToggleConstruction::activated(int iMsg) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index eeb44b8c1..3facec6ad 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4316,9 +4316,10 @@ static const char *cursor_createbspline[]={ class DrawSketchHandlerBSpline: public DrawSketchHandler { public: - DrawSketchHandlerBSpline() + DrawSketchHandlerBSpline(int constructionMethod) : Mode(STATUS_SEEK_FIRST_CONTROLPOINT) , EditCurve(2) + , ConstrMethod(constructionMethod) , CurrentConstraint(0) { std::vector sugConstr1; @@ -4432,10 +4433,11 @@ public: //Add arc of parabola Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.%s.addGeometry(Part.BSplineCurve" - "(%s)," + "(%s,%s)," "%s)", sketchgui->getObject()->getNameInDocument(), controlpoints.c_str(), + ConstrMethod == 0 ?"False":"True", geometryCreationMode==Construction?"True":"False"); currentgeoid++; @@ -4508,10 +4510,11 @@ protected: std::vector> sugConstr; int CurrentConstraint; + int ConstrMethod; }; -DEF_STD_CMD_AU(CmdSketcherCreateBSpline); +DEF_STD_CMD_A(CmdSketcherCreateBSpline); CmdSketcherCreateBSpline::CmdSketcherCreateBSpline() : Command("Sketcher_CreateBSpline") @@ -4529,10 +4532,10 @@ CmdSketcherCreateBSpline::CmdSketcherCreateBSpline() void CmdSketcherCreateBSpline::activated(int iMsg) { Q_UNUSED(iMsg); - ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerBSpline() ); + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerBSpline(0) ); } -void CmdSketcherCreateBSpline::updateAction(int mode) +/*void CmdSketcherCreateBSpline::updateAction(int mode) { switch (mode) { case Normal: @@ -4544,13 +4547,154 @@ void CmdSketcherCreateBSpline::updateAction(int mode) getAction()->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline_Constr")); break; } -} +}*/ bool CmdSketcherCreateBSpline::isActive(void) { return isCreateGeoActive(getActiveGuiDocument()); } +/// @brief Macro that declares a new sketcher command class 'CmdSketcherCreateBSpline' +DEF_STD_CMD_A(CmdSketcherCreatePeriodicBSpline); + +/** + * @brief ctor + */ +CmdSketcherCreatePeriodicBSpline::CmdSketcherCreatePeriodicBSpline() +: Command("Sketcher_CreatePeriodicBSpline") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create periodic B-Spline"); + sToolTipText = QT_TR_NOOP("Create a periodic B-Spline via control point in the sketch."); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_Create_Periodic_BSpline"; + eType = ForEdit; +} + +void CmdSketcherCreatePeriodicBSpline::activated(int iMsg) +{ + Q_UNUSED(iMsg); + ActivateHandler(getActiveGuiDocument(),new DrawSketchHandlerEllipse(1) ); +} + +bool CmdSketcherCreatePeriodicBSpline::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + + +/// @brief Macro that declares a new sketcher command class 'CmdSketcherCompCreateBSpline' +DEF_STD_CMD_ACLU(CmdSketcherCompCreateBSpline); + +/** + * @brief ctor + */ +CmdSketcherCompCreateBSpline::CmdSketcherCompCreateBSpline() +: Command("Sketcher_CompCreateBSpline") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Create a bspline"); + sToolTipText = QT_TR_NOOP("Create a bspline in the sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + eType = ForEdit; +} + +/** + * @brief Instantiates the bspline handler when the bspline command activated + * @param int iMsg + */ +void CmdSketcherCompCreateBSpline::activated(int iMsg) +{ + if (iMsg == 0) { + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerBSpline(iMsg)); + } else if (iMsg == 1) { + ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerBSpline(iMsg)); + } else { + return; + } + + // Since the default icon is reset when enabing/disabling the command we have + // to explicitly set the icon of the used command. + Gui::ActionGroup* pcAction = qobject_cast(_pcAction); + QList a = pcAction->actions(); + + assert(iMsg < a.size()); + pcAction->setIcon(a[iMsg]->icon()); +} + +Gui::Action * CmdSketcherCompCreateBSpline::createAction(void) +{ + Gui::ActionGroup* pcAction = new Gui::ActionGroup(this, Gui::getMainWindow()); + pcAction->setDropDownMenu(true); + applyCommandData(this->className(), pcAction); + + QAction* bspline = pcAction->addAction(QString()); + bspline->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline")); + + QAction* periodicbspline = pcAction->addAction(QString()); + periodicbspline->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Create_Periodic_BSpline")); + + _pcAction = pcAction; + languageChange(); + + // default + pcAction->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline")); + int defaultId = 0; + pcAction->setProperty("defaultAction", QVariant(defaultId)); + + return pcAction; +} + +void CmdSketcherCompCreateBSpline::updateAction(int mode) +{ + Gui::ActionGroup* pcAction = qobject_cast(getAction()); + if (!pcAction) + return; + + QList a = pcAction->actions(); + int index = pcAction->property("defaultAction").toInt(); + switch (mode) { + case Normal: + a[0]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline")); + a[1]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Create_Periodic_BSpline")); + getAction()->setIcon(a[index]->icon()); + break; + case Construction: + a[0]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_CreateBSpline_Constr")); + a[1]->setIcon(Gui::BitmapFactory().pixmap("Sketcher_Create_Periodic_BSpline_Constr")); + getAction()->setIcon(a[index]->icon()); + break; + } +} + +void CmdSketcherCompCreateBSpline::languageChange() +{ + Command::languageChange(); + + if (!_pcAction) + return; + Gui::ActionGroup* pcAction = qobject_cast(_pcAction); + QList a = pcAction->actions(); + + QAction* bspline = a[0]; + bspline->setText(QApplication::translate("Sketcher_CreateBSpline","BSpline by control points or poles")); + bspline->setToolTip(QApplication::translate("Sketcher_CreateBSpline","Create a BSpline by control points or poles")); + bspline->setStatusTip(QApplication::translate("Sketcher_CreateBSpline","Create a BSpline by control points or poles")); + QAction* periodicbspline = a[1]; + periodicbspline->setText(QApplication::translate("Sketcher_Create_Periodic_BSpline","Periodic BSpline by control points or poles")); + periodicbspline->setToolTip(QApplication::translate("Sketcher_Create_Periodic_BSpline","Create a periodic BSpline by control points or poles")); + periodicbspline->setStatusTip(QApplication::translate("Sketcher_Create_Periodic_BSpline","Create a periodic BSpline by control points or poles")); +} + +bool CmdSketcherCompCreateBSpline::isActive(void) +{ + return isCreateGeoActive(getActiveGuiDocument()); +} + // ====================================================================================== @@ -6620,6 +6764,8 @@ void CreateSketcherCommandsCreateGeo(void) rcCmdMgr.addCommand(new CmdSketcherCreateArcOfHyperbola()); rcCmdMgr.addCommand(new CmdSketcherCreateArcOfParabola()); rcCmdMgr.addCommand(new CmdSketcherCreateBSpline()); + rcCmdMgr.addCommand(new CmdSketcherCreatePeriodicBSpline()); + rcCmdMgr.addCommand(new CmdSketcherCompCreateBSpline()); rcCmdMgr.addCommand(new CmdSketcherCreateLine()); rcCmdMgr.addCommand(new CmdSketcherCreatePolyline()); rcCmdMgr.addCommand(new CmdSketcherCreateRectangle()); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 818b539d2..5779f0660 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -142,14 +142,15 @@ inline void SketcherAddWorkspaceArcs(Gui::MenuItem& geom){ << "Sketcher_CreateArcOfEllipse" << "Sketcher_CreateArcOfHyperbola" << "Sketcher_CreateArcOfParabola" - << "Sketcher_CreateBSpline"; + << "Sketcher_CreateBSpline" + << "Sketcher_CreatePeriodicBSpline"; } template <> inline void SketcherAddWorkspaceArcs(Gui::ToolBarItem& geom){ geom << "Sketcher_CompCreateArc" << "Sketcher_CompCreateCircle" << "Sketcher_CompCreateConic" - << "Sketcher_CreateBSpline"; + << "Sketcher_CompCreateBSpline"; } template void SketcherAddWorkspaceRegularPolygon(T& geom); From 1b59e745688d1f92f0d2f5a69cd3cc4deafccf14 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Fri, 13 Jan 2017 23:42:57 +0100 Subject: [PATCH 26/38] Sketcher: Solver Simplification for basic case ============================================== This commit is intended to allow to early merging to master of BSpline support. Parts of it will be reverted when a more advanced solver implementation is available. The intention is to have an advances solver implementation in the future. This commit cripples part of the potential functionality, but allows a very simplistic solver structure (no de Boor, no recursion). In particular: 1. Knots are not solver parameters and the solver acts as if such a parameter did not exist. 2. For non-periodic case, the start point and the endpoint coincide with the first pole and the last pole respectively. This is only valid under certain first and last knot multiplicity. If the user manually changes this multiplicities, the sketch will remain unsolved. For the periodic case, end and start points are not even solver parameters as an end and start point is an ilusion and we really do not care where that happens. It is not reasonable to ask the user to constrain where this point should be. --- src/Mod/Sketcher/App/Sketch.cpp | 51 ++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 6aad91d61..e83b63040 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -691,28 +691,44 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) std::vector sweights; for(std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it) { - params.push_back(new double( (*it) )); - sweights.push_back(params[params.size()-1]); + params.push_back(new double( (*it) )); + sweights.push_back(params[params.size()-1]); } std::vector sknots; for(std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it) { - params.push_back(new double( (*it) )); - sknots.push_back(params[params.size()-1]); + double * knot = new double( (*it) ); + //params.push_back(knot); + sknots.push_back(knot); } GCS::Point p1, p2; - 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]; + double * p1x = new double(startPnt.x); + double * p1y = new double(startPnt.y); - 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]; + // if periodic, startpoint and endpoint do not play a role in the solver, this removes unnecesarry DoF of determining where in the curve + // the start and the stop should be + if(!periodic) { + params.push_back(p1x); + params.push_back(p1y); + } + + p1.x = p1x; + p1.y = p1y; + + double * p2x = new double(endPnt.x); + double * p2y = new double(endPnt.y); + + // if periodic, startpoint and endpoint do not play a role in the solver, this removes unnecesarry DoF of determining where in the curve + // the start and the stop should be + if(!periodic) { + params.push_back(p2x); + params.push_back(p2y); + } + p2.x = p2x; + p2.y = p2y; def.startPointId = Points.size(); Points.push_back(p1); @@ -734,10 +750,13 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) // store complete set Geoms.push_back(def); - // arcs require an rule constraint for the end points - /*if (!fixed) - GCSsys.addConstraintArcOfParabolaRules(bs);*/ - + // WARNING: This is only valid where the multiplicity of the endpoints conforms with a BSpline + // only then the startpoint is the first control point and the endpoint is the last control point + // accordingly, it is never the case for a periodic BSpline. + if(!bs.periodic) { + GCSsys.addConstraintP2PCoincident(*(bs.poles.begin()),bs.start); + GCSsys.addConstraintP2PCoincident(*(bs.poles.end()-1),bs.end); + } // return the position of the newly added geometry return Geoms.size()-1; } From 512fd62c416318ecda240f3bfe28146b50da1e01 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 14 Jan 2017 01:23:04 +0100 Subject: [PATCH 27/38] Sketcher: Enable BSpline edge and enpoints movement --- src/Mod/Sketcher/App/Sketch.cpp | 60 ++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index e83b63040..2cece36a9 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -3008,6 +3008,41 @@ int Sketch::initMove(int geoId, PointPos pos, bool fine) GCSsys.rescaleConstraint(i-1, 0.01); GCSsys.rescaleConstraint(i, 0.01); + } + } else if (Geoms[geoId].type == BSpline) { + if (pos == start || pos == end) { + MoveParameters.resize(2); // x,y + GCS::Point p0; + p0.x = &MoveParameters[0]; + p0.y = &MoveParameters[1]; + if (pos == start) { + GCS::Point &p = Points[Geoms[geoId].startPointId]; + *p0.x = *p.x; + *p0.y = *p.y; + GCSsys.addConstraintP2PCoincident(p0,p,-1); + } else if (pos == end) { + GCS::Point &p = Points[Geoms[geoId].endPointId]; + *p0.x = *p.x; + *p0.y = *p.y; + GCSsys.addConstraintP2PCoincident(p0,p,-1); + } + } else if (pos == none || pos == mid) { + GCS::BSpline &bsp = BSplines[Geoms[geoId].index]; + MoveParameters.resize(bsp.poles.size()*2); // x0,y0,x1,y1,....xp,yp + + int mvindex = 0; + for(std::vector::iterator it = bsp.poles.begin(); it != bsp.poles.end() ; it++, mvindex++) { + GCS::Point p1; + p1.x = &MoveParameters[mvindex]; + mvindex++; + p1.y = &MoveParameters[mvindex]; + + *p1.x = *(*it).x; + *p1.y = *(*it).y; + + GCSsys.addConstraintP2PCoincident(p1,(*it),-1); + } + } } else if (Geoms[geoId].type == Arc) { GCS::Point ¢er = Points[Geoms[geoId].midPointId]; @@ -3116,7 +3151,30 @@ 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 == BSpline) { + if (pos == start || pos == end) { + MoveParameters[0] = toPoint.x; + MoveParameters[1] = toPoint.y; + } else if (pos == none || pos == mid) { + GCS::BSpline &bsp = BSplines[Geoms[geoId].index]; + + double cx = 0, cy = 0; // geometric center + for (int i=0; i < int(InitParameters.size()-1); i+=2) { + cx += InitParameters[i]; + cy += InitParameters[i+1]; + } + + cx /= bsp.poles.size(); + cy /= bsp.poles.size(); + + for (int i=0; i < int(MoveParameters.size()-1); i+=2) { + + MoveParameters[i] = toPoint.x + InitParameters[i] - cx; + MoveParameters[i+1] = toPoint.y + InitParameters[i+1] - cy; + } + + } + } return solve(); } From 9bf1e8f4f4cebf7b563abf916ead0c69f362217c Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 14 Jan 2017 19:33:40 +0100 Subject: [PATCH 28/38] Sketcher: BSpline box selection --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 34 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 0fe679e6e..b2f5621f2 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2346,9 +2346,37 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { const Part::GeomBSplineCurve *spline = static_cast(*it); - std::vector poles = spline->getPoles(); - VertexId += poles.size(); - // TODO + //std::vector poles = spline->getPoles(); + VertexId += 2; + + Plm.multVec(spline->getStartPoint(), pnt1); + Plm.multVec(spline->getEndPoint(), pnt2); + pnt1 = proj(pnt1); + pnt2 = proj(pnt2); + + bool pnt1Inside = polygon.Contains(Base::Vector2d(pnt1.x, pnt1.y)); + bool pnt2Inside = polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y)); + if (pnt1Inside) { + std::stringstream ss; + ss << "Vertex" << VertexId; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + + if (pnt2Inside) { + std::stringstream ss; + ss << "Vertex" << VertexId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } + + // This is a rather approximated approach. No it does not guarantie that the whole curve is boxed, specially + // for periodic curves, but it works reasonably well. Including all poles, which could be done, generally + // forces the user to select much more than the curve (all the poles) and it would not select the curve in cases + // where it is indeed comprised in the box. + if (pnt1Inside && pnt2Inside) { + std::stringstream ss; + ss << "Edge" << GeoId + 1; + Gui::Selection().addSelection(doc->getName(), sketchObject->getNameInDocument(), ss.str().c_str()); + } } } From e53dc90c9a18c25a1dc69d63bfd068bf751a8548 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sat, 14 Jan 2017 23:29:32 +0100 Subject: [PATCH 29/38] Sketcher: BSpline simplified endpoint tangency/perpendicularity solver implementation ===================================================================================== Support for tangency/perpendicularity using angle via point for BSpline with appropriate endpoint multiplicity so that the endpoints goes thru the first and last poles (control points). Warning: Not applicable to periodic BSplines. Warning: Not applicable to any non-periodic BSpline with inappropriate endpoint conditions. --- src/Mod/Sketcher/App/planegcs/Geo.cpp | 44 ++++++++++++++++++++- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 15 +++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/planegcs/Geo.cpp b/src/Mod/Sketcher/App/planegcs/Geo.cpp index ab30b0b23..71b236332 100644 --- a/src/Mod/Sketcher/App/planegcs/Geo.cpp +++ b/src/Mod/Sketcher/App/planegcs/Geo.cpp @@ -611,7 +611,49 @@ ArcOfParabola* ArcOfParabola::Copy() DeriVector2 BSpline::CalculateNormal(Point& p, double* derivparam) { // place holder - DeriVector2 ret = DeriVector2(); + DeriVector2 ret; + + if (mult[0] > degree && mult[mult.size()-1] > degree) { + // if endpoints thru end poles + if(*p.x == *start.x && *p.y == *start.y) { + // and you are asking about the normal at start point + // then tangency is defined by first to second poles + DeriVector2 endpt(this->poles[1], derivparam); + DeriVector2 spt(this->poles[0], derivparam); + DeriVector2 npt(this->poles[2], derivparam); // next pole to decide normal direction + + DeriVector2 tg = endpt.subtr(spt); + DeriVector2 nv = npt.subtr(spt); + + if ( tg.scalarProd(nv) > 0 ) + ret = tg.rotate90cw(); + else + ret = tg.rotate90ccw(); + } + else if(*p.x == *end.x && *p.y == *end.y) { + // and you are asking about the normal at end point + // then tangency is defined by last to last but one poles + DeriVector2 endpt(this->poles[poles.size()-1], derivparam); + DeriVector2 spt(this->poles[poles.size()-2], derivparam); + DeriVector2 npt(this->poles[poles.size()-3], derivparam); // next pole to decide normal direction + + DeriVector2 tg = endpt.subtr(spt); + DeriVector2 nv = npt.subtr(spt); + + if ( tg.scalarProd(nv) > 0 ) + ret = tg.rotate90ccw(); + else + ret = tg.rotate90cw(); + } else { + // another point and we have no clue until we implement De Boor + ret = DeriVector2(); + } + } + else { + // either periodic or abnormal endpoint multiplicity, we have no clue so currently unsupported + ret = DeriVector2(); + } + return ret; } diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 84165edd4..6554383fa 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -2298,6 +2298,21 @@ void CmdSketcherConstrainTangent::activated(int iMsg) return; } + // This code supports simple bspline endpoint tangency to any other geometric curve + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || + geom2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) { + std::swap(GeoId1,GeoId2); + std::swap(PosId1,PosId2); + } + // GeoId1 is the bspline now + } // end of code supports simple bspline endpoint tangency + openCommand("add tangent constraint"); Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d,%d)) ", From 340d33f3a5b19a768e752be99f6d7a672bb49b1d Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 00:57:05 +0100 Subject: [PATCH 30/38] Sketcher: BSpline - Informing the user of non-supported tangencies --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 6554383fa..1f9d4a338 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -2340,6 +2340,15 @@ void CmdSketcherConstrainTangent::activated(int iMsg) QObject::tr("Cannot add a tangency constraint at an unconnected point!")); return; } + + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom2 && geom2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ){ + // unsupported until tangent to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Tangency to BSpline edge currently unsupported.")); + return; + } openCommand("add tangent constraint"); Gui::Command::doCommand( @@ -2361,6 +2370,17 @@ void CmdSketcherConstrainTangent::activated(int iMsg) const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || + geom2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() )){ + + // unsupported until tangent to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Tangency to BSpline edge currently unsupported.")); + return; + } + + if( geom1 && geom2 && ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() )){ From 2eec558ce7699e3ef0458171e6c8d99e1ea61f51 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 01:27:46 +0100 Subject: [PATCH 31/38] Sketcher: BSpline - UI Perpendicularity --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 1f9d4a338..3614b189c 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1948,6 +1948,21 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) QObject::tr("Cannot add a perpendicularity constraint at an unconnected point!")); return; } + + // This code supports simple bspline endpoint perp to any other geometric curve + const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom1 && geom2 && + ( geom1->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || + geom2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() )){ + + if(geom1->getTypeId() != Part::GeomBSplineCurve::getClassTypeId()) { + std::swap(GeoId1,GeoId2); + std::swap(PosId1,PosId2); + } + // GeoId1 is the bspline now + } // end of code supports simple bspline endpoint tangency openCommand("add perpendicular constraint"); Gui::Command::doCommand( @@ -1976,6 +1991,15 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) QObject::tr("Cannot add a perpendicularity constraint at an unconnected point!")); return; } + + const Part::Geometry *geom2 = Obj->getGeometry(GeoId2); + + if( geom2 && geom2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ){ + // unsupported until normal to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Perpendicular to BSpline edge currently unsupported.")); + return; + } openCommand("add perpendicularity constraint"); Gui::Command::doCommand( @@ -1996,12 +2020,23 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("One of the selected edges should be a line.")); return; } + + if( geo1 && geo2 && + ( geo1->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || + geo2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() )){ + + // unsupported until tangent to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Perpendicular to BSpline edge currently unsupported.")); + return; + } if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) std::swap(GeoId1,GeoId2); From 6b5622a6611dceb19f853d6f59e8bfe6bd06d8d7 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 01:40:04 +0100 Subject: [PATCH 32/38] Sketcher: BSpline - Equality not supported user indication --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 3614b189c..2f14750af 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3201,8 +3201,16 @@ void CmdSketcherConstrainEqual::activated(int iMsg) else hasAlreadyExternal = true; } - + const Part::Geometry *geo = Obj->getGeometry(GeoId); + + if(geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + // unsupported as they are generally hereogeneus shapes + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Equality for BSpline edge currently unsupported.")); + return; + } + if (geo->getTypeId() != Part::GeomLineSegment::getClassTypeId()) lineSel = true; else if (geo->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) From 4da262dd3310f96bcbf903b9a1cbc038f8fc2b2f Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 01:49:45 +0100 Subject: [PATCH 33/38] Sketcher: BSpline solver improvement =================================== In the unusual event that endpoint knot multiplicity is edited, avoid trying to force the bspline end-point to match the corresponding control point (aka pole), as this leads to unsolvable sketches. --- src/Mod/Sketcher/App/Sketch.cpp | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 2cece36a9..b0f2ae6d5 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -678,14 +678,14 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) std::vector spoles; for(std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it){ - params.push_back(new double( (*it).x )); - params.push_back(new double( (*it).y )); - - GCS::Point p; - p.x = params[params.size()-2]; - p.y = params[params.size()-1]; - - spoles.push_back(p); + params.push_back(new double( (*it).x )); + params.push_back(new double( (*it).y )); + + GCS::Point p; + p.x = params[params.size()-2]; + p.y = params[params.size()-1]; + + spoles.push_back(p); } std::vector sweights; @@ -736,15 +736,15 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) Points.push_back(p2); GCS::BSpline bs; - bs.start = p1; - bs.end = p2; - bs.poles = spoles; - bs.weights = sweights; - bs.knots = sknots; - bs.mult = mult; - bs.degree = degree; - bs.periodic = periodic; - def.index = BSplines.size(); + bs.start = p1; + bs.end = p2; + bs.poles = spoles; + bs.weights = sweights; + bs.knots = sknots; + bs.mult = mult; + bs.degree = degree; + bs.periodic = periodic; + def.index = BSplines.size(); BSplines.push_back(bs); // store complete set @@ -753,7 +753,7 @@ int Sketch::addBSpline(const Part::GeomBSplineCurve &bspline, bool fixed) // WARNING: This is only valid where the multiplicity of the endpoints conforms with a BSpline // only then the startpoint is the first control point and the endpoint is the last control point // accordingly, it is never the case for a periodic BSpline. - if(!bs.periodic) { + if(!bs.periodic && bs.mult[0] > bs.degree && bs.mult[mult.size()-1] > bs.degree) { GCSsys.addConstraintP2PCoincident(*(bs.poles.begin()),bs.start); GCSsys.addConstraintP2PCoincident(*(bs.poles.end()-1),bs.end); } From c1decd3bb4b066fd98e24cda03f023a9d1baafb5 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 22:21:18 +0100 Subject: [PATCH 34/38] Sketcher: Enable relative movement of BSpline edge --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index b2f5621f2..7dd7b9ec4 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -1081,7 +1081,8 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor edit->DragCurve = edit->PreselectCurve; getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); - if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() || + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ) { relative = true; //xInit = x; //yInit = y; From f935f3334563337fc22a78290bdddcb493f2a8e1 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 22:29:21 +0100 Subject: [PATCH 35/38] Sketcher: BSpline point-on-object - unsupported --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 2f14750af..458e2ff30 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1362,6 +1362,16 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) } if (points[iPnt].GeoId == curves[iCrv].GeoId) continue; //constraining a point of an element onto the element is a bad idea... + + const Part::Geometry *geom = Obj->getGeometry(curves[iCrv].GeoId); + + if( geom && geom->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ){ + // unsupported until normal to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Point on BSpline edge currently unsupported.")); + continue; + } + cnt++; Gui::Command::doCommand( Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", From 2e789dc523463f22c730242b66c10cf8b238dadc Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Sun, 15 Jan 2017 22:34:14 +0100 Subject: [PATCH 36/38] Sketcher: BSpline SnellsLaw - unsupported --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 458e2ff30..2aaeac71d 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3517,6 +3517,15 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg) strError = QObject::tr("Incompatible geometry is selected!", dmbg); throw(Base::Exception("")); }; + + const Part::Geometry *geo = Obj->getGeometry(GeoId3); + + if( geo && geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ){ + // unsupported until normal to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("SnellsLaw on BSpline edge currently unsupported.")); + return; + } double n2divn1=0; From 252d84ff4f9ebcc969a487599dd80b9bcd1f5d16 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Mon, 16 Jan 2017 21:28:40 +0100 Subject: [PATCH 37/38] Sketcher: Array/Copy/Clone support for BSpline --- src/Mod/Sketcher/App/SketchObject.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index b83ec3f79..21d3233da 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -2632,7 +2632,22 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 if(it == geoIdList.begin()) iterfirstpoint = geoaoe->getStartPoint(true); - } + } + else if(geocopy->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()){ + Part::GeomBSplineCurve *geobsp = static_cast(geocopy); + + std::vector poles = geobsp->getPoles(); + + for(std::vector::iterator it = poles.begin(); it != poles.end(); ++it){ + + (*it) = (*it) + double(x)*displacement + double(y)*perpendicularDisplacement; + } + + geobsp->setPoles(poles); + + if(it == geoIdList.begin()) + iterfirstpoint = geobsp->getStartPoint(); + } else if(geocopy->getTypeId() == Part::GeomPoint::getClassTypeId()){ Part::GeomPoint *geopoint = static_cast(geocopy); Base::Vector3d cp = geopoint->getPoint(); From 46075f31ba6fd856b5dd70a01969a1bfadee7964 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Mon, 16 Jan 2017 21:47:03 +0100 Subject: [PATCH 38/38] Sketcher: Symmetry support for BSpline --- src/Mod/Sketcher/App/SketchObject.cpp | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 21d3233da..9847c1fdc 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -2140,6 +2140,20 @@ 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::GeomBSplineCurve::getClassTypeId()){ + Part::GeomBSplineCurve *geosymbsp = static_cast(geosym); + + std::vector poles = geosymbsp->getPoles(); + + for(std::vector::iterator it = poles.begin(); it != poles.end(); ++it){ + + (*it) = (*it) + 2.0*((*it).Perpendicular(refGeoLine->getStartPoint(),vectline)-(*it)); + } + + geosymbsp->setPoles(poles); + + 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(); @@ -2189,6 +2203,9 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, else if(georef->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()){ const Part::GeomArcOfParabola *geosymaoe = static_cast(georef); refpoint = geosymaoe->getStartPoint(true); + } else if(georef->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()){ + const Part::GeomBSplineCurve *geosymbsp = static_cast(georef); + refpoint = geosymbsp->getStartPoint(); } break; case Sketcher::end: @@ -2212,6 +2229,10 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, const Part::GeomArcOfParabola *geosymaoe = static_cast(georef); refpoint = geosymaoe->getEndPoint(true); } + else if(georef->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()){ + const Part::GeomBSplineCurve *geosymbsp = static_cast(georef); + refpoint = geosymbsp->getEndPoint(); + } break; case Sketcher::mid: if(georef->getTypeId() == Part::GeomCircle::getClassTypeId()){ @@ -2383,6 +2404,20 @@ 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::GeomBSplineCurve::getClassTypeId()){ + Part::GeomBSplineCurve *geosymbsp = static_cast(geosym); + + std::vector poles = geosymbsp->getPoles(); + + for(std::vector::iterator it = poles.begin(); it != poles.end(); ++it){ + + (*it) = (*it) + 2.0*(refpoint-(*it)); + } + + geosymbsp->setPoles(poles); + + //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();