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_Sketch.h"
11 #include "SketchPlugin_Tools.h"
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeRefAttr.h>
15 #include <ModelAPI_AttributeString.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
19 #include <GeomAPI_Circ.h>
20 #include <GeomAPI_Circ2d.h>
21 #include <GeomAPI_Dir2d.h>
22 #include <GeomAPI_Edge.h>
23 #include <GeomAPI_Lin.h>
24 #include <GeomAPI_Lin2d.h>
25 #include <GeomAPI_Pnt2d.h>
26 #include <GeomAPI_Vertex.h>
27 #include <GeomAPI_XY.h>
29 #include <GeomDataAPI_Point2D.h>
30 #include <GeomDataAPI_Dir.h>
31 #include <GeomAlgoAPI_PointBuilder.h>
32 #include <GeomAlgoAPI_EdgeBuilder.h>
33 #include <GeomAlgoAPI_CompoundBuilder.h>
38 const double tolerance = 1e-7;
39 const double paramTolerance = 1.e-4;
40 const double PI = 3.141592653589793238463;
43 SketchPlugin_MacroArc::SketchPlugin_MacroArc()
44 : SketchPlugin_SketchEntity(),
49 void SketchPlugin_MacroArc::initAttributes()
51 data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId());
53 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
54 data()->addAttribute(START_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
55 data()->addAttribute(END_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
57 data()->addAttribute(START_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
58 data()->addAttribute(END_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
59 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
61 data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
62 data()->addAttribute(END_POINT_3_ID(), GeomDataAPI_Point2D::typeId());
64 data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
66 data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
67 data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
69 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
71 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72 data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73 data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
74 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
76 boolean(REVERSED_ID())->setValue(false);
78 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
79 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
80 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
81 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
84 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
86 std::string anArcType = string(ARC_TYPE())->value();
88 // If arc type switched reset according attributes.
89 if(theID == ARC_TYPE()) {
90 std::string aType = string(ARC_TYPE())->value();
91 if(aType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
92 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
93 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
94 SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
95 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
96 SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
97 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
98 } else if(aType == ARC_TYPE_BY_THREE_POINTS()) {
99 SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
100 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
101 SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
102 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
103 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
104 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
105 } else if(aType == ARC_TYPE_BY_TANGENT_EDGE()) {
106 SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
107 SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
108 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
114 boolean(REVERSED_ID())->setValue(false);
116 } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
117 std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
118 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
119 if(!aCenterPointAttr->isInitialized()) {
122 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
123 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
124 if(!aStartPointAttr->isInitialized()) {
128 myCenter = aCenterPointAttr->pnt();
129 myStart = aStartPointAttr->pnt();
132 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
133 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
134 if(anEndPointAttr->isInitialized()) {
135 // End point should be a projection on circle.
136 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
137 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc.project(anEndPointAttr->pnt());
138 if(aProjection.get()) {
139 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
140 anEndPointAttr->setValue(aProjection);
141 data()->blockSendAttributeUpdated(aWasBlocked, false);
143 myEnd = anEndPointAttr->pnt();
145 double aParameterNew = 0.0;
146 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
147 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
148 boolean(REVERSED_ID())->setValue(true);
149 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
150 boolean(REVERSED_ID())->setValue(false);
153 myParamBefore = aParameterNew;
155 } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
156 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
157 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
158 if(!aStartPointAttr->isInitialized()) {
161 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
162 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
163 if(!anEndPointAttr->isInitialized()) {
167 myStart = aStartPointAttr->pnt();
168 myEnd = anEndPointAttr->pnt();
170 std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
171 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
172 if(aPassedPointAttr->isInitialized()) {
173 std::shared_ptr<GeomAPI_Pnt2d> aPassed = aPassedPointAttr->pnt();
174 GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed);
175 myCenter = aCircle.center();
176 aCircle = GeomAPI_Circ2d(myCenter, myStart);
177 double anEndParam, aPassedParam;
178 aCircle.parameter(myEnd, paramTolerance, anEndParam);
179 aCircle.parameter(aPassed, paramTolerance, aPassedParam);
180 if(aPassedParam > anEndParam) {
181 boolean(REVERSED_ID())->setValue(true);
183 boolean(REVERSED_ID())->setValue(false);
186 std::shared_ptr<GeomAPI_XY> aDir = myEnd->xy()->decreased(myStart->xy())->multiplied(0.5);
187 double x = aDir->x();
188 double y = aDir->y();
191 myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(aDir)));
193 } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
194 AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
195 if(!aTangentAttr->isInitialized()) {
198 std::shared_ptr<GeomDataAPI_Point2D> aTangentPointAttr =
199 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
200 if(!aTangentPointAttr->isInitialized()) {
203 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
204 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
205 if(!anEndPointAttr->isInitialized()) {
209 myStart = aTangentPointAttr->pnt();
210 myEnd = anEndPointAttr->pnt();
212 if(myStart->isEqual(myEnd)) {
216 SketchPlugin_Sketch* aSketch = sketch();
221 std::shared_ptr<GeomAPI_Dir2d> anOrthoDir;
222 FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
223 std::shared_ptr<GeomAPI_Edge> aTangEdge =
224 std::dynamic_pointer_cast<GeomAPI_Edge>(aTangFeature->lastResult()->shape());
225 if(aTangEdge->isLine()) {
226 std::shared_ptr<GeomAPI_Dir> aDir = aTangEdge->line()->direction();
227 std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aDir->x(), aDir->y(), aDir->z()));
228 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aSketch->to2D(aPnt);
229 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aPnt2d->y(), aPnt2d->x()));
231 else if (aTangEdge->isArc()) {
232 std::shared_ptr<GeomAPI_Pnt> aCenter = aTangEdge->circle()->center();
233 std::shared_ptr<GeomAPI_Pnt2d> aCenter2d = aSketch->to2D(aCenter);
234 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(
235 new GeomAPI_Dir2d(myStart->xy()->decreased(aCenter2d->xy())));
238 // compute parameters of the middle perpendicular
239 std::shared_ptr<GeomAPI_XY> aEndPntCoord = myEnd->xy();
240 std::shared_ptr<GeomAPI_XY> aTempDir = aEndPntCoord->decreased(myStart->xy());
241 std::shared_ptr<GeomAPI_Dir2d> aMidDir(new GeomAPI_Dir2d(-aTempDir->y(), aTempDir->x()));
242 std::shared_ptr<GeomAPI_Pnt2d> aMidPnt(
243 new GeomAPI_Pnt2d(aEndPntCoord->added(myStart->xy())->multiplied(0.5)));
245 // compute center of arc by calculating intersection of
246 // orthogonal line and middle perpendicular
247 std::shared_ptr<GeomAPI_Lin2d> anOrthoLine(new GeomAPI_Lin2d(myStart, anOrthoDir));
248 std::shared_ptr<GeomAPI_Lin2d> aMiddleLine(new GeomAPI_Lin2d(aMidPnt, aMidDir));
249 std::shared_ptr<GeomAPI_Pnt2d> aCenter = anOrthoLine->intersect(aMiddleLine);
254 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
255 double aParameterNew = 0.0;
256 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
257 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
258 if(!boolean(REVERSED_ID())->value()) {
259 boolean(REVERSED_ID())->setValue(true);
261 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
262 if(boolean(REVERSED_ID())->value()) {
263 boolean(REVERSED_ID())->setValue(false);
267 myParamBefore = aParameterNew;
272 if(myCenter.get() && myStart.get()) {
273 aRadius = myCenter->distance(myStart);
275 if(myStart->isEqual(myEnd)) {
278 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
279 double aStartParam, anEndParam;
280 aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
281 aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
282 anAngle = (anEndParam - aStartParam) / PI * 180.0;
283 if(boolean(REVERSED_ID())->value()) anAngle = 360.0 - anAngle;
288 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
289 real(RADIUS_ID())->setValue(aRadius);
290 real(ANGLE_ID())->setValue(anAngle);
291 data()->blockSendAttributeUpdated(aWasBlocked, false);
294 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
296 if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
297 return AISObjectPtr();
300 SketchPlugin_Sketch* aSketch = sketch();
302 return AISObjectPtr();
305 std::shared_ptr<GeomAPI_Pnt> aStart = aSketch->to3D(myStart->x(), myStart->y());
306 std::shared_ptr<GeomAPI_Pnt> anEnd = aSketch->to3D(myEnd->x(), myEnd->y());
307 std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
309 std::shared_ptr<GeomDataAPI_Dir> aNDir =
310 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
311 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
312 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
313 GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
314 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
315 : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
316 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
318 if(!anArcShape.get() || !aCenterPointShape.get()) {
319 return AISObjectPtr();
322 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
323 aShapes.push_back(anArcShape);
324 aShapes.push_back(aCenterPointShape);
326 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
327 AISObjectPtr anAIS = thePrevious;
329 anAIS.reset(new GeomAPI_AISObject());
331 anAIS->createShape(aCompound);
335 void SketchPlugin_MacroArc::execute()
337 // Create arc feature.
338 FeaturePtr anArcFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
339 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
340 anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenter);
341 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
342 anArcFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(myStart);
343 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
344 anArcFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(myEnd);
345 anArcFeature->boolean(SketchPlugin_Arc::REVERSED_ID())
346 ->setValue(boolean(REVERSED_ID())->value());
347 anArcFeature->execute();
353 // Create constraints.
354 std::string anArcType = string(ARC_TYPE())->value();
355 if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
356 SketchPlugin_Tools::createConstraint(this,
357 CENTER_POINT_REF_ID(),
358 anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
361 SketchPlugin_Tools::createConstraint(this,
362 START_POINT_REF_ID(),
363 anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
366 SketchPlugin_Tools::createConstraint(this,
368 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
371 } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
372 SketchPlugin_Tools::createConstraint(this,
373 START_POINT_REF_ID(),
374 anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
377 SketchPlugin_Tools::createConstraint(this,
379 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
382 SketchPlugin_Tools::createConstraint(this,
383 PASSED_POINT_REF_ID(),
385 anArcFeature->lastResult(),
387 } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
388 SketchPlugin_Tools::createConstraint(this,
390 anArcFeature->attribute(SketchPlugin_Arc::END_ID()),