+ if (isArcArcInternal != isArcArcTangencyInternal(anEntity1, anEntity2))
+ rebuild();
+ }
+}
+
+void SketchSolver_ConstraintTangent::notify(const FeaturePtr& theFeature,
+ PlaneGCSSolver_Update* theUpdater)
+{
+ if (theFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
+ return;
+
+ // base constraint may become invalid (for example, during undo)
+ if (!myBaseConstraint->data() || !myBaseConstraint->data()->isValid())
+ return;
+
+ FeaturePtr aTgFeat1, aTgFeat2;
+ getTangentFeatures(myBaseConstraint, aTgFeat1, aTgFeat2);
+
+ bool isRebuild = false;
+ if (theFeature->data() && theFeature->data()->isValid()) {
+ // the constraint has been created
+ if (!mySharedPoint) {
+ // features has no shared point, check whether coincidence constraint binds these features)
+ int aNbCoincidentFeatures = 0;
+ for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
+ AttributeRefAttrPtr aRefAttr = theFeature->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
+ if (!aRefAttr)
+ continue;
+
+ ObjectPtr anObj;
+ if (aRefAttr->isObject())
+ anObj = aRefAttr->object();
+ else
+ anObj = aRefAttr->attr()->owner();
+
+ FeaturePtr aFeature = ModelAPI_Feature::feature(anObj);
+ if (aFeature == aTgFeat1 || aFeature == aTgFeat2)
+ ++aNbCoincidentFeatures;
+ }
+
+ if (aNbCoincidentFeatures == 2)
+ isRebuild = true;
+ }
+ }
+
+ 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)
+ rebuild();
+}
+
+
+
+
+// ================== Auxiliary functions =================================
+void getTangentFeatures(const ConstraintPtr& theConstraint,
+ FeaturePtr& theFeature1,
+ FeaturePtr& theFeature2)
+{
+ AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+ theFeature1 = ModelAPI_Feature::feature(aRefAttr->object());
+ aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+ theFeature2 = ModelAPI_Feature::feature(aRefAttr->object());
+}
+
+std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+ const std::set<AttributePtr>& aRefs1 = theFeature1->data()->refsToMe();
+ const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
+
+ std::set<FeaturePtr> aCoincidences;
+ 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())
+ aCoincidences.insert(aRef);
+ }
+
+ // leave only coincidences referred to the second feature
+ std::set<FeaturePtr> aCoincidencesBetweenFeatures;
+ for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) {
+ FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
+ if (aCoincidences.find(aRef) != aCoincidences.end())
+ aCoincidencesBetweenFeatures.insert(aRef);
+ }
+
+ return aCoincidencesBetweenFeatures;
+}
+
+std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+ std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
+ // collect points only
+ 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);