From c9b11eac574f71b147c8441f2b97ba7ed3ebed5a Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 30 Sep 2019 15:43:54 +0300 Subject: [PATCH] Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003) Projection of elliptic arcs --- src/GeomAPI/GeomAPI_Circ.cpp | 3 +- src/GeomAPI/GeomAPI_Curve.cpp | 46 +++- src/GeomAPI/GeomAPI_Curve.h | 4 +- src/GeomAPI/GeomAPI_Ellipse.cpp | 3 +- src/GeomAlgoAPI/GeomAlgoAPI_Projection.h | 6 +- src/SketchPlugin/SketchPlugin_Projection.cpp | 260 ++++++++++++------ src/SketchPlugin/SketchPlugin_Projection.h | 8 +- src/SketchPlugin/SketchPlugin_Validators.cpp | 6 +- .../Test/TestProjectionEllipse.py | 5 +- 9 files changed, 236 insertions(+), 105 deletions(-) diff --git a/src/GeomAPI/GeomAPI_Circ.cpp b/src/GeomAPI/GeomAPI_Circ.cpp index facc1ec2a..a3bb8d97a 100644 --- a/src/GeomAPI/GeomAPI_Circ.cpp +++ b/src/GeomAPI/GeomAPI_Circ.cpp @@ -58,7 +58,8 @@ GeomAPI_Circ::GeomAPI_Circ(const std::shared_ptr& theCenter, //================================================================================================= GeomAPI_Circ::GeomAPI_Circ(const GeomCurvePtr& theCurve) { - Handle(Geom_Curve) aCurve = theCurve->impl(); + GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve(); + Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl(); Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast(aCurve); if (aCirc.IsNull()) throw Standard_ConstructionError("GeomAPI_Circ: Curve is not a circle"); diff --git a/src/GeomAPI/GeomAPI_Curve.cpp b/src/GeomAPI/GeomAPI_Curve.cpp index dd3c57c27..fb5f034ab 100644 --- a/src/GeomAPI/GeomAPI_Curve.cpp +++ b/src/GeomAPI/GeomAPI_Curve.cpp @@ -35,7 +35,9 @@ #define MY_CURVE (*(implPtr())) GeomAPI_Curve::GeomAPI_Curve() - : GeomAPI_Interface(new Handle_Geom_Curve()), myStart(0), myEnd(1) + : GeomAPI_Interface(new Handle_Geom_Curve()), + myStart(-Precision::Infinite()), + myEnd(Precision::Infinite()) { } @@ -47,6 +49,8 @@ GeomAPI_Curve::GeomAPI_Curve(const std::shared_ptr& theShape) if (!anEdge.IsNull()) { Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, myStart, myEnd); if (!aCurve.IsNull()) { + if (!BRep_Tool::IsClosed(anEdge)) + aCurve = new Geom_TrimmedCurve(aCurve, myStart, myEnd); setImpl(new Handle(Geom_Curve)(aCurve)); } } @@ -57,19 +61,53 @@ bool GeomAPI_Curve::isNull() const return MY_CURVE.IsNull() == Standard_True; } +static bool isCurveType(const Handle(Geom_Curve)& theCurve, const Handle(Standard_Type)& theType) +{ + if (theCurve.IsNull()) + return false; + Handle(Geom_Curve) aCurve = theCurve; + if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + return aCurve->DynamicType() == theType; +} + bool GeomAPI_Curve::isLine() const { - return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_Line); + return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Line)); } bool GeomAPI_Curve::isCircle() const { - return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_Circle); + return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Circle)); } bool GeomAPI_Curve::isEllipse() const { - return !isNull() && MY_CURVE->DynamicType() == STANDARD_TYPE(Geom_Ellipse); + return isCurveType(MY_CURVE, STANDARD_TYPE(Geom_Ellipse)); +} + +double GeomAPI_Curve::startParam() +{ + if (Precision::IsInfinite(myStart)) { + if (isTrimmed()) { + myStart = Handle(Geom_TrimmedCurve)::DownCast(MY_CURVE)->FirstParameter(); + } + else if (MY_CURVE->IsClosed() && MY_CURVE->IsPeriodic()) + myStart = 0.0; + } + return myStart; +} + +double GeomAPI_Curve::endParam() +{ + if (Precision::IsInfinite(myEnd)) { + if (isTrimmed()) { + myEnd = Handle(Geom_TrimmedCurve)::DownCast(MY_CURVE)->LastParameter(); + } + else if (MY_CURVE->IsClosed() && MY_CURVE->IsPeriodic()) + myEnd = MY_CURVE->Period(); + } + return myEnd; } std::shared_ptr GeomAPI_Curve::getPoint(double theParam) diff --git a/src/GeomAPI/GeomAPI_Curve.h b/src/GeomAPI/GeomAPI_Curve.h index 5cdf1db89..3922217f1 100644 --- a/src/GeomAPI/GeomAPI_Curve.h +++ b/src/GeomAPI/GeomAPI_Curve.h @@ -63,11 +63,11 @@ class GeomAPI_Curve : public GeomAPI_Interface /// Returns start parameter of the curve GEOMAPI_EXPORT - double startParam() const { return myStart; } + double startParam(); /// Returns end parameter of the curve GEOMAPI_EXPORT - double endParam() const { return myEnd; } + double endParam(); /// Returns \c true if the curve is trimmed GEOMAPI_EXPORT diff --git a/src/GeomAPI/GeomAPI_Ellipse.cpp b/src/GeomAPI/GeomAPI_Ellipse.cpp index 86a0391cb..75a25477c 100644 --- a/src/GeomAPI/GeomAPI_Ellipse.cpp +++ b/src/GeomAPI/GeomAPI_Ellipse.cpp @@ -41,7 +41,8 @@ GeomAPI_Ellipse::GeomAPI_Ellipse(const std::shared_ptr& theAx2, GeomAPI_Ellipse::GeomAPI_Ellipse(GeomCurvePtr theCurve) { - Handle(Geom_Curve) aCurve = theCurve->impl(); + GeomCurvePtr anUntrimmedCurve = theCurve->basisCurve(); + Handle(Geom_Curve) aCurve = anUntrimmedCurve->impl(); Handle(Geom_Ellipse) anEllipse = Handle(Geom_Ellipse)::DownCast(aCurve); if (anEllipse.IsNull()) throw Standard_ConstructionError("GeomAPI_Ellipse: Curve is not an ellipse"); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h index 5ffde6371..4aeca665b 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Projection.h @@ -33,14 +33,16 @@ class GeomAPI_Edge; * \ingroup DataAlgo * \brief Project curve onto a plane */ -class GEOMALGOAPI_EXPORT GeomAlgoAPI_Projection +class GeomAlgoAPI_Projection { public: - GeomAlgoAPI_Projection(const std::shared_ptr& thePlane); + GEOMALGOAPI_EXPORT GeomAlgoAPI_Projection(const std::shared_ptr& thePlane); /// Project curve to the plane + GEOMALGOAPI_EXPORT std::shared_ptr project(const std::shared_ptr& theCurve); /// Project edge to the plane + GEOMALGOAPI_EXPORT std::shared_ptr project(const std::shared_ptr& theEdge); private: diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp index c0d555059..79eb675ca 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.cpp +++ b/src/SketchPlugin/SketchPlugin_Projection.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,22 +105,59 @@ void SketchPlugin_Projection::attributeChanged(const std::string& theID) } } -static const std::string& projectionType(GeomEdgePtr theEdge, - GeomVertexPtr theVertex) +static const std::set& POINT_PROJECTION() +{ + static std::set aProj; + if (aProj.empty()) + aProj.insert(SketchPlugin_Point::ID()); + return aProj; +} + +static const std::set& LINE_PROJECTION() +{ + static std::set aProj; + if (aProj.empty()) + aProj.insert(SketchPlugin_Line::ID()); + return aProj; +} + +static const std::set& CIRCLE_ELLIPSE_PROJECTION() +{ + static std::set aProj; + if (aProj.empty()) { + aProj.insert(SketchPlugin_Circle::ID()); + aProj.insert(SketchPlugin_Ellipse::ID()); + } + return aProj; +} + +static const std::set& ARC_PROJECTION() +{ + static std::set aProj; + if (aProj.empty()) { + aProj.insert(SketchPlugin_Arc::ID()); + aProj.insert(SketchPlugin_EllipticArc::ID()); + } + return aProj; +} + + +static const std::set& possibleProjectionTypes(GeomEdgePtr theEdge, + GeomVertexPtr theVertex) { if (theVertex) - return SketchPlugin_Point::ID(); + return POINT_PROJECTION(); if (theEdge) { if (theEdge->isLine()) - return SketchPlugin_Line::ID(); - else if (theEdge->isCircle()) - return SketchPlugin_Circle::ID(); - else if (theEdge->isArc()) - return SketchPlugin_Arc::ID(); - else if (theEdge->isEllipse()) - return SketchPlugin_Ellipse::ID(); + return LINE_PROJECTION(); + else if (theEdge->isCircle() || theEdge->isArc() || theEdge->isEllipse()) { + if (theEdge->isClosed()) + return CIRCLE_ELLIPSE_PROJECTION(); + else + return ARC_PROJECTION(); + } } - static const std::string DUMMY; + static const std::set DUMMY; return DUMMY; } @@ -144,7 +182,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) if (!anEdge && !aVertex) return; - const std::string& aProjType = projectionType(anEdge, aVertex); + const std::set& aProjType = possibleProjectionTypes(anEdge, aVertex); AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID()); FeaturePtr aProjection; @@ -152,7 +190,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) aProjection = ModelAPI_Feature::feature(aRefAttr->object()); // if the type of feature differs with already selected, remove it and create once again - bool isRebuild = rebuildProjectedFeature(aProjection, aProjType, true); + bool isRebuild = rebuildProjectedFeature(aProjection, aProjType); std::shared_ptr aSketchPlane = sketch()->plane(); @@ -170,7 +208,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) std::shared_ptr aPrjPnt = aSketchPlane->project(aVertex->point()); std::shared_ptr aPntInSketch = sketch()->to2D(aPrjPnt); - rebuildProjectedFeature(aProjection, SketchPlugin_Point::ID()); + rebuildProjectedFeature(aProjection, POINT_PROJECTION(), SketchPlugin_Point::ID()); // update coordinates of projection std::dynamic_pointer_cast( @@ -185,7 +223,7 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) if (aFirstInSketch->distance(aLastInSketch) < tolerance) return; // line is semi-orthogonal to the sketch plane - rebuildProjectedFeature(aProjection, SketchPlugin_Line::ID()); + rebuildProjectedFeature(aProjection, LINE_PROJECTION(), SketchPlugin_Line::ID()); // update attributes of projection std::shared_ptr aStartPnt = std::dynamic_pointer_cast( @@ -195,84 +233,127 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) aStartPnt->setValue(aFirstInSketch); aEndPnt->setValue(aLastInSketch); } - else if (anEdge->isCircle() || anEdge->isEllipse()) { + else if (anEdge->isCircle() || anEdge->isArc() || anEdge->isEllipse()) { GeomAlgoAPI_Projection aProjAlgo(aSketchPlane); GeomCurvePtr aProjectedCurve = aProjAlgo.project(anEdge); if (aProjectedCurve->isCircle()) { - rebuildProjectedFeature(aProjection, SketchPlugin_Circle::ID()); - GeomAPI_Circ aCircle(aProjectedCurve); - std::shared_ptr aCenter = aSketchPlane->project(aCircle.center()); - std::shared_ptr aCenterInSketch = sketch()->to2D(aCenter); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Circle::CENTER_ID())); - aCenterPnt->setValue(aCenterInSketch); - aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius()); + GeomPointPtr aCenter = aSketchPlane->project(aCircle.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + + if (aProjectedCurve->isTrimmed()) { + // ARC is a projection + rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID()); + + GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam()); + GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam()); + GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst)); + GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast)); + + double aNormalsDot = aCircle.normal()->dot(aSketchPlane->direction()); + if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) + return; // arc is not in the plane, parallel to the sketch plane + + bool isInversed = aNormalsDot < 0.; + + bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Arc::CENTER_ID())); + std::shared_ptr aStartPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Arc::END_ID())); + aStartPnt->setValue(aFirstInSketch); + aEndPnt->setValue(aLastInSketch); + aCenterPnt->setValue(aCenterInSketch); + aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed); + + aProjection->data()->blockSendAttributeUpdated(aWasBlocked); + } + else { + // CIRCLE is a projection + rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(), + SketchPlugin_Circle::ID()); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Circle::CENTER_ID())); + aCenterPnt->setValue(aCenterInSketch); + aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius()); + } } else if (aProjectedCurve->isEllipse()) { - rebuildProjectedFeature(aProjection, SketchPlugin_Ellipse::ID()); - GeomAPI_Ellipse anEllipse(aProjectedCurve); - std::shared_ptr aCenter = aSketchPlane->project(anEllipse.center()); - std::shared_ptr aCenterInSketch = sketch()->to2D(aCenter); - std::shared_ptr aFocus = aSketchPlane->project(anEllipse.firstFocus()); - std::shared_ptr aFocusInSketch = sketch()->to2D(aFocus); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID())); - aCenterPnt->setValue(aCenterInSketch); - std::shared_ptr aFocusPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID())); - aFocusPnt->setValue(aFocusInSketch); - aProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue( - anEllipse.minorRadius()); + GeomPointPtr aCenter = aSketchPlane->project(anEllipse.center()); + GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter); + GeomPointPtr aFocus = aSketchPlane->project(anEllipse.firstFocus()); + GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus); + + if (aProjectedCurve->isTrimmed()) { + // ELLIPTIC ARC is a projection + rebuildProjectedFeature(aProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID()); + + GeomPointPtr aFirst = aProjectedCurve->getPoint(aProjectedCurve->startParam()); + GeomPointPtr aLast = aProjectedCurve->getPoint(aProjectedCurve->endParam()); + GeomPnt2dPtr aFirstInSketch = sketch()->to2D(aSketchPlane->project(aFirst)); + GeomPnt2dPtr aLastInSketch = sketch()->to2D(aSketchPlane->project(aLast)); + + double aNormalsDot = anEllipse.normal()->dot(aSketchPlane->direction()); + if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) + return; // arc is not in the plane, parallel to the sketch plane + + bool isInversed = aNormalsDot < 0.; + + bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID())); + std::shared_ptr aFocusPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())); + std::shared_ptr aStartPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID())); + std::shared_ptr aEndPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID())); + aStartPnt->setValue(aFirstInSketch); + aEndPnt->setValue(aLastInSketch); + aCenterPnt->setValue(aCenterInSketch); + aFocusPnt->setValue(aFocusInSketch); + aProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed); + + aProjection->data()->blockSendAttributeUpdated(aWasBlocked); + } + else { + // ELLIPSE is a projection + rebuildProjectedFeature(aProjection, CIRCLE_ELLIPSE_PROJECTION(), + SketchPlugin_Ellipse::ID()); + + // update attributes of projection + std::shared_ptr aCenterPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Ellipse::CENTER_ID())); + aCenterPnt->setValue(aCenterInSketch); + std::shared_ptr aFocusPnt = + std::dynamic_pointer_cast( + aProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID())); + aFocusPnt->setValue(aFocusInSketch); + aProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue( + anEllipse.minorRadius()); + } } else return; - } - else if (anEdge->isArc()) { - std::shared_ptr aFirst = aSketchPlane->project(anEdge->firstPoint()); - std::shared_ptr aLast = aSketchPlane->project(anEdge->lastPoint()); - std::shared_ptr aFirstInSketch = sketch()->to2D(aFirst); - std::shared_ptr aLastInSketch = sketch()->to2D(aLast); - - std::shared_ptr aCircle = anEdge->circle(); - std::shared_ptr aCenter = aSketchPlane->project(aCircle->center()); - std::shared_ptr aCenterInSketch = sketch()->to2D(aCenter); - - double aNormalsDot = aCircle->normal()->dot(aSketchPlane->direction()); - if (fabs(fabs(aNormalsDot) - 1.0) > tolerance) - return; // arc is not in the plane, parallel to the sketch plane - - bool isInversed = aNormalsDot < 0.; - - rebuildProjectedFeature(aProjection, SketchPlugin_Arc::ID()); - - bool aWasBlocked = aProjection->data()->blockSendAttributeUpdated(true); - - // update attributes of projection - std::shared_ptr aCenterPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStartPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndPnt = - std::dynamic_pointer_cast( - aProjection->attribute(SketchPlugin_Arc::END_ID())); - aStartPnt->setValue(aFirstInSketch); - aEndPnt->setValue(aLastInSketch); - aCenterPnt->setValue(aCenterInSketch); - aProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed); - - aProjection->data()->blockSendAttributeUpdated(aWasBlocked); } else return; @@ -294,12 +375,15 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) } } -bool SketchPlugin_Projection::rebuildProjectedFeature(FeaturePtr& theProjection, - const std::string& theResultType, - bool theRemoveOnly) +bool SketchPlugin_Projection::rebuildProjectedFeature( + FeaturePtr& theProjection, + const std::set& theSupportedTypes, + const std::string& theRequestedFeature) { bool isRebuild = false; - if (theProjection && theProjection->getKind() != theResultType) { + if (theProjection && + (theSupportedTypes.find(theProjection->getKind()) == theSupportedTypes.end() || + (!theRequestedFeature.empty() && theProjection->getKind() != theRequestedFeature))) { DocumentPtr aDoc = sketch()->document(); AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID()); @@ -312,7 +396,7 @@ bool SketchPlugin_Projection::rebuildProjectedFeature(FeaturePtr& theProjection, isRebuild = true; } - if (!theProjection && !theRemoveOnly) - theProjection = sketch()->addFeature(theResultType); + if (!theProjection && !theRequestedFeature.empty()) + theProjection = sketch()->addFeature(theRequestedFeature); return isRebuild; } diff --git a/src/SketchPlugin/SketchPlugin_Projection.h b/src/SketchPlugin/SketchPlugin_Projection.h index f62237608..40fd6301a 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.h +++ b/src/SketchPlugin/SketchPlugin_Projection.h @@ -90,9 +90,13 @@ private: /// \brief Delete already calculated projected feature /// if the selection of the projection is changed + /// \param[in/out] theProjection projected feature + /// \param[in] theSupportedTypes types supported relatively to the base selection + /// \param[in] theRequestedFeature type of the new feature to be created + /// (remove only if empty string). bool rebuildProjectedFeature(FeaturePtr& theProjection, - const std::string& theResultType, - bool theRemoveOnly = false); + const std::set& theSupportedTypes, + const std::string& theRequestedFeature = std::string()); bool myIsComputing; }; diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 7f081fb0c..46a358114 100644 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1137,10 +1137,10 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, std::shared_ptr anEllipse = anEdge->ellipse(); std::shared_ptr anEllipseNormal = anEllipse->normal(); double aDot = fabs(aNormal->dot(anEllipseNormal)); - bool aValid = aDot >= tolerance * tolerance; + bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance; if (!aValid) - theError.arg(anEdge->isEllipse() ? "Error: Ellipse is orthogonal to the sketch plane." - : "Error: Elliptic Arc is orthogonal to the sketch plane."); + theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane." + : "Error: Elliptic Arc is orthogonal to the sketch plane."); return aValid; } diff --git a/src/SketchPlugin/Test/TestProjectionEllipse.py b/src/SketchPlugin/Test/TestProjectionEllipse.py index 9dbaabc98..c6a97d98d 100644 --- a/src/SketchPlugin/Test/TestProjectionEllipse.py +++ b/src/SketchPlugin/Test/TestProjectionEllipse.py @@ -49,11 +49,12 @@ model.end() from GeomAPI import * -circle2 = SketchCircle_2.results()[-1].resultSubShapePair()[0].shape() -assert(circle2.isEdge() and circle2.edge().isCircle()) ellipse1 = SketchEllipse_1.results()[-1].resultSubShapePair()[0].shape() assert(ellipse1.isEdge() and ellipse1.edge().isEllipse()) ellipse2 = SketchEllipse_2.results()[-1].resultSubShapePair()[0].shape() assert(ellipse2.isEdge() and ellipse2.edge().isEllipse()) +# TODO [limitation]: projection of an ellipse to non-parallel plane is forbiden (OCCT issue #31016) +assert(Sketch_2.feature().error() != "") + assert(model.checkPythonDump()) -- 2.30.2