1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include "SketchPlugin_MacroCircle.h"
23 #include "SketchPlugin_Circle.h"
24 #include "SketchPlugin_Point.h"
25 #include "SketchPlugin_Tools.h"
26 #include "SketchPlugin_MacroArcReentrantMessage.h"
28 #include <ModelAPI_AttributeDouble.h>
29 #include <ModelAPI_AttributeRefAttr.h>
30 #include <ModelAPI_AttributeString.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_Validator.h>
33 #include <ModelAPI_Events.h>
35 #include <GeomDataAPI_Dir.h>
36 #include <GeomDataAPI_Point2D.h>
38 #include <GeomAPI_Circ2d.h>
39 #include <GeomAPI_Pnt2d.h>
40 #include <GeomAPI_Vertex.h>
42 #include <GeomAlgoAPI_Circ2dBuilder.h>
43 #include <GeomAlgoAPI_CompoundBuilder.h>
44 #include <GeomAlgoAPI_EdgeBuilder.h>
45 #include <GeomAlgoAPI_PointBuilder.h>
48 const double tolerance = 1e-7;
51 static const std::string& POINT_ID(int theIndex)
54 case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
55 case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
56 case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
59 static const std::string DUMMY;
65 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
66 : SketchPlugin_SketchEntity(),
71 void SketchPlugin_MacroCircle::initAttributes()
73 data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
74 data()->addAttribute(EDIT_CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
76 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
77 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
78 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
79 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
81 data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
82 data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
83 data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
84 data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
85 data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
86 data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
88 data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
89 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
91 string(EDIT_CIRCLE_TYPE())->setValue("");
93 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
94 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
95 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
96 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
97 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
98 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_CIRCLE_TYPE());
101 void SketchPlugin_MacroCircle::execute()
103 FeaturePtr aCircle = createCircleFeature();
105 std::string aType = string(CIRCLE_TYPE())->value();
106 if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
107 constraintsForCircleByCenterAndPassed(aCircle);
108 else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
109 constraintsForCircleByThreePoints(aCircle);
111 // message to init reentrant operation
112 static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
113 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
114 <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, this));
116 std::string anEditType = string(EDIT_CIRCLE_TYPE())->value();
117 aMessage->setTypeOfCreation(!anEditType.empty() ? anEditType : aType);
118 aMessage->setCreatedFeature(aCircle);
119 Events_Loop::loop()->send(aMessage);
122 std::string SketchPlugin_MacroCircle::processEvent(
123 const std::shared_ptr<Events_Message>& theMessage)
125 std::string aFilledAttributeName;
126 std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
127 std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
128 if (aReentrantMessage.get()) {
129 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
130 std::string aCircleType = aReentrantMessage->typeOfCreation();
132 string(CIRCLE_TYPE())->setValue(aCircleType);
134 aFilledAttributeName = CIRCLE_TYPE();
135 ObjectPtr anObject = aReentrantMessage->selectedObject();
136 AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
137 std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
139 if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
140 std::string aReferenceAttributeName;
141 if (aCircleType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS()) {
142 aFilledAttributeName = CENTER_POINT_ID();
143 aReferenceAttributeName = CENTER_POINT_REF_ID();
146 aFilledAttributeName = FIRST_POINT_ID();
147 aReferenceAttributeName = FIRST_POINT_REF_ID();
149 // fill 2d point attribute
150 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
151 attribute(aFilledAttributeName));
152 aPointAttr->setValue(aClickedPoint);
153 // fill reference attribute
154 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
155 attribute(aReferenceAttributeName));
156 if (aRefAttr.get()) {
157 if (anAttribute.get()) {
158 if (!anAttribute->owner().get() || !anAttribute->owner()->data()->isValid()) {
159 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
160 if (aCreatedFeature.get()) {
161 std::string anID = anAttribute->id();
163 if (anID == CENTER_POINT_ID())
164 anArcID = SketchPlugin_Circle::CENTER_ID();
165 anAttribute = aCreatedFeature->attribute(anArcID);
168 aRefAttr->setAttr(anAttribute);
170 else if (anObject.get()) {
171 // if presentation of previous reentrant macro arc is used, the object is invalid,
172 // we should use result of previous feature of the message(Arc)
173 if (!anObject->data()->isValid()) {
174 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
175 anObject = aCreatedFeature->lastResult();
177 aRefAttr->setObject(anObject);
181 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
183 return aFilledAttributeName;
186 void SketchPlugin_MacroCircle::constraintsForCircleByCenterAndPassed(FeaturePtr theCircleFeature)
188 // Create constraints.
189 SketchPlugin_Tools::createConstraint(
190 this, CENTER_POINT_REF_ID(),
191 theCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
193 SketchPlugin_Tools::createConstraint(
194 this, PASSED_POINT_REF_ID(), AttributePtr(),
195 theCircleFeature->lastResult(), true);
198 void SketchPlugin_MacroCircle::constraintsForCircleByThreePoints(FeaturePtr theCircleFeature)
200 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
201 SECOND_POINT_REF_ID(),
202 THIRD_POINT_REF_ID() };
204 // Create constraints.
205 ResultPtr aCircleResult = theCircleFeature->lastResult();
206 for (int i = 0; i < 3; ++i)
207 SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
210 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature()
212 FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
213 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
214 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(myCenter->x(),
216 aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(myRadius);
217 aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
218 ->setValue(boolean(AUXILIARY_ID())->value());
219 aCircleFeature->execute();
220 return aCircleFeature;
223 void SketchPlugin_MacroCircle::fillByCenterAndPassed()
225 AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
226 AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
227 if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
230 // Calculate circle parameters
231 AttributeRefAttrPtr aCenterRef = refattr(CENTER_POINT_REF_ID());
232 std::shared_ptr<GeomAPI_Pnt2d> aCenter;
233 std::shared_ptr<GeomAPI_Shape> aCurve;
234 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
235 aCenterRef, aCenterAttr, aCurve, aCenter);
237 aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
238 AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
239 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
240 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
241 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
242 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
245 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
246 aCircBuilder.setCenter(aCenter);
248 aCircBuilder.addTangentCurve(aTangentCurve);
250 AttributePoint2DPtr aPassedPntAttr =
251 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
253 aCircBuilder.setClosestPoint(aPassedPntAttr->pnt());
255 aCircBuilder.addPassingPoint(aPassedPoint);
257 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
259 myCenter = aCircle->center();
260 myRadius = aCircle->radius();
264 void SketchPlugin_MacroCircle::fillByThreePoints()
266 std::string aPointAttr[3] = { FIRST_POINT_ID(),
269 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
270 SECOND_POINT_REF_ID(),
271 THIRD_POINT_REF_ID() };
273 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
275 for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
276 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
277 if (!aPassedAttr->isInitialized())
280 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
281 // calculate circle parameters
282 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
283 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
284 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
285 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
288 aCircBuilder.addPassingPoint(aPassedPoint);
290 aCircBuilder.addTangentCurve(aTangentCurve);
291 AttributePoint2DPtr aPassedPoint =
292 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr);
294 aCircBuilder.setClosestPoint(aPassedPoint->pnt());
298 std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
300 myCenter = aCircle->center();
301 myRadius = aCircle->radius();
305 void SketchPlugin_MacroCircle::fillByTwoPassedPoints()
307 std::string aPointAttr[2] = { FIRST_POINT_ID(),
309 std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
310 SECOND_POINT_REF_ID() };
312 GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
314 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
315 bool hasTangentCurve = false;
317 for (; aPntIndex < 2; ++aPntIndex) {
318 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
319 if (!aPassedAttr->isInitialized())
322 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
323 // calculate circle parameters
324 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
325 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
326 SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
327 aPassedRef, aPassedAttr, aTangentCurve, aPassedPoint);
330 aCircBuilder.addPassingPoint(aPassedPoint);
331 aPassedPoints[aPntIndex] = aPassedPoint;
333 hasTangentCurve = true;
334 aCircBuilder.addTangentCurve(aTangentCurve);
335 // if the circle is tangent to any curve,
336 // the third point will be initialized by the tangent point
337 aCircBuilder.addPassingPoint(
338 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt());
344 std::shared_ptr<GeomAPI_Circ2d> aCircle;
347 aCircle = aCircBuilder.circle();
349 // the circle is defined by two points, calculate its parameters manually
350 std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
351 (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
352 (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
353 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
357 myCenter = aCircle->center();
358 myRadius = aCircle->radius();
362 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
364 SketchPlugin_Sketch* aSketch = sketch();
365 if(!aSketch || !myCenter || myRadius == 0) {
366 return AISObjectPtr();
369 // Compute a circle in 3D view.
370 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
371 std::shared_ptr<GeomDataAPI_Dir> aNDir =
372 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
373 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
374 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
375 GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, myRadius);
376 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
377 if(!aCircleShape.get() || !aCenterPointShape.get()) {
378 return AISObjectPtr();
381 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
382 aShapes.push_back(aCircleShape);
383 aShapes.push_back(aCenterPointShape);
385 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
386 AISObjectPtr anAIS = thePrevious;
388 anAIS.reset(new GeomAPI_AISObject());
390 anAIS->createShape(aCompound);
394 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
395 double aRadius = 0.0;
396 // If circle type switched reset all attributes.
397 if(theID == CIRCLE_TYPE()) {
398 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
399 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
400 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
401 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
402 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
403 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
404 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
405 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
406 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
407 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
408 } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID() ||
409 theID == CENTER_POINT_REF_ID() || theID == PASSED_POINT_REF_ID())
410 fillByCenterAndPassed();
411 else if(theID == FIRST_POINT_ID() || theID == FIRST_POINT_REF_ID() ||
412 theID == SECOND_POINT_ID() || theID == SECOND_POINT_REF_ID() ||
413 theID == THIRD_POINT_ID() || theID == THIRD_POINT_REF_ID()) {
414 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
415 int aNbInitialized = 0;
416 for(int i = 1; i <= 3; ++i) {
417 std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
418 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
419 if(aCurPnt->isInitialized())
420 aPoints[aNbInitialized++] = aCurPnt->pnt();
423 if(aNbInitialized == 1)
425 else if(aNbInitialized == 2)
426 fillByTwoPassedPoints();
431 AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
432 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
434 // center attribute is used in processEvent() to set reference to reentrant arc
435 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()))
436 ->setValue(myCenter);
438 aRadiusAttr->setValue(myRadius);
439 data()->blockSendAttributeUpdated(aWasBlocked, false);