#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Ellipse2d.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>
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 || (*anEntIt)->type() == ENTITY_BSPLINE)
+ else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
++aNbEllipses;
+ else if ((*anEntIt)->type() == ENTITY_BSPLINE)
+ ++aNbSplines;
}
- if (aNbCircles + aNbEllipses < 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 (aNbLines + aNbCircles + aNbEllipses == 2) {
+ else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) {
myType = CONSTRAINT_TANGENT_CURVE_CURVE;
isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
}
return;
}
- FeaturePtr aFeature1, aFeature2;
- getTangentFeatures(myBaseConstraint, aFeature1, aFeature2);
+ FeaturePtr aFeatures[2];
+ getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
// check number of coincident points
- std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeature1, aFeature2);
+ std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
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 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;
mySharedPoint = *aCoincidentPoints.begin();
aSharedPointEntity = myStorage->entity(mySharedPoint);
}
- else if (aNbEllipses > 0) {
+ else if (aNbEllipses + aNbSplines > 0) {
// create auxiliary point
GCSPointPtr aPoint(new GCS::Point);
aPoint->x = aStorage->createParameter();
aPoint->y = aStorage->createParameter();
- calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
+ calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
aSharedPointEntity = myAuxPoint;
- // create auxiliary parameters for coincidence with B-spline
- if (myAttributes.front()->type() == ENTITY_BSPLINE)
- myAuxParameters[0].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
- if (myAttributes.back()->type() == ENTITY_BSPLINE)
- myAuxParameters[1].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
-
- // create auxiliary coincident constraints for tangency with ellipse
EntityWrapperPtr aDummy;
- ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, myAuxParameters[0],
- aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
- anAuxConstraints = aCoincidence->constraints();
- aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
- CONSTRAINT_PT_ON_CURVE, myAuxParameters[1],
- aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
- anAuxConstraints.insert(anAuxConstraints.end(),
- aCoincidence->constraints().begin(), aCoincidence->constraints().end());
+ 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 = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
+ mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
}
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::set<AttributePtr> aCoincidentPoints;
std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
for (; aCIt != aCoincidences.end(); ++ aCIt) {
- AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
- AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
- if (!aRefAttrA || aRefAttrA->isObject() ||
- !aRefAttrB || aRefAttrB->isObject())
- continue;
-
- AttributePtr anAttrA = aRefAttrA->attr();
- AttributePtr anAttrB = aRefAttrB->attr();
- if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
- anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
- aCoincidentPoints.insert(anAttrA);
- aCoincidentPoints.insert(anAttrB);
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ 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()) {
+ AttributeIntegerPtr 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
+ anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
+ if (anAttr)
+ aCoincidentPoints.insert(anAttr);
+ }
+ }
+ else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttr->id() != SketchPlugin_Circle::CENTER_ID())
+ aCoincidentPoints.insert(anAttr);
+ }
}
}
return aCoincidentPoints;