1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_MacroCircle.cpp
4 // Created: 26 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchPlugin_MacroCircle.h"
9 #include "SketchPlugin_Circle.h"
10 #include "SketchPlugin_Point.h"
11 #include "SketchPlugin_Tools.h"
12 #include "SketchPlugin_MacroArcReentrantMessage.h"
14 #include <ModelAPI_AttributeDouble.h>
15 #include <ModelAPI_AttributeRefAttr.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_Session.h>
18 #include <ModelAPI_Validator.h>
19 #include <ModelAPI_Events.h>
21 #include <GeomDataAPI_Dir.h>
22 #include <GeomDataAPI_Point2D.h>
24 #include <GeomAPI_Circ2d.h>
25 #include <GeomAPI_Pnt2d.h>
26 #include <GeomAPI_Vertex.h>
28 #include <GeomAlgoAPI_Circ2dBuilder.h>
29 #include <GeomAlgoAPI_CompoundBuilder.h>
30 #include <GeomAlgoAPI_EdgeBuilder.h>
31 #include <GeomAlgoAPI_PointBuilder.h>
34 const double tolerance = 1e-7;
37 static const std::string& POINT_ID(int theIndex)
40 case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
41 case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
42 case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
45 static const std::string DUMMY;
51 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
52 : SketchPlugin_SketchEntity(),
57 void SketchPlugin_MacroCircle::initAttributes()
59 data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
60 data()->addAttribute(EDIT_CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
62 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
63 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
64 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
65 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
67 data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
68 data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
69 data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
70 data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71 data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72 data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
74 data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
75 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
77 string(EDIT_CIRCLE_TYPE())->setValue("");
79 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
80 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
81 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
82 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
83 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
84 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE());
87 void SketchPlugin_MacroCircle::execute()
89 FeaturePtr aCircle = createCircleFeature();
91 std::string aType = string(CIRCLE_TYPE())->value();
92 if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
93 constraintsForCircleByCenterAndPassed(aCircle);
94 else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
95 constraintsForCircleByThreePoints(aCircle);
97 // message to init reentrant operation
98 static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
99 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
100 <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
102 std::string anEditType = string(EDIT_CIRCLE_TYPE())->value();
103 aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
104 aMessage->setCreatedFeature(aCircle);
105 Events_Loop::loop()->send(aMessage);
108 std::string SketchPlugin_MacroCircle::processEvent(
109 const std::shared_ptr<Events_Message>& theMessage)
111 std::string aFilledAttributeName;
112 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
113 std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
114 if (aReentrantMessage.get()) {
115 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
116 std::string aCircleType = aReentrantMessage->typeOfCreation();
118 string(CIRCLE_TYPE())->setValue(aCircleType);
120 aFilledAttributeName = CIRCLE_TYPE();
121 ObjectPtr anObject = aReentrantMessage->selectedObject();
122 AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
123 std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
125 if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
126 std::string aReferenceAttributeName;
127 if (aCircleType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
128 aFilledAttributeName = CENTER_POINT_ID();
129 aReferenceAttributeName = CENTER_POINT_REF_ID();
132 aFilledAttributeName = FIRST_POINT_ID();
133 aReferenceAttributeName = FIRST_POINT_REF_ID();
135 // fill 2d point attribute
136 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
137 attribute(aFilledAttributeName));
138 aPointAttr->setValue(aClickedPoint);
139 // fill reference attribute
140 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
141 attribute(aReferenceAttributeName));
142 if (aRefAttr.get()) {
143 if (anAttribute.get()) {
144 if (!anAttribute->owner().get() || !anAttribute->owner()->data()->isValid()) {
145 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
146 if (aCreatedFeature.get()) {
147 std::string anID = anAttribute->id();
149 if (anID == CENTER_POINT_ID())
150 anArcID = SketchPlugin_Circle::CENTER_ID();
151 anAttribute = aCreatedFeature->attribute(anArcID);
154 aRefAttr->setAttr(anAttribute);
156 else if (anObject.get()) {
157 // if presentation of previous reentrant macro arc is used, the object is invalid,
158 // we should use result of previous feature of the message(Arc)
159 if (!anObject->data()->isValid()) {
160 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
161 anObject = aCreatedFeature->lastResult();
163 aRefAttr->setObject(anObject);
167 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
169 return aFilledAttributeName;
172 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
174 // Create constraints.
175 SketchPlugin_Tools::createConstraint(
176 this, CENTER_POINT_REF_ID(),
177 theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
179 SketchPlugin_Tools::createConstraint(
180 this, PASSED_POINT_REF_ID(), AttributePtr(),
181 theCircleFeature->lastResult(), true);
184 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
186 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
187 SECOND_POINT_REF_ID(),
188 THIRD_POINT_REF_ID() };
190 // Create constraints.
191 ResultPtr aCircleResult = theCircleFeature->lastResult();
192 for (int i = 0; i < 3; ++i)
193 SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
196 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
198 FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
199 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
200 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
202 aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
203 aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
204 ->setValue(boolean(AUXILIARY_ID())->value());
205 aCircleFeature->execute();
206 return aCircleFeature;
209 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
211 AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
212 AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
213 if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
216 AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
217 // Calculate circle parameters
218 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
219 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
220 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
221 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
222 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
223 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
226 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
227 aCircBuilder.setCenter(aCenter);
229 aCircBuilder.addTangentCurve(aTangentCurve);
231 AttributePoint2DPtr aPassedPntAttr =
232 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
234 aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
236 aCircBuilder.addPassingPoint(aPassedPoint);
238 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
240 myCenter = aCircle->center();
241 myRadius = aCircle->radius();
245 void SketchPlugin_MacroCircle::fillByThreePoints()
247 std::string aPointAttr[3] = { FIRST_POINT_ID(),
250 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
251 SECOND_POINT_REF_ID(),
252 THIRD_POINT_REF_ID() };
254 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
256 for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
257 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
258 if (!aPassedAttr->isInitialized())
261 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
262 // calculate circle parameters
263 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
264 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
265 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
266 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
269 aCircBuilder.addPassingPoint(aPassedPoint);
271 aCircBuilder.addTangentCurve(aTangentCurve);
272 AttributePoint2DPtr aPassedPoint =
273 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
275 aCircBuilder.setClosestPoint(aPassedPoint->pnt());
279 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
281 myCenter = aCircle->center();
282 myRadius = aCircle->radius();
286 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
288 std::string aPointAttr[2] = { FIRST_POINT_ID(),
290 std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
291 SECOND_POINT_REF_ID() };
293 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
295 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
296 bool hasTangentCurve = false;
298 for (; aPntIndex < 2; ++aPntIndex) {
299 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
300 if (!aPassedAttr->isInitialized())
303 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
304 // calculate circle parameters
305 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
306 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
307 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
308 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
311 aCircBuilder.addPassingPoint(aPassedPoint);
312 aPassedPoints[aPntIndex] = aPassedPoint;
314 hasTangentCurve = true;
315 aCircBuilder.addTangentCurve(aTangentCurve);
316 // if the circle is tangent to any curve,
317 // the third point will be initialized by the tangent point
318 aCircBuilder.addPassingPoint(
319 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
325 std::shared_ptr<GeomAPI_Circ2d> aCircle;
328 aCircle = aCircBuilder.circle();
330 // the circle is defined by two points, calculate its parameters manually
331 std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
332 (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
333 (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
334 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
338 myCenter = aCircle->center();
339 myRadius = aCircle->radius();
343 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
345 SketchPlugin_Sketch* aSketch = sketch();
346 if(!aSketch || !myCenter || myRadius == 0) {
347 return AISObjectPtr();
350 // Compute a circle in 3D view.
351 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
352 std::shared_ptr<GeomDataAPI_Dir> aNDir =
353 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
354 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
355 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
356 GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
357 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
358 if(!aCircleShape.get() || !aCenterPointShape.get()) {
359 return AISObjectPtr();
362 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
363 aShapes.push_back(aCircleShape);
364 aShapes.push_back(aCenterPointShape);
366 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
367 AISObjectPtr anAIS = thePrevious;
369 anAIS.reset(new GeomAPI_AISObject());
371 anAIS->createShape(aCompound);
375 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
376 double aRadius = 0.0;
377 // If circle type switched reset all attributes.
378 if(theID == CIRCLE_TYPE()) {
379 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
380 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
381 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
382 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
383 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
384 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
385 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
386 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
387 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
388 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
389 } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
390 theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
391 fillByCenterAndPassed();
392 else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
393 theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
394 theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
395 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
396 int aNbInitialized = 0;
397 for(int i = 1; i <= 3; ++i) {
398 std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
399 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
400 if(aCurPnt->isInitialized())
401 aPoints[aNbInitialized++] = aCurPnt->pnt();
404 if(aNbInitialized == 1)
406 else if(aNbInitialized == 2)
407 fillByTwoPassedPoints();
412 AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
413 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
415 // center attribute is used in processEvent() to set reference to reentrant arc
416 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))
417 ->setValue(myCenter);
419 aRadiusAttr->setValue(myRadius);
420 data()->blockSendAttributeUpdated(aWasBlocked, false);