1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_MacroArc.cpp
4 // Created: 26 Apr 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchPlugin_MacroArc.h"
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_ConstraintTangent.h"
11 #include "SketchPlugin_Sketch.h"
12 #include "SketchPlugin_Tools.h"
13 #include "SketchPlugin_MacroArcReentrantMessage.h"
15 #include <ModelAPI_AttributeDouble.h>
16 #include <ModelAPI_AttributeRefAttr.h>
17 #include <ModelAPI_AttributeString.h>
18 #include <ModelAPI_Events.h>
19 #include <ModelAPI_Session.h>
20 #include <ModelAPI_Validator.h>
22 #include <GeomAPI_Circ.h>
23 #include <GeomAPI_Circ2d.h>
24 #include <GeomAPI_Curve.h>
25 #include <GeomAPI_Dir2d.h>
26 #include <GeomAPI_Edge.h>
27 #include <GeomAPI_Lin.h>
28 #include <GeomAPI_Lin2d.h>
29 #include <GeomAPI_Pnt2d.h>
30 #include <GeomAPI_Vertex.h>
31 #include <GeomAPI_XY.h>
33 #include <GeomDataAPI_Point2D.h>
34 #include <GeomDataAPI_Dir.h>
36 #include <GeomAlgoAPI_Circ2dBuilder.h>
37 #include <GeomAlgoAPI_EdgeBuilder.h>
38 #include <GeomAlgoAPI_CompoundBuilder.h>
39 #include <GeomAlgoAPI_PointBuilder.h>
44 const double tolerance = 1e-7;
45 const double paramTolerance = 1.e-4;
46 const double PI = 3.141592653589793238463;
48 static void projectPointOnCircle(AttributePoint2DPtr& thePoint, const GeomAPI_Circ2d& theCircle)
50 std::shared_ptr<GeomAPI_Pnt2d> aProjection = theCircle.project(thePoint->pnt());
52 thePoint->setValue(aProjection);
56 SketchPlugin_MacroArc::SketchPlugin_MacroArc()
57 : SketchPlugin_SketchEntity(),
62 void SketchPlugin_MacroArc::initAttributes()
64 data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId());
66 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
67 data()->addAttribute(START_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
68 data()->addAttribute(END_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
70 data()->addAttribute(START_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
71 data()->addAttribute(END_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
72 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
74 data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
75 data()->addAttribute(END_POINT_3_ID(), GeomDataAPI_Point2D::typeId());
77 data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
79 data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
80 data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
82 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
84 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
85 data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
86 data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
87 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
89 data()->addAttribute(EDIT_ARC_TYPE_ID(), ModelAPI_AttributeString::typeId());
91 boolean(REVERSED_ID())->setValue(false);
92 string(EDIT_ARC_TYPE_ID())->setValue("");
94 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
95 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
96 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
97 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
98 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_ARC_TYPE_ID());
101 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
103 std::string anArcType = string(ARC_TYPE())->value();
105 // If arc type switched reset according attributes.
106 if(theID == ARC_TYPE()) {
107 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
108 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
109 SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
110 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
111 SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
112 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
113 SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
114 SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
115 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
116 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
117 SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
118 SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
119 SketchPlugin_Tools::resetAttribute(this, REVERSED_ID());
120 SketchPlugin_Tools::resetAttribute(this, RADIUS_ID());
121 SketchPlugin_Tools::resetAttribute(this, ANGLE_ID());
126 boolean(REVERSED_ID())->setValue(false);
128 } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS())
129 fillByCenterAndTwoPassed();
130 else if(anArcType == ARC_TYPE_BY_THREE_POINTS())
131 fillByThreePassedPoints();
132 else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE())
137 if(myCenter.get() && myStart.get()) {
138 aRadius = myCenter->distance(myStart);
140 if(myStart->isEqual(myEnd)) {
143 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
144 double aStartParam, anEndParam;
145 aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
146 aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
147 anAngle = (anEndParam - aStartParam) / PI * 180.0;
148 if(boolean(REVERSED_ID())->value()) anAngle = 360.0 - anAngle;
153 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
154 real(RADIUS_ID())->setValue(aRadius);
155 real(ANGLE_ID())->setValue(anAngle);
156 data()->blockSendAttributeUpdated(aWasBlocked, false);
159 GeomShapePtr SketchPlugin_MacroArc::getArcShape()
161 if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
162 return GeomShapePtr();
165 SketchPlugin_Sketch* aSketch = sketch();
167 return GeomShapePtr();
170 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
171 std::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(myStart->x(), myStart->y()));
172 std::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(myEnd->x(), myEnd->y()));
173 std::shared_ptr<GeomDataAPI_Dir> aNDir =
174 std::dynamic_pointer_cast<GeomDataAPI_Dir>(aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
175 std::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
177 GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
178 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
179 : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
184 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
186 if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
187 return AISObjectPtr();
190 SketchPlugin_Sketch* aSketch = sketch();
192 return AISObjectPtr();
195 GeomShapePtr anArcShape = getArcShape();
196 std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
197 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
199 if(!anArcShape.get() || !aCenterPointShape.get()) {
200 return AISObjectPtr();
203 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
204 aShapes.push_back(anArcShape);
205 aShapes.push_back(aCenterPointShape);
207 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
208 AISObjectPtr anAIS = thePrevious;
210 anAIS.reset(new GeomAPI_AISObject());
212 anAIS->createShape(aCompound);
216 void SketchPlugin_MacroArc::execute()
218 FeaturePtr anArcFeature = createArcFeature();
224 // Create constraints.
225 std::string anArcType = string(ARC_TYPE())->value();
226 if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
227 SketchPlugin_Tools::createConstraint(this,
228 CENTER_POINT_REF_ID(),
229 anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
232 SketchPlugin_Tools::createConstraint(this,
233 START_POINT_REF_ID(),
234 anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
237 SketchPlugin_Tools::createConstraint(this,
239 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
242 } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
243 SketchPlugin_Tools::createConstraint(this,
244 START_POINT_REF_ID(),
245 anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
248 SketchPlugin_Tools::createConstraint(this,
250 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
253 SketchPlugin_Tools::createConstraint(this,
254 PASSED_POINT_REF_ID(),
256 anArcFeature->lastResult(),
258 } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
259 // constraints for tangent arc
260 SketchPlugin_Tools::createConstraint(this,
262 anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
265 FeaturePtr aTangent = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
266 AttributeRefAttrPtr aRefAttrA = aTangent->refattr(SketchPlugin_Constraint::ENTITY_A());
267 AttributeRefAttrPtr aTgPntRefAttr = refattr(TANGENT_POINT_ID());
268 FeaturePtr aTgFeature = ModelAPI_Feature::feature(aTgPntRefAttr->attr()->owner());
269 aRefAttrA->setObject(aTgFeature->lastResult());
270 AttributeRefAttrPtr aRefAttrB = aTangent->refattr(SketchPlugin_Constraint::ENTITY_B());
271 aRefAttrB->setObject(anArcFeature->lastResult());
272 // constraint for end point
273 SketchPlugin_Tools::createConstraint(this,
275 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
280 // message to init reentrant operation
281 static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
282 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
283 <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, 0));
285 std::string anEditArcType = string(EDIT_ARC_TYPE_ID())->value();
286 aMessage->setTypeOfCreation(!anEditArcType.empty() ? anEditArcType : anArcType);
287 aMessage->setCreatedFeature(anArcFeature);
288 Events_Loop::loop()->send(aMessage);
291 std::string SketchPlugin_MacroArc::processEvent(const std::shared_ptr<Events_Message>& theMessage)
293 std::string aFilledAttributeName;
294 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
295 std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
296 if (aReentrantMessage.get()) {
297 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
298 std::string anArcType = aReentrantMessage->typeOfCreation();
300 string(ARC_TYPE())->setValue(anArcType);
302 aFilledAttributeName = ARC_TYPE();
303 if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
304 aFilledAttributeName = TANGENT_POINT_ID();
305 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
306 attribute(aFilledAttributeName));
307 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
308 aRefAttr->setAttr(aCreatedFeature->attribute(SketchPlugin_Arc::END_ID()));
311 ObjectPtr anObject = aReentrantMessage->selectedObject();
312 AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
313 std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
315 if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
316 if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS() ||
317 anArcType == ARC_TYPE_BY_THREE_POINTS()) {
318 std::string aReferenceAttributeName;
319 if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
320 aFilledAttributeName = CENTER_POINT_ID();
321 aReferenceAttributeName = CENTER_POINT_REF_ID();
324 aFilledAttributeName = START_POINT_2_ID();
325 aReferenceAttributeName = START_POINT_REF_ID();
327 // fill 2d point attribute
328 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
329 attribute(aFilledAttributeName));
330 aPointAttr->setValue(aClickedPoint);
331 // fill reference attribute
332 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
333 attribute(aReferenceAttributeName));
334 if (aRefAttr.get()) {
335 if (anAttribute.get())
336 aRefAttr->setAttr(anAttribute);
337 else if (anObject.get()) {
338 // if presentation of previous reentrant macro arc is used, the object is invalid,
339 // we should use result of previous feature of the message(Arc)
340 if (!anObject->data()->isValid()) {
341 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
342 anObject = aCreatedFeature->lastResult();
344 aRefAttr->setObject(anObject);
350 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
352 return aFilledAttributeName;
355 FeaturePtr SketchPlugin_MacroArc::createArcFeature()
357 FeaturePtr anArcFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
358 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
359 anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenter);
360 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
361 anArcFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(myStart);
362 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
363 anArcFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(myEnd);
364 anArcFeature->boolean(SketchPlugin_Arc::REVERSED_ID())
365 ->setValue(boolean(REVERSED_ID())->value());
366 anArcFeature->boolean(SketchPlugin_Arc::AUXILIARY_ID())
367 ->setValue(boolean(AUXILIARY_ID())->value());
368 anArcFeature->execute();
373 void SketchPlugin_MacroArc::fillByCenterAndTwoPassed()
375 AttributePoint2DPtr aCenterPointAttr =
376 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
377 if (!aCenterPointAttr->isInitialized())
380 AttributePoint2DPtr aStartPointAttr =
381 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
382 if (!aStartPointAttr->isInitialized())
385 myCenter = aCenterPointAttr->pnt();
386 myStart = aStartPointAttr->pnt();
389 AttributePoint2DPtr anEndPointAttr =
390 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
391 if (!anEndPointAttr->isInitialized())
394 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
396 // End point should be a projection on circle.
397 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
398 projectPointOnCircle(anEndPointAttr, aCircleForArc);
399 data()->blockSendAttributeUpdated(aWasBlocked, false);
400 myEnd = anEndPointAttr->pnt();
402 // update the REVERSED flag
403 recalculateReversedFlagByEnd(aCircleForArc);
406 void SketchPlugin_MacroArc::recalculateReversedFlagByEnd(const GeomAPI_Circ2d& theCurrentCircular)
408 double aParameterNew = 0.0;
409 if(theCurrentCircular.parameter(myEnd, paramTolerance, aParameterNew)) {
410 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
411 boolean(REVERSED_ID())->setValue(true);
412 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
413 boolean(REVERSED_ID())->setValue(false);
416 myParamBefore = aParameterNew;
419 void SketchPlugin_MacroArc::fillByThreePassedPoints()
421 AttributePoint2DPtr aStartPointAttr =
422 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
423 if (!aStartPointAttr->isInitialized())
426 AttributePoint2DPtr anEndPointAttr =
427 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
428 if (!anEndPointAttr->isInitialized())
431 myStart = aStartPointAttr->pnt();
432 myEnd = anEndPointAttr->pnt();
434 AttributePoint2DPtr aPassedPointAttr =
435 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
436 if (aPassedPointAttr->isInitialized()) {
437 std::shared_ptr<GeomAPI_Pnt2d> aPassedPnt;
438 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
439 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
440 refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt);
442 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
443 aCircBuilder.addPassingPoint(myStart);
444 aCircBuilder.addPassingPoint(myEnd);
446 aCircBuilder.addTangentCurve(aTangentCurve);
447 aCircBuilder.setClosestPoint(aPassedPointAttr->pnt());
449 aCircBuilder.addPassingPoint(aPassedPnt);
451 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
454 myCenter = aCircle->center();
456 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
457 recalculateReversedFlagByPassed(*aCircle);
459 myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5)));
462 void SketchPlugin_MacroArc::recalculateReversedFlagByPassed(
463 const GeomAPI_Circ2d& theCurrentCircular)
465 AttributePoint2DPtr aPassedAttr =
466 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
467 std::shared_ptr<GeomAPI_Pnt2d> aPassed = theCurrentCircular.project(aPassedAttr->pnt());
469 double aEndParam, aPassedParam;
470 theCurrentCircular.parameter(myEnd, paramTolerance, aEndParam);
471 theCurrentCircular.parameter(aPassed, paramTolerance, aPassedParam);
473 if(aPassedParam > aEndParam)
474 boolean(REVERSED_ID())->setValue(true);
476 boolean(REVERSED_ID())->setValue(false);
478 myParamBefore = aEndParam;
481 void SketchPlugin_MacroArc::fillByTangentEdge()
483 AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
484 if (!aTangentAttr->isInitialized())
487 AttributePoint2DPtr aTangentPointAttr =
488 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
489 if (!aTangentPointAttr->isInitialized())
492 AttributePoint2DPtr anEndPointAttr =
493 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
494 if (!anEndPointAttr->isInitialized())
497 myStart = aTangentPointAttr->pnt();
498 myEnd = anEndPointAttr->pnt();
499 if (myStart->isEqual(myEnd))
502 // obtain a shape the tangent point belongs to
503 FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
504 std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
506 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
507 aCircBuilder.addPassingPoint(myStart);
508 aCircBuilder.addPassingPoint(myEnd);
509 aCircBuilder.addTangentCurve(aTangentShape);
511 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
512 myCenter = aCircle->center();
514 // rebuild circle to set start point equal to zero parameter
515 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
516 recalculateReversedFlagByEnd(*aCircle);