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, 0));
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 aRefAttr->setAttr(anAttribute);
145 else if (anObject.get()) {
146 // if presentation of previous reentrant macro arc is used, the object is invalid,
147 // we should use result of previous feature of the message(Arc)
148 if (!anObject->data()->isValid()) {
149 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
150 anObject = aCreatedFeature->lastResult();
152 aRefAttr->setObject(anObject);
156 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
158 return aFilledAttributeName;
161 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
163 // Create constraints.
164 SketchPlugin_Tools::createConstraint(
165 this, CENTER_POINT_REF_ID(),
166 theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
168 SketchPlugin_Tools::createConstraint(
169 this, PASSED_POINT_REF_ID(), AttributePtr(),
170 theCircleFeature->lastResult(), true);
173 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
175 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
176 SECOND_POINT_REF_ID(),
177 THIRD_POINT_REF_ID() };
179 // Create constraints.
180 ResultPtr aCircleResult = theCircleFeature->lastResult();
181 for (int i = 0; i < 3; ++i)
182 SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
185 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
187 FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
188 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
189 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
191 aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
192 aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
193 ->setValue(boolean(AUXILIARY_ID())->value());
194 aCircleFeature->execute();
195 return aCircleFeature;
198 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
200 AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
201 AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
202 if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
205 AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
206 // Calculate circle parameters
207 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
208 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
209 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
210 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
211 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
212 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
215 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
216 aCircBuilder.setCenter(aCenter);
218 aCircBuilder.addTangentCurve(aTangentCurve);
220 AttributePoint2DPtr aPassedPntAttr =
221 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
223 aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
225 aCircBuilder.addPassingPoint(aPassedPoint);
227 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
229 myCenter = aCircle->center();
230 myRadius = aCircle->radius();
234 void SketchPlugin_MacroCircle::fillByThreePoints()
236 std::string aPointAttr[3] = { FIRST_POINT_ID(),
239 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
240 SECOND_POINT_REF_ID(),
241 THIRD_POINT_REF_ID() };
243 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
245 for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
246 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
247 if (!aPassedAttr->isInitialized())
250 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
251 // calculate circle parameters
252 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
253 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
254 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
255 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
258 aCircBuilder.addPassingPoint(aPassedPoint);
260 aCircBuilder.addTangentCurve(aTangentCurve);
263 AttributePoint2DPtr aThirdPoint =
264 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
266 aCircBuilder.setClosestPoint(aThirdPoint->pnt());
268 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
270 myCenter = aCircle->center();
271 myRadius = aCircle->radius();
275 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
277 std::string aPointAttr[2] = { FIRST_POINT_ID(),
279 std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
280 SECOND_POINT_REF_ID() };
282 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
284 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
286 for (; aPntIndex < 2; ++aPntIndex) {
287 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
288 if (!aPassedAttr->isInitialized())
291 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
292 // calculate circle parameters
293 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
294 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
295 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
296 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
299 aCircBuilder.addPassingPoint(aPassedPoint);
300 aPassedPoints[aPntIndex] = aPassedPoint;
302 aCircBuilder.addTangentCurve(aTangentCurve);
303 // if the circle is tangent to any curve,
304 // the third point will be initialized by the tangent point
305 aCircBuilder.addPassingPoint(
306 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
310 std::shared_ptr<GeomAPI_Circ2d> aCircle;
313 aCircle = aCircBuilder.circle();
314 else if (aPntIndex == 2) {
315 // the circle is defined by two points, calculate its parameters manually
316 std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
317 (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
318 (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
319 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
323 myCenter = aCircle->center();
324 myRadius = aCircle->radius();
328 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
330 SketchPlugin_Sketch* aSketch = sketch();
331 if(!aSketch || !myCenter || myRadius == 0) {
332 return AISObjectPtr();
335 // Compute a circle in 3D view.
336 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
337 std::shared_ptr<GeomDataAPI_Dir> aNDir =
338 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
339 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
340 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
341 GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
342 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
343 if(!aCircleShape.get() || !aCenterPointShape.get()) {
344 return AISObjectPtr();
347 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
348 aShapes.push_back(aCircleShape);
349 aShapes.push_back(aCenterPointShape);
351 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
352 AISObjectPtr anAIS = thePrevious;
354 anAIS.reset(new GeomAPI_AISObject());
356 anAIS->createShape(aCompound);
360 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
361 double aRadius = 0.0;
362 // If circle type switched reset all attributes.
363 if(theID == CIRCLE_TYPE()) {
364 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
365 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
366 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
367 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
368 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
369 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
370 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
371 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
372 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
373 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
374 } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
375 theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
376 fillByCenterAndPassed();
377 else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
378 theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
379 theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
380 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
381 int aNbInitialized = 0;
382 for(int i = 1; i <= 3; ++i) {
383 std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
384 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
385 if(aCurPnt->isInitialized())
386 aPoints[aNbInitialized++] = aCurPnt->pnt();
389 if(aNbInitialized == 1)
391 else if(aNbInitialized == 2)
392 fillByTwoPassedPoints();
397 AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
398 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
399 aRadiusAttr->setValue(myRadius);
400 data()->blockSendAttributeUpdated(aWasBlocked, false);