}
+GeomAPI_Circ2d::GeomAPI_Circ2d(const double theCenterX,
+ const double theCenterY,
+ const double theRadius)
+ : GeomAPI_Interface(newCirc2d(theCenterX, theCenterY, gp::DX2d(), theRadius))
+{
+}
GeomAPI_Circ2d::GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
const std::shared_ptr<GeomAPI_Pnt2d>& theCirclePoint)
class GeomAPI_Circ2d : public GeomAPI_Interface
{
- public:
+public:
+ /// Creation of circle defined by center point and circle radius
+ GEOMAPI_EXPORT
+ GeomAPI_Circ2d(const double theCenterX, const double theCenterY, const double theRadius);
+
/// Creation of circle defined by center point and circle radius
GEOMAPI_EXPORT
GeomAPI_Circ2d(const std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
#include "GeomAPI_Ellipse.h"
#include "GeomAPI_Ax2.h"
+#include "GeomAPI_Curve.h"
#include "GeomAPI_Pnt.h"
+#include <Geom_Ellipse.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <gp_Elips.hxx>
#define MY_ELIPS implPtr<gp_Elips>()
{
}
+GeomAPI_Ellipse::GeomAPI_Ellipse(GeomCurvePtr theCurve)
+{
+ Handle(Geom_Curve) aCurve = theCurve->impl<Handle(Geom_Curve)>();
+ Handle(Geom_Ellipse) anEllipse = Handle(Geom_Ellipse)::DownCast(aCurve);
+ if (anEllipse.IsNull())
+ throw Standard_ConstructionError("GeomAPI_Ellipse: Curve is not an ellipse");
+ setImpl(new gp_Elips(anEllipse->Elips()));
+}
+
std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::center() const
{
const gp_Pnt& aCenter = MY_ELIPS->Location();
{
return MY_ELIPS->MajorRadius();
}
+
+const std::shared_ptr<GeomAPI_Pnt> GeomAPI_Ellipse::project(
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint) const
+{
+ std::shared_ptr<GeomAPI_Pnt> aResult;
+ if (!MY_ELIPS)
+ return aResult;
+
+ Handle(Geom_Ellipse) aEllipse = new Geom_Ellipse(*MY_ELIPS);
+
+ const gp_Pnt& aPoint = thePoint->impl<gp_Pnt>();
+
+ GeomAPI_ProjectPointOnCurve aProj(aPoint, aEllipse);
+ Standard_Integer aNbPoint = aProj.NbPoints();
+ if (aNbPoint > 0) {
+ gp_Pnt aNearest = aProj.NearestPoint();
+ aResult = GeomPointPtr(new GeomAPI_Pnt(aNearest.X(), aNearest.Y(), aNearest.Z()));
+ }
+ return aResult;
+}
#include <memory>
class GeomAPI_Ax2;
+class GeomAPI_Curve;
class GeomAPI_Dir;
class GeomAPI_Pnt;
GEOMAPI_EXPORT GeomAPI_Ellipse(const std::shared_ptr<GeomAPI_Ax2>& theAx2,
double theMajorRadius, double theMinorRadius);
+ GEOMAPI_EXPORT GeomAPI_Ellipse(std::shared_ptr<GeomAPI_Curve> theCurve);
+
/// Returns center of the ellipse
GEOMAPI_EXPORT std::shared_ptr<GeomAPI_Pnt> center() const;
/// Returns major radius of the ellipse
GEOMAPI_EXPORT double majorRadius() const;
+ /// Project point on ellipse
+ GEOMAPI_EXPORT const std::shared_ptr<GeomAPI_Pnt> project(
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint) const;
};
//! Pointer on the object
// Author: Artem ZHIDKOV
#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Circ2d.h>
#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
#include <GeomAPI_Pnt2d.h>
+#include <Extrema_ExtCC2d.hxx>
+#include <Extrema_ExtElC2d.hxx>
+#include <Geom2d_Ellipse.hxx>
+#include <Geom2dAdaptor_Curve.hxx>
#include <gp_Ax22d.hxx>
#include <gp_Elips2d.hxx>
#include <Precision.hxx>
{
return MY_ELLIPSE->MajorRadius();
}
+
+template <typename EXTREMAPTR>
+static double extrema(EXTREMAPTR theAlgo,
+ GeomPnt2dPtr& thePoint1,
+ GeomPnt2dPtr& thePoint2)
+{
+ double aDistance = Precision::Infinite();
+ if (theAlgo->IsDone() && theAlgo->NbExt() > 0) {
+ Extrema_POnCurv2d aP1, aP2;
+ for (int i = 1; i <= theAlgo->NbExt(); ++i)
+ if (theAlgo->SquareDistance(i) < aDistance) {
+ aDistance = Sqrt(theAlgo->SquareDistance(i));
+ theAlgo->Points(i, aP1, aP2);
+ }
+
+ aDistance = Sqrt(aDistance);
+ thePoint1 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP1.Value().X(), aP1.Value().Y()));
+ thePoint2 = GeomPnt2dPtr(new GeomAPI_Pnt2d(aP2.Value().X(), aP2.Value().Y()));
+ }
+ return aDistance;
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnLine)
+{
+ Extrema_ExtElC2d anExtema(theLine->impl<gp_Lin2d>(), *MY_ELLIPSE);
+ return extrema(&anExtema, thePointOnLine, thePointOnMe);
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Circ2d>& theCircle,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnCircle)
+{
+ Extrema_ExtElC2d anExtema(theCircle->impl<gp_Circ2d>(), *MY_ELLIPSE);
+ return extrema(&anExtema, thePointOnCircle, thePointOnMe);
+}
+
+double GeomAPI_Ellipse2d::distance(const std::shared_ptr<GeomAPI_Ellipse2d>& theEllipse,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnEllipse)
+{
+ Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(theEllipse->impl<gp_Elips2d>());
+ Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(*MY_ELLIPSE);
+
+ Extrema_ExtCC2d* anExtema =
+ new Extrema_ExtCC2d(Geom2dAdaptor_Curve(anEllipse1), Geom2dAdaptor_Curve(anEllipse2));
+ double aDistance = extrema(anExtema, thePointOnEllipse, thePointOnMe);
+ delete anExtema;
+ return aDistance;
+}
#include <GeomAPI_Interface.h>
-class GeomAPI_Pnt2d;
+class GeomAPI_Circ2d;
class GeomAPI_Dir2d;
+class GeomAPI_Lin2d;
+class GeomAPI_Pnt2d;
/**\class GeomAPI_Ellipse2d
* \ingroup DataModel
/// Returns major radius of the ellipse
GEOMAPI_EXPORT double majorRadius() const;
+
+ /// Calculate minimal distance between the ellipse and a line.
+ /// Return corresponding points on the ellipse and on the line.
+ GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Lin2d>& theLine,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnLine);
+
+ /// Calculate minimal distance between the ellipse and a circle.
+ /// Return corresponding points on the ellipse and on the circle.
+ GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Circ2d>& theCircle,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnCircle);
+
+ /// Calculate minimal distance between two ellipses.
+ /// Return corresponding points on the ellipses.
+ GEOMAPI_EXPORT double distance(const std::shared_ptr<GeomAPI_Ellipse2d>& theEllipse,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnMe,
+ std::shared_ptr<GeomAPI_Pnt2d>& thePointOnEllipse);
};
#endif
return false;
GeomAPI_Edge aEdge1(aShape);
- if (aEdge1.isLine() || aEdge1.isArc()) {
- if (aList.size() == 2) {
- // Check second selection
- aPrs = aList.last();
- const GeomShapePtr& aShape2 = aPrs->shape();
- if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
- return false;
- GeomAPI_Edge aEdge2(aShape2);
-
- if (aEdge1.isLine() && aEdge2.isArc())
- return true;
- else if (aEdge1.isArc() && aEdge2.isLine())
- return true;
- else
- return false;
- } else
- return true;
+ if (aList.size() == 2) {
+ // Check second selection
+ aPrs = aList.last();
+ const GeomShapePtr& aShape2 = aPrs->shape();
+ if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
+ return false;
+ GeomAPI_Edge aEdge2(aShape2);
+
+ if (aEdge1.isLine() && aEdge2.isLine())
+ return false;
}
- return false;
}
+ return true;
}
bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection,
TestConstraintRadius.py
TestConstraintRadiusFailure.py
TestConstraintTangent.py
+ TestConstraintTangentEllipse.py
TestConstraintVertical.py
TestCreateArcByCenterStartEnd.py
TestCreateArcByTangentEdge.py
if (!aOtherFea)
return true;
- if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
- if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
- aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
- theError = "It refers to a %1, but %2 is neither an %3 nor %4";
- theError.arg(SketchPlugin_Line::ID()).arg(aParamA)
- .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
- return false;
- }
- }
- else if (aRefFea->getKind() == SketchPlugin_Arc::ID() ||
- aRefFea->getKind() == SketchPlugin_Circle::ID()) {
- if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
- aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
- aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
- theError = "It refers to an %1, but %2 is not a %3 or an %4 or a %5";
- theError.arg(SketchPlugin_Arc::ID()).arg(aParamA)
- .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID())
- .arg(SketchPlugin_Circle::ID());
- return false;
- }
- }
- else {
- theError = "It refers to %1, but should refer to %2 or %3 or %4";
- theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID())
- .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
+ if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
+ aOtherFea->getKind() == SketchPlugin_Line::ID()) {
+ theError = "Two segments cannot be tangent";
return false;
}
return true;
--- /dev/null
+# Copyright (C) 2019 CEA/DEN, EDF R&D
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test constraint "Tangent" applied to ellipse and another entity
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+
+from GeomAPI import *
+from SketchAPI import *
+
+__updated__ = "2019-09-20"
+
+class TestTangentEllipse(unittest.TestCase):
+ def setUp(self):
+ axisStart = GeomAPI_Pnt2d(20., 60.)
+ axisEnd = GeomAPI_Pnt2d(80., 50.)
+ passedPoint = GeomAPI_Pnt2d(60., 70.)
+
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
+ model.do()
+ self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
+ self.myCenter = macroEllipse.center()
+ self.myFocus1 = macroEllipse.focus1()
+ self.myFocus2 = macroEllipse.focus2()
+ self.myMajorAxis = macroEllipse.majorAxis()
+ self.myMajorStart = macroEllipse.majorAxisStart()
+ self.myMajorEnd = macroEllipse.majorAxisEnd()
+ self.myMinorAxis = macroEllipse.minorAxis()
+ self.myMinorStart = macroEllipse.minorAxisStart()
+ self.myMinorEnd = macroEllipse.minorAxisEnd()
+
+ self.myDOF = 5
+ self.myNbPoints = 7
+ self.myNbLines = 2
+ self.myNbArcs = 0
+ self.myNbCircles = 0
+ self.myNbEllipses = 1
+ self.myNbInternals = 11
+ self.myNbCoincidence = 0
+ self.myNbTangency = 0
+
+ def tearDown(self):
+ model.end()
+ self.checkDOF()
+ self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
+ self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
+ self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
+ self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
+ self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
+ self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
+ self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
+ self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
+ self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
+ self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
+ self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
+ model.testNbSubFeatures(self.mySketch, "SketchPoint", self.myNbPoints)
+ model.testNbSubFeatures(self.mySketch, "SketchLine", self.myNbLines)
+ model.testNbSubFeatures(self.mySketch, "SketchArc", self.myNbArcs)
+ model.testNbSubFeatures(self.mySketch, "SketchCircle", self.myNbCircles)
+ model.testNbSubFeatures(self.mySketch, "SketchEllipse", self.myNbEllipses)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", self.myNbInternals)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoincidence)
+ model.testNbSubFeatures(self.mySketch, "SketchConstraintTangent", self.myNbTangency)
+
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def assertTangentLineEllipse(self, theLine, theEllipse):
+ aLine = GeomAPI_Lin2d(theLine.startPoint().pnt(), theLine.endPoint().pnt())
+ projF1 = aLine.project(theEllipse.firstFocus().pnt())
+ projF2 = aLine.project(theEllipse.secondFocus().pnt())
+
+ distF1P1 = model.distancePointPoint(theEllipse.firstFocus(), projF1)
+ distF2P2 = model.distancePointPoint(theEllipse.secondFocus(), projF2)
+
+ tgPoint = GeomAPI_Pnt2d((projF1.x() * distF2P2 + projF2.x() * distF1P1) / (distF1P1 + distF2P2), (projF1.y() * distF2P2 + projF2.y() * distF1P1) / (distF1P1 + distF2P2))
+ distF1T = model.distancePointPoint(theEllipse.firstFocus(), tgPoint)
+ distF2T = model.distancePointPoint(theEllipse.secondFocus(), tgPoint)
+ self.assertAlmostEqual(distF1T + distF2T, 2 * theEllipse.majorRadius().value())
+
+ def assertTangentCircleEllipse(self, theCircle, theEllipse):
+ axis = GeomAPI_Dir2d(theEllipse.firstFocus().x() - theEllipse.center().x(), theEllipse.firstFocus().y() - theEllipse.center().y())
+ anEllipse = GeomAPI_Ellipse2d(theEllipse.center().pnt(), axis, theEllipse.majorRadius().value(), theEllipse.minorRadius().value())
+ aCircle = GeomAPI_Circ2d(theCircle.center().pnt(), GeomAPI_Dir2d(1, 0), theCircle.radius().value())
+
+ pOnE = GeomAPI_Pnt2d(0, 0)
+ pOnC = GeomAPI_Pnt2d(0, 0)
+ anEllipse.distance(aCircle, pOnE, pOnC)
+ self.assertAlmostEqual(model.distancePointPoint(pOnE, theCircle.center()), theCircle.radius().value())
+
+ dist1 = model.distancePointPoint(pOnC, theEllipse.firstFocus())
+ dist2 = model.distancePointPoint(pOnC, theEllipse.secondFocus())
+ self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse.majorRadius().value())
+
+ def assertTangentEllipses(self, theEllipse1, theEllipse2):
+ axis1 = GeomAPI_Dir2d(theEllipse1.firstFocus().x() - theEllipse1.center().x(), theEllipse1.firstFocus().y() - theEllipse1.center().y())
+ anEllipse1 = GeomAPI_Ellipse2d(theEllipse1.center().pnt(), axis1, theEllipse1.majorRadius().value(), theEllipse1.minorRadius().value())
+ axis2 = GeomAPI_Dir2d(theEllipse2.firstFocus().x() - theEllipse2.center().x(), theEllipse2.firstFocus().y() - theEllipse2.center().y())
+ anEllipse2 = GeomAPI_Ellipse2d(theEllipse2.center().pnt(), axis2, theEllipse2.majorRadius().value(), theEllipse2.minorRadius().value())
+
+ p1 = GeomAPI_Pnt2d(0, 0)
+ p2 = GeomAPI_Pnt2d(0, 0)
+ anEllipse1.distance(anEllipse2, p1, p2)
+
+ dist1 = model.distancePointPoint(p2, theEllipse1.firstFocus())
+ dist2 = model.distancePointPoint(p2, theEllipse1.secondFocus())
+ self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse1.majorRadius().value())
+
+ dist1 = model.distancePointPoint(p1, theEllipse2.firstFocus())
+ dist2 = model.distancePointPoint(p1, theEllipse2.secondFocus())
+ self.assertAlmostEqual(dist1 + dist2, 2 * theEllipse2.majorRadius().value())
+
+ def assertPoints(self, thePoint1, thePoint2):
+ self.assertAlmostEqual(thePoint1.x(), thePoint2.x())
+ self.assertAlmostEqual(thePoint1.y(), thePoint2.y())
+
+
+ def test_line_tangent(self):
+ """ Test 1. Set tangency between ellipse and a line
+ """
+ aLine = self.mySketch.addLine(10, 10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+ def test_line_coincident_then_tangent(self):
+ """ Test 2. Set tangency between ellipse and a line, if the extremity of the line is coincident with the ellipse
+ """
+ aLine = self.mySketch.addLine(10, 10, 90, 40)
+ self.mySketch.setCoincident(aLine.endPoint(), self.myEllipse.result())
+ self.myNbLines += 1
+ self.myNbCoincidence += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+ def test_line_tangent_then_coincident(self):
+ """ Test 3. Set tangency between ellipse and a line, after that apply coincidence of extremity of the line and the ellipse's curve
+ """
+ aLine = self.mySketch.addLine(10, 10, 90, 40)
+ self.myNbLines += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setCoincident(aLine.startPoint(), self.myEllipse.result())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+ def test_line_tangent_then_remove_coincidence(self):
+ """ Test 4. Set tangency between ellipse and a line, which have a coincident point, then remove this coincidence
+ """
+ aLine = self.mySketch.addLine(10, 10, 90, 40)
+ aCoincidence = self.mySketch.setCoincident(aLine.endPoint(), self.myEllipse.result())
+ self.myNbLines += 1
+ self.myNbCoincidence += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aLine.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.myDocument.removeFeature(aCoincidence.feature())
+ self.myNbCoincidence -= 1
+ self.myDOF += 1
+ model.do()
+
+ self.assertTangentLineEllipse(aLine, self.myEllipse)
+
+
+ def test_circle_tangent(self):
+ """ Test 5. Set tangency between ellipse and a circle
+ """
+ aCircle = self.mySketch.addCircle(30, 10, 20)
+ self.myNbCircles += 1
+ self.myDOF += 3
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentCircleEllipse(aCircle, self.myEllipse)
+
+
+ def test_circle_coincident_then_tangent(self):
+ """ Test 6. Set tangency between ellipse and a circle, if the circle is coincident with start point of ellipse's minor axis
+ """
+ aCircle = self.mySketch.addCircle(30, 10, 20)
+ self.mySketch.setCoincident(self.myMinorStart.coordinates(), aCircle.defaultResult())
+ self.myNbCircles += 1
+ self.myNbCoincidence += 1
+ self.myDOF += 2
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), aCircle.defaultResult())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentCircleEllipse(aCircle, self.myEllipse)
+ self.assertAlmostEqual(model.distancePointPoint(aCircle.center(), self.myMinorStart.coordinates()), aCircle.radius().value())
+
+
+ def test_arc_tangent(self):
+ """ Test 7. Set tangency between ellipse and a circular arc
+ """
+ anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+ def test_arc_coincident_then_tangent(self):
+ """ Test 8. Set tangency between ellipse and an arc, if the extremity of the arc is coincident with the ellipse
+ """
+ anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+ self.mySketch.setCoincident(anArc.endPoint(), self.myEllipse.result())
+ self.myNbArcs += 1
+ self.myNbCoincidence += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+ def test_arc_tangent_then_coincident(self):
+ """ Test 9. Set tangency between ellipse and an arc, after that apply coincidence of extremity of the arc and the ellipse's curve
+ """
+ anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+ self.myNbArcs += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.mySketch.setCoincident(anArc.startPoint(), self.myEllipse.result())
+ self.myNbCoincidence += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+ def test_arc_tangent_then_remove_coincidence(self):
+ """ Test 10. Set tangency between ellipse and an arc, which have a coincident point, then remove this coincidence
+ """
+ anArc = self.mySketch.addArc(30, 10, 20, 10, 40, 10, False)
+ aCoincidence = self.mySketch.setCoincident(anArc.endPoint(), self.myEllipse.result())
+ self.myNbArcs += 1
+ self.myNbCoincidence += 1
+ self.myDOF += 4
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), anArc.results()[-1])
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.myDocument.removeFeature(aCoincidence.feature())
+ self.myNbCoincidence -= 1
+ self.myDOF += 1
+ model.do()
+
+ self.assertTangentCircleEllipse(anArc, self.myEllipse)
+
+
+ def test_ellipse_tangent(self):
+ """ Test 11. Set tangency between two ellipses
+ """
+ anEllipse = self.mySketch.addEllipse(10, 10, 20, -50, 20)
+ self.myNbEllipses += 1
+ self.myDOF += 5
+ model.do()
+
+ self.mySketch.setTangent(self.myEllipse.result(), anEllipse.result())
+ self.myNbTangency += 1
+ self.myDOF -= 1
+ model.do()
+
+ self.assertTangentEllipses(anEllipse, self.myEllipse)
+
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
CONSTRAINT_UNKNOWN = 0,
CONSTRAINT_COINCIDENCE, // base coincidence if we don't know exact type yet
CONSTRAINT_PT_PT_COINCIDENT,
- CONSTRAINT_PT_ON_LINE,
- CONSTRAINT_PT_ON_CIRCLE,
- CONSTRAINT_PT_ON_ELLIPSE,
+ CONSTRAINT_PT_ON_CURVE,
CONSTRAINT_MIDDLE_POINT,
CONSTRAINT_DISTANCE, // base distance if we don't know the measured objects yet
CONSTRAINT_PT_PT_DISTANCE,
CONSTRAINT_EQUAL_RADIUS,
CONSTRAINT_TANGENT, // base tangency if we don't know the measured objects yet
CONSTRAINT_TANGENT_CIRCLE_LINE,
- CONSTRAINT_TANGENT_CIRCLE_CIRCLE,
+ CONSTRAINT_TANGENT_CURVE_CURVE,
CONSTRAINT_COLLINEAR,
CONSTRAINT_MULTI_TRANSLATION,
CONSTRAINT_MULTI_ROTATION
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
+
#include <cmath>
case CONSTRAINT_PT_PT_COINCIDENT:
aResult = createConstraintCoincidence(aPoint1, aPoint2);
break;
- case CONSTRAINT_PT_ON_LINE:
- case CONSTRAINT_PT_ON_CIRCLE:
- case CONSTRAINT_PT_ON_ELLIPSE:
+ case CONSTRAINT_PT_ON_CURVE:
aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_EDGE_WRAPPER(theEntity1));
break;
case CONSTRAINT_MIDDLE_POINT:
return std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aStart->pnt(), aEnd->pnt()));
}
+std::shared_ptr<GeomAPI_Circ2d> PlaneGCSSolver_Tools::circle(EntityWrapperPtr theEntity)
+{
+ if (theEntity->type() != ENTITY_CIRCLE && theEntity->type() != ENTITY_ARC)
+ return std::shared_ptr<GeomAPI_Circ2d>();
+
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity);
+ std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(anEntity->entity());
+ return std::shared_ptr<GeomAPI_Circ2d>(
+ new GeomAPI_Circ2d(*(aCirc->center.x), *(aCirc->center.y), *(aCirc->rad)));
+}
+
+std::shared_ptr<GeomAPI_Ellipse2d> PlaneGCSSolver_Tools::ellipse(EntityWrapperPtr theEntity)
+{
+ if (theEntity->type() != ENTITY_ELLIPSE && theEntity->type() != ENTITY_ELLIPTICAL_ARC)
+ return std::shared_ptr<GeomAPI_Ellipse2d>();
+
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEntity);
+ std::shared_ptr<GCS::Ellipse> anEllipse =
+ std::dynamic_pointer_cast<GCS::Ellipse>(anEntity->entity());
+
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter(
+ new GeomAPI_Pnt2d(*(anEllipse->center.x), *(anEllipse->center.y)));
+ std::shared_ptr<GeomAPI_Dir2d> anAxis(new GeomAPI_Dir2d(
+ *(anEllipse->focus1.x) - *(anEllipse->center.x),
+ *(anEllipse->focus1.y) - *(anEllipse->center.y)));
+
+ return std::shared_ptr<GeomAPI_Ellipse2d>(
+ new GeomAPI_Ellipse2d(aCenter, anAxis, anEllipse->getRadMaj(), *anEllipse->radmin));
+}
+
+
GCS::SET_pD PlaneGCSSolver_Tools::parameters(const EntityWrapperPtr& theEntity)
{
#include <SketchSolver_ConstraintMovement.h>
#include <SketchPlugin_Constraint.h>
-#include <GeomAPI_Lin2d.h>
-#include <GeomAPI_Pnt2d.h>
+class GeomAPI_Circ2d;
+class GeomAPI_Ellipse2d;
+class GeomAPI_Lin2d;
+class GeomAPI_Pnt2d;
/** \namespace PlaneGCSSolver_Tools
* \ingroup Plugins
/// \brief Convert entity to line
/// \return empty pointer if the entity is not a line
std::shared_ptr<GeomAPI_Lin2d> line(EntityWrapperPtr theEntity);
+ /// \brief Convert entity to circle
+ /// \return empty pointer if the entity is not a circle
+ std::shared_ptr<GeomAPI_Circ2d> circle(EntityWrapperPtr theEntity);
+ /// \brief Convert entity to ellipse
+ /// \return empty pointer if the entity is not an ellipse
+ std::shared_ptr<GeomAPI_Ellipse2d> ellipse(EntityWrapperPtr theEntity);
/// \brief Convert entity to line
/// \return empty pointer if the entity is not a line
if (theAttributes[1])
myType = CONSTRAINT_PT_PT_COINCIDENT;
else if (theAttributes[2]) {
- // check the type of entity (line or circle)
- SketchSolver_EntityType anEntType = theAttributes[2]->type();
- if (anEntType == ENTITY_LINE)
- myType = CONSTRAINT_PT_ON_LINE;
- else if (anEntType == ENTITY_CIRCLE || anEntType == ENTITY_ARC)
- myType = CONSTRAINT_PT_ON_CIRCLE;
- else if (anEntType == ENTITY_ELLIPSE || anEntType == ENTITY_ELLIPTICAL_ARC)
- myType = CONSTRAINT_PT_ON_ELLIPSE;
- else
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
-
+ myType = CONSTRAINT_PT_ON_CURVE;
// obtain extremity points of the coincident feature for further checking of multi-coincidence
getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
} else
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateFeature.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeRefList.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateCoincidence.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Lin2d.h>
#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_Ellipse2d.h>
+
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMiddle.h>
#include <cmath>
static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
FeaturePtr theFeature2);
+/// \brief Collect points coincident with each of two features
+static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
+
/// \brief Check if two connected arcs have centers
/// in same direction relatively to connection point
static bool isArcArcTangencyInternal(EntityWrapperPtr theArc1,
double* theAngle = 0);
static ConstraintWrapperPtr
- createArcArcTangency(EntityWrapperPtr theEntity1,
- EntityWrapperPtr theEntity2,
- bool theInternalTangency,
- EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
- double* theAngle = 0);
+ createCurveCurveTangency(EntityWrapperPtr theEntity1,
+ EntityWrapperPtr theEntity2,
+ bool theInternalTangency,
+ EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
+ double* theAngle = 0);
+
+static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+ GCSPointPtr& theTangencyPoint);
void SketchSolver_ConstraintTangent::process()
if (mySolverConstraint)
myStorage->removeConstraint(myBaseConstraint);
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
mySolverConstraint = ConstraintWrapperPtr();
mySharedPoint = AttributePtr();
+ if (myAuxPoint) {
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ aStorage->removeParameters(aParams);
+ myAuxPoint = EntityWrapperPtr();
+ }
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbCircles = 0;
+ int aNbEllipses = 0;
std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
for (; anEntIt != myAttributes.end(); ++anEntIt) {
if (!(*anEntIt).get())
++aNbLines;
else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
++aNbCircles;
+ else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTICAL_ARC)
+ ++aNbEllipses;
}
- if (aNbCircles < 1) {
+ if (aNbCircles + aNbEllipses < 1) {
myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
return;
}
if (aNbLines == 1 && aNbCircles == 1) {
myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
}
- else if (aNbCircles == 2) {
- myType = CONSTRAINT_TANGENT_CIRCLE_CIRCLE;
+ else if (aNbLines + aNbCircles + aNbEllipses == 2) {
+ myType = CONSTRAINT_TANGENT_CURVE_CURVE;
isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
}
else {
return;
}
+ // Try to find non-boundary points coincident with both features.
+ // It is necesasry to create tangency with ellipse
+ if (aCoincidentPoints.empty() && aNbEllipses > 0)
+ aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
+
EntityWrapperPtr aSharedPointEntity;
+ std::list<GCSConstraintPtr> anAuxConstraints;
if (!aCoincidentPoints.empty()) {
mySharedPoint = *aCoincidentPoints.begin();
aSharedPointEntity = myStorage->entity(mySharedPoint);
}
+ else if (aNbEllipses > 0) {
+ // create auxiliary point
+ GCSPointPtr aPoint(new GCS::Point);
+ aPoint->x = aStorage->createParameter();
+ aPoint->y = aStorage->createParameter();
+ calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
+
+ myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
+ aSharedPointEntity = myAuxPoint;
+
+ // create auxiliary coincident constraints for tangency with ellipse
+ EntityWrapperPtr aDummy;
+ ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+ CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
+ anAuxConstraints = aCoincidence->constraints();
+ aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+ CONSTRAINT_PT_ON_CURVE, aDummy, aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
+ anAuxConstraints.insert(anAuxConstraints.end(),
+ aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ }
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
aSharedPointEntity, &myCurveCurveAngle);
} else {
- mySolverConstraint = createArcArcTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
}
+ if (!anAuxConstraints.empty()) {
+ anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
+ mySolverConstraint->constraints().end());
+ mySolverConstraint->setConstraints(anAuxConstraints);
+ }
+
myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
}
void SketchSolver_ConstraintTangent::adjustConstraint()
{
- if (myType == CONSTRAINT_TANGENT_CIRCLE_CIRCLE) {
+ if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) {
EntityWrapperPtr anEntity1 =
myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
EntityWrapperPtr anEntity2 =
}
}
- if (mySharedPoint && !isRebuild) {
- // The features are tangent in the shared point, but the coincidence has been removed/updated.
- // Check if the coincidence is the same.
- std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
- isRebuild = true;
- std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
- for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
- if (*anIt == mySharedPoint)
- isRebuild = false; // the coincidence is still exists => nothing to change
+ if (!isRebuild) {
+ if (mySharedPoint) {
+ // The features are tangent in the shared point, but the coincidence has been removed/updated.
+ // Check if the coincidence is the same.
+ std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
+ isRebuild = true;
+ std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
+ for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
+ if (*anIt == mySharedPoint)
+ isRebuild = false; // the coincidence is still exists => nothing to change
+ }
+ else {
+ // check both features have a coincident point
+ std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
+ isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
+ }
}
if (isRebuild)
return aCoincidentPoints;
}
+static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
+{
+ std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
+ const std::list<ResultPtr>& aResults = theFeature->results();
+ for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
+ anIt != aResults.end(); ++anIt) {
+ const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
+ aRefs.insert(aResRefs.begin(), aResRefs.end());
+ }
+ return aRefs;
+}
+
+// collect all points coincident with the feature
+static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
+{
+ std::set<AttributePtr> aPoints;
+
+ std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
+ for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+ FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+ if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (aRefAttr) {
+ AttributePtr anAttr = aRefAttr->attr();
+ if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+ aPoints.insert(anAttr);
+ }
+ }
+ }
+ }
+ return aPoints;
+}
+
+std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+ std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
+ std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
+
+ std::set<AttributePtr> aCommonPoints;
+ for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
+ anIt != aPointsOnF1.end(); ++anIt)
+ if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
+ aCommonPoints.insert(*anIt);
+ return aCommonPoints;
+}
+
bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
{
std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
}
-ConstraintWrapperPtr createArcArcTangency(EntityWrapperPtr theEntity1,
- EntityWrapperPtr theEntity2,
- bool theInternalTangency,
- EntityWrapperPtr theSharedPoint,
- double* theAngle)
+ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1,
+ EntityWrapperPtr theEntity2,
+ bool theInternalTangency,
+ EntityWrapperPtr theSharedPoint,
+ double* theAngle)
{
- std::shared_ptr<GCS::Circle> aCirc1 =
- std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity1)->entity());
- std::shared_ptr<GCS::Circle> aCirc2 =
- std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity2)->entity());
+ GCSCurvePtr aCurve1 =
+ std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity1)->entity());
+ GCSCurvePtr aCurve2 =
+ std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity2)->entity());
GCSConstraintPtr aNewConstr;
if (theSharedPoint) {
GCSPointPtr aPoint =
std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
- adjustAngleBetweenCurves(aCirc1, aCirc2, aPoint, theAngle);
+ adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
aNewConstr =
- GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCirc1, *aCirc2, *aPoint, theAngle));
+ GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle));
} else {
+ std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(aCurve1);
+ std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(aCurve2);
aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
aCirc1->rad, aCirc2->rad, theInternalTangency));
}
return ConstraintWrapperPtr(
- new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_CIRCLE));
+ new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE));
+}
+
+void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
+ GCSPointPtr& theTangencyPoint)
+{
+ std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
+ EntityWrapperPtr aCurve2 = theCurve2;
+ if (!anEllipse) {
+ // try converting to ellipse the second curve
+ anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
+ if (!anEllipse)
+ return; // no one curve is ellipse
+ aCurve2 = theCurve1;
+ }
+
+ GeomPnt2dPtr aP1, aP2;
+ if (aCurve2->type() == ENTITY_LINE) {
+ std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
+ anEllipse->distance(aLine, aP1, aP2);
+ }
+ else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
+ anEllipse->distance(aCircle, aP1, aP2);
+ }
+ else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTICAL_ARC) {
+ std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
+ anEllipse->distance(anEl2, aP1, aP2);
+ }
+
+ if (aP1 && aP2) {
+ *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x());
+ *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y());
+ }
}
bool isArcArcInternal;
double myCurveCurveAngle;
AttributePtr mySharedPoint;
+ EntityWrapperPtr myAuxPoint;
};
#endif
#include "SketcherPrs_PositionMgr.h"
#include "SketcherPrs_Tools.h"
-#include <GeomAPI_Edge.h>
-#include <GeomAPI_Curve.h>
-#include <GeomAPI_Vertex.h>
-#include <GeomAPI_Dir.h>
#include <GeomAPI_Ax3.h>
#include <GeomAPI_Circ.h>
+#include <GeomAPI_Curve.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
+#include <GeomAPI_Dir.h>
#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Vertex.h>
#include <GeomDataAPI_Point2D.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Ellipse.h>
+#include <SketchPlugin_Line.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintTangent.h>
#include <TopoDS_Vertex.hxx>
#include <Geom_Curve.hxx>
if (aDist <= Precision::Confusion())
aList.push_back(aFeature->firstResult());
}
- } else if ((aFeature->getKind() == SketchPlugin_Circle::ID()) ||
- (aFeature->getKind() == SketchPlugin_Arc::ID())) {
+ } else {
GeomCurvePtr aCurve;
ObjectPtr aResObj;
std::list<ResultPtr> aResults = aFeature->results();
}
}
if (aCurve.get()) {
- double aStart = aCurve->startParam();
- double aEnd = aCurve->endParam();
- GeomCirclePtr aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
- GeomPointPtr aProjPnt = aCircle->project(thePnt);
+ GeomPointPtr aProjPnt;
+ if (aFeature->getKind() == SketchPlugin_Circle::ID() ||
+ aFeature->getKind() == SketchPlugin_Arc::ID()) {
+ GeomCirclePtr aCircle = GeomCirclePtr(new GeomAPI_Circ(aCurve));
+ aProjPnt = aCircle->project(thePnt);
+ }
+ else if (aFeature->getKind() == SketchPlugin_Ellipse::ID()) {
+ GeomEllipsePtr anEllipse = GeomEllipsePtr(new GeomAPI_Ellipse(aCurve));
+ aProjPnt = anEllipse->project(thePnt);
+ }
if (aProjPnt && thePnt->distance(aProjPnt) <= Precision::Confusion())
aList.push_back(aResObj);
}