+
+ // message to init reentrant operation
+ static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
+ std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
+ <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
+
+ std::string anEditArcType = string(EDIT_ARC_TYPE_ID())->value();
+ aMessage->setTypeOfCreation(!anEditArcType.empty() ? anEditArcType : anArcType);
+ aMessage->setCreatedFeature(anArcFeature);
+ Events_Loop::loop()->send(aMessage);
+}
+
+std::string SketchPlugin_MacroArc::processEvent(const std::shared_ptr<Events_Message>& theMessage)
+{
+ std::string aFilledAttributeName;
+ std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
+ std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
+ if (aReentrantMessage.get()) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ std::string anArcType = aReentrantMessage->typeOfCreation();
+
+ string(ARC_TYPE())->setValue(anArcType);
+
+ aFilledAttributeName = ARC_TYPE();
+ if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
+ aFilledAttributeName = TANGENT_POINT_ID();
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ attribute(aFilledAttributeName));
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ aRefAttr->setAttr(aCreatedFeature->attribute(SketchPlugin_Arc::END_ID()));
+ }
+ else {
+ ObjectPtr anObject = aReentrantMessage->selectedObject();
+ AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+ std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+ if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
+ if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS() ||
+ anArcType == ARC_TYPE_BY_THREE_POINTS()) {
+ std::string aReferenceAttributeName;
+ if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
+ aFilledAttributeName = CENTER_POINT_ID();
+ aReferenceAttributeName = CENTER_POINT_REF_ID();
+ }
+ else {
+ aFilledAttributeName = START_POINT_2_ID();
+ aReferenceAttributeName = START_POINT_REF_ID();
+ }
+ // fill 2d point attribute
+ AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ attribute(aFilledAttributeName));
+ aPointAttr->setValue(aClickedPoint);
+ // fill reference attribute
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ attribute(aReferenceAttributeName));
+ if (aRefAttr.get()) {
+ if (anAttribute.get()) {
+ if (!anAttribute->owner().get() || !anAttribute->owner()->data()->isValid()) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ if (aCreatedFeature.get()) {
+ std::string anID = anAttribute->id();
+ std::string anArcID;
+ if (anID == END_POINT_1_ID() || anID == END_POINT_2_ID() ||
+ anID == END_POINT_3_ID())
+ anArcID = SketchPlugin_Arc::END_ID();
+ else if (anID == START_POINT_1_ID() || anID ==START_POINT_2_ID())
+ anArcID = SketchPlugin_Arc::START_ID();
+ else if (anID == CENTER_POINT_ID())
+ anArcID = SketchPlugin_Arc::CENTER_ID();
+ anAttribute = aCreatedFeature->attribute(anArcID);
+ }
+ }
+ aRefAttr->setAttr(anAttribute);
+ }
+ else if (anObject.get()) {
+ // if presentation of previous reentrant macro arc is used, the object is invalid,
+ // we should use result of previous feature of the message(Arc)
+ if (!anObject->data()->isValid()) {
+ FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+ if (aCreatedFeature.get())
+ anObject = aCreatedFeature->lastResult();
+ }
+ aRefAttr->setObject(anObject);
+ }
+ }
+ }
+ }
+ }
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ }
+ return aFilledAttributeName;
+}
+
+FeaturePtr SketchPlugin_MacroArc::createArcFeature()
+{
+ FeaturePtr anArcFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenter);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anArcFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(myStart);
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ anArcFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(myEnd);
+ anArcFeature->boolean(SketchPlugin_Arc::REVERSED_ID())
+ ->setValue(boolean(REVERSED_ID())->value());
+ anArcFeature->boolean(SketchPlugin_Arc::AUXILIARY_ID())
+ ->setValue(boolean(AUXILIARY_ID())->value());
+ anArcFeature->execute();
+
+ return anArcFeature;
+}
+
+void SketchPlugin_MacroArc::fillByCenterAndTwoPassed()
+{
+ AttributePoint2DPtr aCenterPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
+ if (!aCenterPointAttr->isInitialized())
+ return;
+
+ AttributePoint2DPtr aStartPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
+ if (!aStartPointAttr->isInitialized())
+ return;
+
+ myCenter = aCenterPointAttr->pnt();
+ myStart = aStartPointAttr->pnt();
+ myEnd = myStart;
+
+ AttributePoint2DPtr anEndPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
+ if (!anEndPointAttr->isInitialized())
+ return;
+
+ GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
+
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+ // check the end point is referred to another feature
+ GeomShapePtr aRefShape;
+ AttributeRefAttrPtr aEndPointRefAttr = refattr(END_POINT_REF_ID());
+ if (aEndPointRefAttr && aEndPointRefAttr->isInitialized()) {
+ if (aEndPointRefAttr->isObject()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aEndPointRefAttr->object());
+ if (aFeature)
+ aRefShape = aFeature->lastResult()->shape();
+ }
+ }
+ if (aRefShape) {
+ // Calculate end point as an intersection between circle and another shape
+ intersectShapeAndCircle(aRefShape, aCircleForArc, sketch(), anEndPointAttr);
+ } else {
+ // End point should be a projection on circle.
+ projectPointOnCircle(anEndPointAttr, aCircleForArc);
+ }
+ data()->blockSendAttributeUpdated(aWasBlocked, false);
+ myEnd = anEndPointAttr->pnt();
+
+ // update the REVERSED flag
+ recalculateReversedFlagByEnd(aCircleForArc);
+}
+
+void SketchPlugin_MacroArc::recalculateReversedFlagByEnd(const GeomAPI_Circ2d& theCurrentCircular)
+{
+ double aParameterNew = 0.0;
+ if(theCurrentCircular.parameter(myEnd, paramTolerance, aParameterNew)) {
+ if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
+ boolean(REVERSED_ID())->setValue(true);
+ } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
+ boolean(REVERSED_ID())->setValue(false);
+ }
+ }
+ myParamBefore = aParameterNew;
+}
+
+void SketchPlugin_MacroArc::fillByThreePassedPoints()
+{
+ AttributePoint2DPtr aStartPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
+ if (!aStartPointAttr->isInitialized())
+ return;
+
+ AttributePoint2DPtr anEndPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
+ if (!anEndPointAttr->isInitialized())
+ return;
+
+ myStart = aStartPointAttr->pnt();
+ myEnd = anEndPointAttr->pnt();
+
+ AttributePoint2DPtr aPassedPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
+ if (aPassedPointAttr->isInitialized()) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPassedPnt;
+ std::shared_ptr<GeomAPI_Shape> aTangentCurve;
+ SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
+ refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt);
+
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+ aCircBuilder.addPassingPoint(myStart);
+ aCircBuilder.addPassingPoint(myEnd);
+ if (aTangentCurve) {
+ aCircBuilder.addTangentCurve(aTangentCurve);
+ aCircBuilder.setClosestPoint(aPassedPointAttr->pnt());
+ } else
+ aCircBuilder.addPassingPoint(aPassedPnt);
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ if (!aCircle)
+ return;
+ myCenter = aCircle->center();
+
+ aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+ recalculateReversedFlagByPassed(*aCircle);
+ } else
+ myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5)));
+}
+
+void SketchPlugin_MacroArc::recalculateReversedFlagByPassed(
+ const GeomAPI_Circ2d& theCurrentCircular)
+{
+ AttributePoint2DPtr aPassedAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
+ std::shared_ptr<GeomAPI_Pnt2d> aPassed = theCurrentCircular.project(aPassedAttr->pnt());
+
+ double aEndParam, aPassedParam;
+ theCurrentCircular.parameter(myEnd, paramTolerance, aEndParam);
+ theCurrentCircular.parameter(aPassed, paramTolerance, aPassedParam);
+
+ if(aPassedParam > aEndParam)
+ boolean(REVERSED_ID())->setValue(true);
+ else
+ boolean(REVERSED_ID())->setValue(false);
+
+ myParamBefore = aEndParam;
+}
+
+void SketchPlugin_MacroArc::fillByTangentEdge()
+{
+ AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
+ if (!aTangentAttr->isInitialized())
+ return;
+
+ AttributePoint2DPtr aTangentPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
+ if (!aTangentPointAttr->isInitialized())
+ return;
+
+ AttributePoint2DPtr anEndPointAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
+ if (!anEndPointAttr->isInitialized())
+ return;
+
+ myStart = aTangentPointAttr->pnt();
+ myEnd = anEndPointAttr->pnt();
+ if (myStart->isEqual(myEnd))
+ return;
+
+ // obtain a shape the tangent point belongs to
+ FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
+ std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
+
+ GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
+ aCircBuilder.addPassingPoint(myStart);
+ aCircBuilder.addPassingPoint(myEnd);
+ aCircBuilder.addTangentCurve(aTangentShape);
+
+ std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
+ myCenter = aCircle->center();
+
+ // rebuild circle to set start point equal to zero parameter
+ aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
+ recalculateReversedFlagByEnd(*aCircle);