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_CompoundBuilder.h>
29 #include <GeomAlgoAPI_EdgeBuilder.h>
30 #include <GeomAlgoAPI_PointBuilder.h>
33 const double tolerance = 1e-7;
36 static const std::string& POINT_ID(int theIndex)
39 case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
40 case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
41 case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
44 static const std::string DUMMY;
50 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
51 : SketchPlugin_SketchEntity(),
56 void SketchPlugin_MacroCircle::initAttributes()
58 data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
59 data()->addAttribute(EDIT_CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
61 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
62 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
63 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
64 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66 data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
67 data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
68 data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
69 data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
70 data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71 data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73 data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
74 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
76 string(EDIT_CIRCLE_TYPE())->setValue("");
78 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
79 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
80 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
81 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
82 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
83 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE());
86 void SketchPlugin_MacroCircle::execute()
88 FeaturePtr aCircle = createCircleFeature();
90 std::string aType = string(CIRCLE_TYPE())->value();
91 if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
92 constraintsForCircleByCenterAndPassed(aCircle);
93 else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
94 constraintsForCircleByThreePoints(aCircle);
96 // message to init reentrant operation
97 static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
98 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
99 <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, 0));
101 std::string anEditType = string(EDIT_CIRCLE_TYPE())->value();
102 aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
103 aMessage->setCreatedFeature(aCircle);
104 Events_Loop::loop()->send(aMessage);
107 std::string SketchPlugin_MacroCircle::processEvent(
108 const std::shared_ptr<Events_Message>& theMessage)
110 std::string aFilledAttributeName;
111 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
112 std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
113 if (aReentrantMessage.get()) {
114 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
115 std::string aCircleType = aReentrantMessage->typeOfCreation();
117 string(CIRCLE_TYPE())->setValue(aCircleType);
119 aFilledAttributeName = CIRCLE_TYPE();
120 ObjectPtr anObject = aReentrantMessage->selectedObject();
121 AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
122 std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
124 if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
125 std::string aReferenceAttributeName;
126 if (aCircleType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
127 aFilledAttributeName = CENTER_POINT_ID();
128 aReferenceAttributeName = CENTER_POINT_REF_ID();
131 aFilledAttributeName = FIRST_POINT_ID();
132 aReferenceAttributeName = FIRST_POINT_REF_ID();
134 // fill 2d point attribute
135 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
136 attribute(aFilledAttributeName));
137 aPointAttr->setValue(aClickedPoint);
138 // fill reference attribute
139 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
140 attribute(aReferenceAttributeName));
141 if (aRefAttr.get()) {
142 if (anAttribute.get())
143 aRefAttr->setAttr(anAttribute);
144 else if (anObject.get()) {
145 // if presentation of previous reentrant macro arc is used, the object is invalid,
146 // we should use result of previous feature of the message(Arc)
147 if (!anObject->data()->isValid()) {
148 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
149 anObject = aCreatedFeature->lastResult();
151 aRefAttr->setObject(anObject);
155 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
157 return aFilledAttributeName;
160 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
162 // Create constraints.
163 SketchPlugin_Tools::createConstraint(
164 this, CENTER_POINT_REF_ID(),
165 theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
167 SketchPlugin_Tools::createConstraint(
168 this, PASSED_POINT_REF_ID(), AttributePtr(),
169 theCircleFeature->lastResult(), true);
172 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
174 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
175 SECOND_POINT_REF_ID(),
176 THIRD_POINT_REF_ID() };
178 // Create constraints.
179 ResultPtr aCircleResult = theCircleFeature->lastResult();
180 for (int i = 0; i < 3; ++i)
181 SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
184 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
186 FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
187 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
188 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
190 aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
191 aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
192 ->setValue(boolean(AUXILIARY_ID())->value());
193 aCircleFeature->execute();
194 return aCircleFeature;
197 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
199 AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
200 AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
201 if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
204 AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
205 // Calculate circle parameters
206 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
207 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
208 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
209 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
210 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
211 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
214 std::shared_ptr<GeomAPI_Circ2d> aCircle;
216 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
217 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
219 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
220 if (aCircle->implPtr<char>()) {
221 myCenter = aCircle->center();
222 myRadius = aCircle->radius();
226 void SketchPlugin_MacroCircle::fillByThreePoints()
228 std::string aPointAttr[3] = { FIRST_POINT_ID(),
231 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
232 SECOND_POINT_REF_ID(),
233 THIRD_POINT_REF_ID() };
234 std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
235 for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
236 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
237 if (!aPassedAttr->isInitialized())
240 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
241 // calculate circle parameters
242 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
243 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
244 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
245 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
248 aPassedEntities[aPntIndex] = aPassedPoint;
250 aPassedEntities[aPntIndex] = aTangentCurve;
253 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
254 std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
255 new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
256 if (aCircle->implPtr<char>()) {
257 myCenter = aCircle->center();
258 myRadius = aCircle->radius();
262 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
264 std::string aPointAttr[2] = { FIRST_POINT_ID(),
266 std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
267 SECOND_POINT_REF_ID() };
268 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
269 std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
271 for (; aPntIndex < 2; ++aPntIndex) {
272 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
273 if (!aPassedAttr->isInitialized())
276 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
277 // calculate circle parameters
278 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
279 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
280 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
281 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
284 aPassedEntities[aPntIndex] = aPassedPoint;
285 aPassedPoints[aPntIndex] = aPassedPoint;
287 aPassedEntities[aPntIndex] = aTangentCurve;
288 // if the circle is tangent to any curve,
289 // the third point will be initialized by the tangent point
290 aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
296 std::shared_ptr<GeomAPI_Circ2d> aCircle;
297 if (aPassedEntities[2]) {
298 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
299 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
300 new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
302 // the circle is defined by two points, calculate its parameters manually
303 std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
304 (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
305 (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
306 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
308 if (aCircle->implPtr<char>()) {
309 myCenter = aCircle->center();
310 myRadius = aCircle->radius();
314 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
316 SketchPlugin_Sketch* aSketch = sketch();
317 if(!aSketch || !myCenter || myRadius == 0) {
318 return AISObjectPtr();
321 // Compute a circle in 3D view.
322 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
323 std::shared_ptr<GeomDataAPI_Dir> aNDir =
324 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
325 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
326 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
327 GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
328 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
329 if(!aCircleShape.get() || !aCenterPointShape.get()) {
330 return AISObjectPtr();
333 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
334 aShapes.push_back(aCircleShape);
335 aShapes.push_back(aCenterPointShape);
337 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
338 AISObjectPtr anAIS = thePrevious;
340 anAIS.reset(new GeomAPI_AISObject());
342 anAIS->createShape(aCompound);
346 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
347 double aRadius = 0.0;
348 // If circle type switched reset all attributes.
349 if(theID == CIRCLE_TYPE()) {
350 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
351 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
352 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
353 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
354 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
355 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
356 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
357 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
358 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
359 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
360 } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
361 theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
362 fillByCenterAndPassed();
363 else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
364 theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
365 theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
366 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
367 int aNbInitialized = 0;
368 for(int i = 1; i <= 3; ++i) {
369 std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
370 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
371 if(aCurPnt->isInitialized())
372 aPoints[aNbInitialized++] = aCurPnt->pnt();
375 if(aNbInitialized == 1)
377 else if(aNbInitialized == 2)
378 fillByTwoPassedPoints();
383 AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
384 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
385 aRadiusAttr->setValue(myRadius);
386 data()->blockSendAttributeUpdated(aWasBlocked, false);