diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp index 48470d748a..271c641629 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeCoinManager.cpp @@ -91,6 +91,8 @@ void EditModeCoinManager::ParameterObserver::initParameters() [this](const std::string & param){updateOverlayVisibilityParameter(param);}}, {"BSplinePoleWeightVisible", [this](const std::string & param){updateOverlayVisibilityParameter(param);}}, + {"ArcCircleHelperVisible", + [this](const std::string & param){updateOverlayVisibilityParameter(param);}}, {"TopRenderGeometryId", [this](const std::string & param){updateLineRenderingOrderParameters(param);}}, {"MidRenderGeometryId", @@ -208,6 +210,8 @@ void EditModeCoinManager::ParameterObserver::updateOverlayVisibilityParameter(co Client.overlayParameters.bSplineKnotMultiplicityVisible = hGrpsk->GetBool(parametername.c_str(), true); else if constexpr (visibilityparameter == OverlayVisibilityParameter::BSplinePoleWeightVisible) Client.overlayParameters.bSplinePoleWeightVisible = hGrpsk->GetBool(parametername.c_str(), true); + else if constexpr (visibilityparameter == OverlayVisibilityParameter::ArcCircleHelperVisible) + Client.overlayParameters.arcCircleHelperVisible = hGrpsk->GetBool(parametername.c_str(), true); Client.overlayParameters.visibleInformationChanged = true; } @@ -611,6 +615,11 @@ void EditModeCoinManager::processGeometryInformationOverlay(const GeoListFacade ioconv.convert(geo, geoid); } + for (auto geoid : analysisResults.arcGeoIds) { + const Part::Geometry *geo = geolistfacade.getGeometryFromGeoId(geoid); + ioconv.convert(geo, geoid); + } + overlayParameters.visibleInformationChanged = false; // just updated } diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManager.h b/src/Mod/Sketcher/Gui/EditModeCoinManager.h index 085ca3c6df..7ee9b842c2 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManager.h +++ b/src/Mod/Sketcher/Gui/EditModeCoinManager.h @@ -111,7 +111,8 @@ class SketcherGuiExport EditModeCoinManager BSplineControlPolygonVisible, BSplineCombVisible, BSplineKnotMultiplicityVisible, - BSplinePoleWeightVisible + BSplinePoleWeightVisible, + ArcCircleHelperVisible }; public: diff --git a/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h b/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h index 4820867c3e..d52ffece39 100644 --- a/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h +++ b/src/Mod/Sketcher/Gui/EditModeCoinManagerParameters.h @@ -257,6 +257,7 @@ struct AnalysisResults { // TODO: This needs to be refactored double combRepresentationScale = 0; // used for information overlay (BSpline comb) float boundingBoxMagnitudeOrder = 0; // used for grid extension std::vector bsplineGeoIds; // used for information overlay + std::vector arcGeoIds; }; /** @brief Struct adapted to store the parameters necessary to create and update @@ -273,6 +274,7 @@ struct OverlayParameters { bool bSplineCombVisible; bool bSplineKnotMultiplicityVisible; bool bSplinePoleWeightVisible; + bool arcCircleHelperVisible; }; /** @brief Struct adapted to store the parameters necessary to create and update diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp index 42a894bdcf..7cf401f677 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.cpp @@ -51,6 +51,7 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade & geol // measurements bsplineGeoIds.clear(); + arcGeoIds.clear(); // end information layer Coords.clear(); @@ -184,6 +185,7 @@ void EditModeGeometryCoinConverter::convert(const Sketcher::GeoListFacade & geol EditModeGeometryCoinConverter::CurveMode::OpenCurve, EditModeGeometryCoinConverter::AnalyseMode::BoundingBoxMagnitude>(geom, GeoId); setTracking(GeoId, coinLayer, EditModeGeometryCoinConverter::PointsMode::InsertStartEndMid, 1); + arcGeoIds.push_back(GeoId); } else if (type == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline (a bounded curve that is not a conic) convert< Part::GeomBSplineCurve, diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h index 0f0a7489bd..06ee5e49d2 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinConverter.h @@ -128,6 +128,11 @@ public: */ auto getBSplineGeoIds(){ return std::move(bsplineGeoIds);} + /** + * returns the GeoIds of Arc geometries + */ + auto getArcGeoIds(){ return std::move(arcGeoIds);} + private: template < typename GeoType, PointsMode pointmode, CurveMode curvemode, AnalyseMode analysemode > void convert(const Sketcher::GeometryFacade * geometryfacade, [[maybe_unused]] int geoId); @@ -159,6 +164,7 @@ private: float boundingBoxMaxMagnitude = 100; double combrepscale = 0; // the repscale that would correspond to this comb based only on this calculation. std::vector bsplineGeoIds; + std::vector arcGeoIds; }; diff --git a/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp index a3bc8f1b1b..1cbf51af34 100644 --- a/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeGeometryCoinManager.cpp @@ -111,6 +111,7 @@ void EditModeGeometryCoinManager::processGeometry(const GeoListFacade & geolistf analysisResults.combRepresentationScale = gcconv.getCombRepresentationScale(); analysisResults.boundingBoxMagnitudeOrder = exp(ceil(log(std::abs(gcconv.getBoundingBoxMaxMagnitude())))); analysisResults.bsplineGeoIds = gcconv.getBSplineGeoIds(); + analysisResults.arcGeoIds = gcconv.getArcGeoIds(); } void EditModeGeometryCoinManager::updateGeometryColor(const GeoListFacade & geolistfacade, bool issketchinvalid) diff --git a/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.cpp b/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.cpp index 3fd78714b9..8ea28d9b56 100644 --- a/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.cpp +++ b/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.cpp @@ -58,21 +58,25 @@ EditModeInformationOverlayCoinConverter::EditModeInformationOverlayCoinConverter void EditModeInformationOverlayCoinConverter::convert(const Part::Geometry * geometry, int geoid) { - // at this point all calculations relate to BSplineCurves - assert(geometry->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()); - - calculate(geometry, geoid); - calculate(geometry, geoid); - calculate(geometry, geoid); - calculate(geometry, geoid); - calculate(geometry, geoid); - - addUpdateNode(degree); - addUpdateNode(controlPolygon); - addUpdateNode(curvatureComb); - addUpdateNode(knotMultiplicity); - addUpdateNode(poleWeights); + if (geometry->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()){ + // at this point all calculations relate to BSplineCurves + calculate(geometry, geoid); + calculate(geometry, geoid); + calculate(geometry, geoid); + calculate(geometry, geoid); + calculate(geometry, geoid); + addUpdateNode(degree); + addUpdateNode(controlPolygon); + addUpdateNode(curvatureComb); + addUpdateNode(knotMultiplicity); + addUpdateNode(poleWeights); + } else if (geometry->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + // at this point all calculations relate to ArcOfCircle + calculate(geometry, geoid); + addUpdateNode(circleHelper); + } else + assert(false /* Not implemented */); }; void EditModeInformationOverlayCoinConverter::addToInfoGroup(SoSwitch * sw) { @@ -82,167 +86,188 @@ void EditModeInformationOverlayCoinConverter::addToInfoGroup(SoSwitch * sw) { template < EditModeInformationOverlayCoinConverter::CalculationType calculation > void EditModeInformationOverlayCoinConverter::calculate(const Part::Geometry * geometry, [[maybe_unused]] int geoid) { - const Part::GeomBSplineCurve *spline = static_cast(geometry); - if constexpr (calculation == CalculationType::BSplineDegree ) { - clearCalculation(degree); + if constexpr (calculation == CalculationType::ArcCircleHelper ) { + const Part::GeomArcOfCircle *arc = static_cast(geometry); + clearCalculation(circleHelper); - std::vector poles = spline->getPoles(); + Base::Vector3d center = arc->getCenter(); + double radius = arc->getRadius(); + Part::GeomCircle circle; + circle.setRadius(radius); + circle.setCenter(center); - degree.strings.clear(); - degree.positions.clear(); + const int ndiv = drawingParameters.curvedEdgeCountSegments; - Base::Vector3d midp = Base::Vector3d(0,0,0); + circleHelper.coordinates.reserve(ndiv); + for (int i = 0; i < ndiv; i++) { + double param = i * std::atan(1) * 8 / ndiv; + circleHelper.coordinates.emplace_back(circle.value(param)); + } + circleHelper.coordinates.emplace_back(circle.value(0.0)); + circleHelper.indices.push_back(ndiv + 1); + } else { + const Part::GeomBSplineCurve *spline = static_cast(geometry); - for (auto val : poles) - midp += val; + if constexpr (calculation == CalculationType::BSplineDegree ) { + clearCalculation(degree); - midp /= poles.size(); + std::vector poles = spline->getPoles(); - degree.strings.emplace_back(std::to_string(spline->getDegree())); - degree.positions.emplace_back(midp); - } - else if constexpr (calculation == CalculationType::BSplineControlPolygon ) { + degree.strings.clear(); + degree.positions.clear(); - clearCalculation(controlPolygon); + Base::Vector3d midp = Base::Vector3d(0,0,0); - std::vector poles = spline->getPoles(); + for (auto val : poles) + midp += val; - controlPolygon.coordinates.clear(); - controlPolygon.indices.clear(); + midp /= poles.size(); - size_t nvertices; + degree.strings.emplace_back(std::to_string(spline->getDegree())); + degree.positions.emplace_back(midp); + } + else if constexpr (calculation == CalculationType::BSplineControlPolygon ) { - if (spline->isPeriodic()) - nvertices = poles.size()+1; - else - nvertices = poles.size(); + clearCalculation(controlPolygon); - controlPolygon.coordinates.reserve(nvertices); + std::vector poles = spline->getPoles(); - for (auto & v : poles) - controlPolygon.coordinates.emplace_back(v); + controlPolygon.coordinates.clear(); + controlPolygon.indices.clear(); - if (spline->isPeriodic()) - controlPolygon.coordinates.emplace_back(poles[0]); + size_t nvertices; - controlPolygon.indices.push_back(nvertices); // single continuous polygon starting at index 0 - } - else if constexpr (calculation == CalculationType::BSplineCurvatureComb ) { + if (spline->isPeriodic()) + nvertices = poles.size()+1; + else + nvertices = poles.size(); - clearCalculation(curvatureComb); - // curvature graph -------------------------------------------------------- + controlPolygon.coordinates.reserve(nvertices); - // based on python source - // https://github.com/tomate44/CurvesWB/blob/master/freecad/Curves/ParametricComb.py - // by FreeCAD user Chris_G + for (auto & v : poles) + controlPolygon.coordinates.emplace_back(v); - std::vector poles = spline->getPoles(); - auto knots = spline->getKnots(); - auto mults = spline->getMultiplicities(); + if (spline->isPeriodic()) + controlPolygon.coordinates.emplace_back(poles[0]); - const int ndivPerPiece = 64; // heuristic of number of division to fill in - const int ndiv = ndivPerPiece * (knots.size() - 1); + controlPolygon.indices.push_back(nvertices); // single continuous polygon starting at index 0 + } + else if constexpr (calculation == CalculationType::BSplineCurvatureComb ) { - std::vector pointatcurvelist; - std::vector curvaturelist; - std::vector normallist; + clearCalculation(curvatureComb); + // curvature graph -------------------------------------------------------- - pointatcurvelist.reserve(ndiv); - curvaturelist.reserve(ndiv); - normallist.reserve(ndiv); + // based on python source + // https://github.com/tomate44/CurvesWB/blob/master/freecad/Curves/ParametricComb.py + // by FreeCAD user Chris_G - // go through the polynomial pieces (i.e. from one knot to next) - for (size_t k = 0; k < knots.size()-1; ++k) { - // first and last params are a little off to account for possible discontinuity at knots - double firstparam = knots[k] + Precision::Approximation()*(knots[k + 1] - knots[k]); - double lastparam = knots[k + 1] - Precision::Approximation()*(knots[k + 1] - knots[k]); + std::vector poles = spline->getPoles(); + auto knots = spline->getKnots(); + auto mults = spline->getMultiplicities(); - // TODO: Maybe this can be improved, specifically adapted for each piece - double step = (lastparam - firstparam) / (ndivPerPiece - 1); + const int ndivPerPiece = 64; // heuristic of number of division to fill in + const int ndiv = ndivPerPiece * (knots.size() - 1); - for (int i = 0; i < ndivPerPiece; ++i) { - double param = firstparam + i * step; - pointatcurvelist.emplace_back(spline->value(param)); + std::vector pointatcurvelist; + std::vector curvaturelist; + std::vector normallist; - try { - curvaturelist.emplace_back(spline->curvatureAt(param)); - } - catch(Base::CADKernelError &e) { - // it is "just" a visualisation matter OCC could not calculate the curvature - // terminating here would mean that the other shapes would not be drawn. - // Solution: Report the issue and set dummy curvature to 0 - e.ReportException(); - Base::Console().Error("Curvature graph for B-Spline with GeoId=%d could not be calculated.\n", geoid); - curvaturelist.emplace_back(0); - } + pointatcurvelist.reserve(ndiv); + curvaturelist.reserve(ndiv); + normallist.reserve(ndiv); - Base::Vector3d normal; - try { - spline->normalAt(param, normal); - normallist.emplace_back(normal); - } - catch(Base::Exception&) { - normallist.emplace_back(0,0,0); + // go through the polynomial pieces (i.e. from one knot to next) + for (size_t k = 0; k < knots.size()-1; ++k) { + // first and last params are a little off to account for possible discontinuity at knots + double firstparam = knots[k] + Precision::Approximation()*(knots[k + 1] - knots[k]); + double lastparam = knots[k + 1] - Precision::Approximation()*(knots[k + 1] - knots[k]); + + // TODO: Maybe this can be improved, specifically adapted for each piece + double step = (lastparam - firstparam) / (ndivPerPiece - 1); + + for (int i = 0; i < ndivPerPiece; ++i) { + double param = firstparam + i * step; + pointatcurvelist.emplace_back(spline->value(param)); + + try { + curvaturelist.emplace_back(spline->curvatureAt(param)); + } + catch(Base::CADKernelError &e) { + // it is "just" a visualisation matter OCC could not calculate the curvature + // terminating here would mean that the other shapes would not be drawn. + // Solution: Report the issue and set dummy curvature to 0 + e.ReportException(); + Base::Console().Error("Curvature graph for B-Spline with GeoId=%d could not be calculated.\n", geoid); + curvaturelist.emplace_back(0); + } + + Base::Vector3d normal; + try { + spline->normalAt(param, normal); + normallist.emplace_back(normal); + } + catch(Base::Exception&) { + normallist.emplace_back(0,0,0); + } } } + + std::vector pointatcomblist; + pointatcomblist.reserve(ndiv); + + for (int i = 0; i < ndiv; i++) { + pointatcomblist.emplace_back(pointatcurvelist[i] - overlayParameters.currentBSplineCombRepresentationScale * curvaturelist[i] * normallist[i]); + } + + curvatureComb.coordinates.reserve(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment + curvatureComb.indices.reserve(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end + + auto zInfoH = ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider) * drawingParameters.zInfo; + + for (int i = 0; i < ndiv; i++) { + // note emplace emplaces on the position BEFORE the iterator given. + curvatureComb.coordinates.emplace_back(pointatcurvelist[i].x, pointatcurvelist[i].y, zInfoH); // radials + curvatureComb.coordinates.emplace_back(pointatcomblist[i].x, pointatcomblist[i].y, zInfoH); // radials + + curvatureComb.indices.emplace_back(2); // line + } + + for (int i = 0; i < ndiv; i++) + curvatureComb.coordinates.emplace_back(pointatcomblist[i].x, pointatcomblist[i].y, zInfoH); // // comb endpoint closing segment + + curvatureComb.indices.emplace_back(ndiv); // Comb line } + else if constexpr (calculation == CalculationType::BSplineKnotMultiplicity ) { - std::vector pointatcomblist; - pointatcomblist.reserve(ndiv); + clearCalculation(knotMultiplicity); + std::vector knots = spline->getKnots(); + std::vector mult = spline->getMultiplicities(); - for (int i = 0; i < ndiv; i++) { - pointatcomblist.emplace_back(pointatcurvelist[i] - overlayParameters.currentBSplineCombRepresentationScale * curvaturelist[i] * normallist[i]); + for (size_t i=0; ipointAtParameter(knots[i])); + + std::ostringstream stringStream; + stringStream << "(" << mult[i] << ")"; + + knotMultiplicity.strings.emplace_back( stringStream.str()); + } } + else if constexpr (calculation == CalculationType::BSplinePoleWeight ) { - curvatureComb.coordinates.reserve(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment - curvatureComb.indices.reserve(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end + clearCalculation(poleWeights); + std::vector poles = spline->getPoles(); + auto weights = spline->getWeights(); - auto zInfoH = ViewProviderSketchCoinAttorney::getViewOrientationFactor(viewProvider) * drawingParameters.zInfo; + for (size_t i=0; i knots = spline->getKnots(); - std::vector mult = spline->getMultiplicities(); - - for (size_t i=0; ipointAtParameter(knots[i])); - - std::ostringstream stringStream; - stringStream << "(" << mult[i] << ")"; - - knotMultiplicity.strings.emplace_back( stringStream.str()); + poleWeights.strings.emplace_back(WeightString.toStdString()); + } } } - else if constexpr (calculation == CalculationType::BSplinePoleWeight ) { - - clearCalculation(poleWeights); - std::vector poles = spline->getPoles(); - auto weights = spline->getWeights(); - - for (size_t i=0; i @@ -271,6 +296,9 @@ bool EditModeInformationOverlayCoinConverter::isVisible() { else if constexpr ( calculation == CalculationType::BSplinePoleWeight ) { return overlayParameters.bSplinePoleWeightVisible; } + else if constexpr ( calculation == CalculationType::ArcCircleHelper ) { + return overlayParameters.arcCircleHelperVisible; + } } template < typename Result > @@ -367,7 +395,7 @@ void EditModeInformationOverlayCoinConverter::addNode(const Result & result) { sep->addChild(mat); sep->addChild(font); - sep->addChild(translate); + sep->addChild(translate); sep->addChild(text); sw->addChild(sep); diff --git a/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.h b/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.h index a2373c1596..ba9af8a173 100644 --- a/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.h +++ b/src/Mod/Sketcher/Gui/EditModeInformationOverlayCoinConverter.h @@ -64,7 +64,7 @@ namespace SketcherGui { * addUpdateNode is responsible for creating or updating the node structure (depending on overlayParameters.rebuildInformationLayer) * * Supported: - * Currently it only supports information of Part::Geometry objects and implements calculations only for GeomBSplineCurve. + * Currently it only supports information of Part::Geometry objects and implements calculations only for GeomBSplineCurve and GeomArc. * * Caveats: * - This class relies on the order of creation to perform the update. Any parallel execution that does not deterministically @@ -81,7 +81,8 @@ private: BSplineControlPolygon, BSplineCurvatureComb, BSplineKnotMultiplicity, - BSplinePoleWeight + BSplinePoleWeight, + ArcCircleHelper }; enum class VisualisationType { @@ -196,6 +197,7 @@ private: NodeText poleWeights; NodePolygon controlPolygon; NodePolygon curvatureComb; + NodePolygon circleHelper; // Node Management int nodeId;