-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023 CEA, EDF
+//
+// 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
+//
#include <SketchSolver_ConstraintTangent.h>
#include <SketchSolver_Error.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 <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeInteger.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_ConstraintMiddle.h>
#include <cmath>
/// \brief Check whether the entities has only one shared point or less.
/// Return list of coincident points.
-static std::list<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
+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
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);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
+ aStorage->removeParameters(aParams);
+ myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
+ }
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbCircles = 0;
+ int aNbEllipses = 0;
+ int aNbSplines = 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_ELLIPTIC_ARC)
+ ++aNbEllipses;
+ else if ((*anEntIt)->type() == ENTITY_BSPLINE)
+ ++aNbSplines;
}
- if (aNbCircles < 1) {
+ if (aNbCircles + aNbEllipses + aNbSplines < 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 + aNbSplines == 2) {
+ myType = CONSTRAINT_TANGENT_CURVE_CURVE;
isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
}
else {
return;
}
- FeaturePtr aFeature1, aFeature2;
- getTangentFeatures(myBaseConstraint, aFeature1, aFeature2);
+ FeaturePtr aFeatures[2];
+ getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
// check number of coincident points
- std::list<AttributePtr> aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
- if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 1) {
+ std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
+ if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
return;
}
+ EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() };
+
+ if (aCoincidentPoints.empty()) {
+ // Try to find non-boundary points coincident with both features.
+ // It is necesasry to create tangency with ellipse.
+ if (aNbEllipses > 0)
+ aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]);
+ }
+ else if (aNbSplines > 0) {
+ // General approach applying tangency to B-spline leads to hang-up in PlaneGCS.
+ // So, the tangency will be applied for the construction segment instead of B-spline curve.
+ for (int i = 0; i < 2; ++i) {
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE) {
+ EdgeWrapperPtr anEdge =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aTgEntities[i]);
+ std::shared_ptr<GCS::BSpline> aBSpline =
+ std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+
+ // which boundary is coincident?
+ GCS::Point aPoint1, aPoint2;
+ for (std::set<AttributePtr>::iterator aPIt = aCoincidentPoints.begin();
+ aPIt != aCoincidentPoints.end(); ++aPIt) {
+ if ((*aPIt)->owner() == aFeatures[i]) {
+ if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) {
+ aPoint1 = aBSpline->poles[0];
+ aPoint2 = aBSpline->poles[1];
+ }
+ else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) {
+ aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2];
+ aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1];
+ }
+ break;
+ }
+ }
+
+ // substitute B-spline by its boundary segment
+ std::shared_ptr<GCS::Line> aSegment(new GCS::Line);
+ aSegment->p1 = aPoint1;
+ aSegment->p2 = aPoint2;
+ aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment));
+ --aNbSplines;
+ ++aNbLines;
+ }
+ }
+ }
+
EntityWrapperPtr aSharedPointEntity;
+ std::list<GCSConstraintPtr> anAuxConstraints;
if (!aCoincidentPoints.empty()) {
- mySharedPoint = aCoincidentPoints.front();
+ mySharedPoint = *aCoincidentPoints.begin();
aSharedPointEntity = myStorage->entity(mySharedPoint);
}
+ else if (aNbEllipses + aNbSplines > 0) {
+ // create auxiliary point
+ GCSPointPtr aPoint(new GCS::Point);
+ aPoint->x = aStorage->createParameter();
+ aPoint->y = aStorage->createParameter();
+ calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
+
+ myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
+ aSharedPointEntity = myAuxPoint;
+
+ EntityWrapperPtr aDummy;
+ for (int i = 0; i < 2; ++i) {
+ // create auxiliary parameters for coincidence with B-spline
+ if (aTgEntities[i]->type() == ENTITY_BSPLINE)
+ myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
+
+ // create auxiliary coincident constraints for tangency with ellipse
+ ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
+ CONSTRAINT_PT_ON_CURVE, myAuxParameters[i],
+ aSharedPointEntity, aDummy, aTgEntities[i], aDummy);
+ anAuxConstraints.insert(anAuxConstraints.end(),
+ aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ }
+ }
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
- mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1],
aSharedPointEntity, &myCurveCurveAngle);
} else {
- mySolverConstraint = createArcArcTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
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 (aNbCoincidentFeatures == 2)
isRebuild = true;
}
- } else if (mySharedPoint) {
- // The features are tangent in the shared point, but the coincidence has been removed.
- // Check if the coincidence is the same.
- std::list<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
- isRebuild = true;
- std::list<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)
rebuild();
}
+bool SketchSolver_ConstraintTangent::remove()
+{
+ if (myAuxPoint) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
+ if (myAuxParameters[0])
+ aParams.insert(myAuxParameters[0]->scalar());
+ if (myAuxParameters[1])
+ aParams.insert(myAuxParameters[1]->scalar());
+ aStorage->removeParameters(aParams);
+ myAuxPoint = EntityWrapperPtr();
+ myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
+ }
+ return SketchSolver_Constraint::remove();
+}
+
const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
std::set<FeaturePtr> aCoincidences;
+ std::map<AttributePtr, FeaturePtr> aCoincidentPoints;
std::set<AttributePtr>::const_iterator anIt;
// collect coincidences referred to the first feature
for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
- if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID())
+ if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
aCoincidences.insert(aRef);
+ AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A());
+ if (!aRefAttrA->isObject())
+ aCoincidentPoints[aRefAttrA->attr()] = aRef;
+ AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B());
+ if (!aRefAttrB->isObject())
+ aCoincidentPoints[aRefAttrB->attr()] = aRef;
+ }
}
// leave only coincidences referred to the second feature
FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
if (aCoincidences.find(aRef) != aCoincidences.end())
aCoincidencesBetweenFeatures.insert(aRef);
+ else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
+ aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (aRefAttr && !aRefAttr->isObject()) {
+ std::map<AttributePtr, FeaturePtr>::iterator aFound =
+ aCoincidentPoints.find(aRefAttr->attr());
+ if (aFound != aCoincidentPoints.end()) {
+ aCoincidencesBetweenFeatures.insert(aRef);
+ aCoincidencesBetweenFeatures.insert(aFound->second);
+ }
+ }
+ }
+ }
}
return aCoincidencesBetweenFeatures;
}
-std::list<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
{
std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
// collect points only
- std::list<AttributePtr> aCoincidentPoints;
+ std::map<FeaturePtr, std::set<AttributePtr> > aCoincidentPoints;
std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++ aCIt) {
for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
- AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
- if (aRefAttr && !aRefAttr->isObject()) {
- aCoincidentPoints.push_back(aRefAttr->attr());
- break;
+ AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (!aRefAttr || aRefAttr->isObject())
+ continue;
+
+ AttributePtr anAttr = aRefAttr->attr();
+ FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
+ if (anOwner == theFeature1 || anOwner == theFeature2) {
+ if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
+ AttributePoint2DArrayPtr aPoles =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
+
+ AttributeIntegerPtr anIndex;
+ if (anOwner->getKind() == SketchPlugin_BSpline::ID()) {
+ anIndex = (*aCIt)->integer(i == 0 ?
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
+ SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+ }
+ if (anIndex) {
+ if (anIndex->value() == 0)
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
+ else if (anIndex->value() + 1 == aPoles->size())
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
+ if (anAttr)
+ aCoincidentPoints[anOwner].insert(anAttr);
+ }
+ }
+ else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+ aCoincidentPoints[anOwner].insert(anAttr);
}
}
}
- return aCoincidentPoints;
+
+ std::set<AttributePtr> aBoundaryPoints;
+ if (aCoincidentPoints.size() == 2) {
+ for (std::map<FeaturePtr, std::set<AttributePtr> >::iterator anIt = aCoincidentPoints.begin();
+ anIt != aCoincidentPoints.end(); ++anIt)
+ aBoundaryPoints.insert(anIt->second.begin(), anIt->second.end());
+ }
+ return aBoundaryPoints;
+}
+
+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_ConstraintCoincidenceInternal::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)
const GCSPointPtr& thePoint,
double* theAngle)
{
- double anAngle = GCS::System::calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
+ double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
// bring angle to [-pi..pi]
if (anAngle > PI) anAngle -= 2.0 * PI;
if (anAngle < -PI) anAngle += 2.0 * PI;
std::shared_ptr<GCS::Circle> aCirc =
std::dynamic_pointer_cast<GCS::Circle>(anEntCirc->entity());
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
+
std::shared_ptr<GCS::Line> aLine =
std::dynamic_pointer_cast<GCS::Line>(anEntLine->entity());
GCSConstraintPtr aNewConstr;
- if (theSharedPoint) {
- std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
+ if (theSharedPoint && anArc) { // do not process shared point between circle and line
GCSPointPtr aPoint =
std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
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) {
- std::shared_ptr<GCS::Arc> anArc1 = std::dynamic_pointer_cast<GCS::Arc>(aCirc1);
- std::shared_ptr<GCS::Arc> anArc2 = std::dynamic_pointer_cast<GCS::Arc>(aCirc2);
GCSPointPtr aPoint =
std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
- adjustAngleBetweenCurves(anArc1, anArc2, aPoint, theAngle);
+ adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
aNewConstr =
- GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc1, *anArc2, *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_ELLIPTIC_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());
+ }
}