- myXEndBefore = anEndAttr->x();
- myYEndBefore = anEndAttr->y();
- myEndUpdate = false;
- } else if (theID == START_ID() && !myStartUpdate) {
- myStartUpdate = true;
- // compute and change the arc start point
- std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
- new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
- std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
- if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
- aStartAttr->setValue(aProjection);
- myStartUpdate = false;
- } else if (theID == CENTER_ID() && !myEndUpdate) {
- myEndUpdate = true;
- // compute and change the arc end point
- std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
- new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
- std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
- if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
- anEndAttr->setValue(aProjection);
- myEndUpdate = false;
+ else if (aConstrFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ if ((aRefAttrA && aRefAttrA->object() == aThisArc) ||
+ (aRefAttrB && aRefAttrB->object() == aThisArc))
+ aTangency.insert(aConstrFeature);
+ }
+ }
+ // search applicable pair of constraints
+ bool isFound = false;
+ FeaturePtr aPrevCoincidence, aPrevTangency;
+ std::set<FeaturePtr>::const_iterator aCIt, aTIt;
+ for (aCIt = aCoincidence.begin(); aCIt != aCoincidence.end() && !isFound; ++aCIt) {
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ (*aCIt)->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ (*aCIt)->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ AttributePtr anOtherPoint =
+ aRefAttrA->attr() == aStartAttr ? aRefAttrB->attr() : aRefAttrA->attr();
+ for (aTIt = aTangency.begin(); aTIt != aTangency.end() && !isFound; ++aTIt) {
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ (*aTIt)->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ (*aTIt)->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ ObjectPtr anOtherObject = aRefAttrA->object() == aThisArc ?
+ aRefAttrB->object() : aRefAttrA->object();
+ FeaturePtr anOtherFeature = ModelAPI_Feature::feature(anOtherObject);
+ if (anOtherPoint->owner() == anOtherFeature) {
+ isFound = true;
+ aPrevCoincidence = *aCIt;
+ aPrevTangency = *aTIt;
+ }
+ }
+ }
+
+ if (isFound) {
+ // update previous constraints
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aPrevCoincidence->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aPrevCoincidence->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ if (aRefAttrA->attr() == aStartAttr)
+ aRefAttrB->setAttr(aTangPtAttr->attr());
+ else
+ aRefAttrA->setAttr(aTangPtAttr->attr());
+
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aPrevTangency->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aPrevTangency->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ if (aRefAttrA->object() == aThisArc)
+ aRefAttrB->setObject(aTangFeature);
+ else
+ aRefAttrA->setObject(aTangFeature);
+ } else {
+ // Wait all constraints being removed, then send update events
+ static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED);
+ bool isDeleteFlushed = Events_Loop::loop()->isFlushed(aDeleteEvent);
+ if (isDeleteFlushed)
+ Events_Loop::loop()->setFlushed(aDeleteEvent, false);
+ // Remove all obtained constraints which use current arc, because
+ // there is no information which of them were used to build tangency arc.
+ DocumentPtr aDoc = sketch()->document();
+ std::set<FeaturePtr> aFeaturesToBeRemoved;
+ for (aCIt = aCoincidence.begin(); aCIt != aCoincidence.end(); ++aCIt)
+ aFeaturesToBeRemoved.insert(*aCIt);
+ for (aTIt = aTangency.begin(); aTIt != aTangency.end(); ++aTIt)
+ aFeaturesToBeRemoved.insert(*aTIt);
+ ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
+ // Send events to update the sub-features by the solver.
+ if (isDeleteFlushed)
+ Events_Loop::loop()->setFlushed(aDeleteEvent, true);
+ else
+ Events_Loop::loop()->flush(aDeleteEvent);
+
+ // Wait all constraints being created, then send update events
+ static Events_ID aCreateEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+ bool isCreateFlushed = Events_Loop::loop()->isFlushed(aCreateEvent);
+ if (isCreateFlushed)
+ Events_Loop::loop()->setFlushed(aCreateEvent, false);
+
+ // Create new constraints
+ FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ aRefAttrA->setAttr(aStartAttr);
+ aRefAttrB->setAttr(aTangPtAttr->attr());
+ aConstraint->execute();
+ ModelAPI_EventCreator::get()->sendUpdated(aConstraint, aCreateEvent);
+
+ aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+ aRefAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ aRefAttrA->setObject(aThisArc);
+ aRefAttrB->setObject(aTangFeature);
+ aConstraint->execute();
+ ModelAPI_EventCreator::get()->sendUpdated(aConstraint, aCreateEvent);
+
+ // Send events to update the sub-features by the solver.
+ if(isCreateFlushed)
+ Events_Loop::loop()->setFlushed(aCreateEvent, true);
+ else
+ Events_Loop::loop()->flush(aCreateEvent);