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_Sketch.h"
10 #include "SketchPlugin_Tools.h"
12 #include <ModelAPI_AttributeDouble.h>
13 #include <ModelAPI_AttributeRefAttr.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_Session.h>
16 #include <ModelAPI_Validator.h>
18 #include <GeomAPI_Circ.h>
19 #include <GeomAPI_Circ2d.h>
20 #include <GeomAPI_Dir2d.h>
21 #include <GeomAPI_Edge.h>
22 #include <GeomAPI_Lin.h>
23 #include <GeomAPI_Lin2d.h>
24 #include <GeomAPI_Pnt2d.h>
25 #include <GeomAPI_Vertex.h>
26 #include <GeomAPI_XY.h>
28 #include <GeomDataAPI_Point2D.h>
29 #include <GeomDataAPI_Dir.h>
30 #include <GeomAlgoAPI_PointBuilder.h>
31 #include <GeomAlgoAPI_EdgeBuilder.h>
32 #include <GeomAlgoAPI_CompoundBuilder.h>
37 const double tolerance = 1e-7;
38 const double paramTolerance = 1.e-4;
39 const double PI = 3.141592653589793238463;
42 SketchPlugin_MacroArc::SketchPlugin_MacroArc()
43 : SketchPlugin_SketchEntity(),
48 void SketchPlugin_MacroArc::initAttributes()
50 data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId());
52 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
53 data()->addAttribute(START_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
54 data()->addAttribute(END_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
56 data()->addAttribute(START_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
57 data()->addAttribute(END_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
58 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
60 data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
61 data()->addAttribute(END_POINT_3_ID(), GeomDataAPI_Point2D::typeId());
63 data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
65 data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
66 data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
68 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
70 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71 data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72 data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
73 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
75 boolean(REVERSED_ID())->setValue(false);
77 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
78 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
79 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
80 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
83 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
85 std::string anArcType = string(ARC_TYPE())->value();
87 // If arc type switched reset according attributes.
88 if(theID == ARC_TYPE()) {
89 std::string aType = string(ARC_TYPE())->value();
90 if(aType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
91 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
92 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
93 SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
94 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
95 SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
96 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
97 } else if(aType == ARC_TYPE_BY_THREE_POINTS()) {
98 SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
99 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
100 SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
101 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
102 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
103 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
104 } else if(aType == ARC_TYPE_BY_TANGENT_EDGE()) {
105 SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
106 SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
107 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
113 boolean(REVERSED_ID())->setValue(false);
115 } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
116 std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
117 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
118 if(!aCenterPointAttr->isInitialized()) {
121 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
122 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
123 if(!aStartPointAttr->isInitialized()) {
127 myCenter = aCenterPointAttr->pnt();
128 myStart = aStartPointAttr->pnt();
131 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
132 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
133 if(anEndPointAttr->isInitialized()) {
134 // End point should be a projection on circle.
135 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
136 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc.project(anEndPointAttr->pnt());
137 if(aProjection.get()) {
138 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
139 anEndPointAttr->setValue(aProjection);
140 data()->blockSendAttributeUpdated(aWasBlocked, false);
142 myEnd = anEndPointAttr->pnt();
144 double aParameterNew = 0.0;
145 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
146 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
147 boolean(REVERSED_ID())->setValue(true);
148 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
149 boolean(REVERSED_ID())->setValue(false);
152 myParamBefore = aParameterNew;
154 } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
155 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
156 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
157 if(!aStartPointAttr->isInitialized()) {
160 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
161 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
162 if(!anEndPointAttr->isInitialized()) {
166 myStart = aStartPointAttr->pnt();
167 myEnd = anEndPointAttr->pnt();
169 std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
170 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
171 if(aPassedPointAttr->isInitialized()) {
172 std::shared_ptr<GeomAPI_Pnt2d> aPassed = aPassedPointAttr->pnt();
173 GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed);
174 myCenter = aCircle.center();
175 aCircle = GeomAPI_Circ2d(myCenter, myStart);
176 double anEndParam, aPassedParam;
177 aCircle.parameter(myEnd, paramTolerance, anEndParam);
178 aCircle.parameter(aPassed, paramTolerance, aPassedParam);
179 if(aPassedParam > anEndParam) {
180 boolean(REVERSED_ID())->setValue(true);
182 boolean(REVERSED_ID())->setValue(false);
185 std::shared_ptr<GeomAPI_XY> aDir = myEnd->xy()->decreased(myStart->xy())->multiplied(0.5);
186 double x = aDir->x();
187 double y = aDir->y();
190 myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(aDir)));
192 } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
193 AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
194 if(!aTangentAttr->isInitialized()) {
197 std::shared_ptr<GeomDataAPI_Point2D> aTangentPointAttr =
198 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
199 if(!aTangentPointAttr->isInitialized()) {
202 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
203 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
204 if(!anEndPointAttr->isInitialized()) {
208 myStart = aTangentPointAttr->pnt();
209 myEnd = anEndPointAttr->pnt();
211 if(myStart->isEqual(myEnd)) {
215 SketchPlugin_Sketch* aSketch = sketch();
220 std::shared_ptr<GeomAPI_Dir2d> anOrthoDir;
221 FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
222 std::shared_ptr<GeomAPI_Edge> aTangEdge =
223 std::dynamic_pointer_cast<GeomAPI_Edge>(aTangFeature->lastResult()->shape());
224 if(aTangEdge->isLine()) {
225 std::shared_ptr<GeomAPI_Dir> aDir = aTangEdge->line()->direction();
226 std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aDir->x(), aDir->y(), aDir->z()));
227 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aSketch->to2D(aPnt);
228 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aPnt2d->y(), aPnt2d->x()));
230 else if (aTangEdge->isArc()) {
231 std::shared_ptr<GeomAPI_Pnt> aCenter = aTangEdge->circle()->center();
232 std::shared_ptr<GeomAPI_Pnt2d> aCenter2d = aSketch->to2D(aCenter);
233 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(
234 new GeomAPI_Dir2d(myStart->xy()->decreased(aCenter2d->xy())));
237 // compute parameters of the middle perpendicular
238 std::shared_ptr<GeomAPI_XY> aEndPntCoord = myEnd->xy();
239 std::shared_ptr<GeomAPI_XY> aTempDir = aEndPntCoord->decreased(myStart->xy());
240 std::shared_ptr<GeomAPI_Dir2d> aMidDir(new GeomAPI_Dir2d(-aTempDir->y(), aTempDir->x()));
241 std::shared_ptr<GeomAPI_Pnt2d> aMidPnt(
242 new GeomAPI_Pnt2d(aEndPntCoord->added(myStart->xy())->multiplied(0.5)));
244 // compute center of arc by calculating intersection of
245 // orthogonal line and middle perpendicular
246 std::shared_ptr<GeomAPI_Lin2d> anOrthoLine(new GeomAPI_Lin2d(myStart, anOrthoDir));
247 std::shared_ptr<GeomAPI_Lin2d> aMiddleLine(new GeomAPI_Lin2d(aMidPnt, aMidDir));
248 std::shared_ptr<GeomAPI_Pnt2d> aCenter = anOrthoLine->intersect(aMiddleLine);
253 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
254 double aParameterNew = 0.0;
255 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
256 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
257 if(!boolean(REVERSED_ID())->value()) {
258 boolean(REVERSED_ID())->setValue(true);
260 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
261 if(boolean(REVERSED_ID())->value()) {
262 boolean(REVERSED_ID())->setValue(false);
266 myParamBefore = aParameterNew;
271 if(myCenter.get() && myStart.get()) {
272 aRadius = myCenter->distance(myStart);
274 if(myStart->isEqual(myEnd)) {
277 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
278 double aStartParam, anEndParam;
279 aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
280 aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
281 anAngle = (anEndParam - aStartParam) / PI * 180.0;
282 if(boolean(REVERSED_ID())->value()) anAngle = 360.0 - anAngle;
287 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
288 real(RADIUS_ID())->setValue(aRadius);
289 real(ANGLE_ID())->setValue(anAngle);
290 data()->blockSendAttributeUpdated(aWasBlocked, false);
293 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
295 if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
296 return AISObjectPtr();
299 SketchPlugin_Sketch* aSketch = sketch();
301 return AISObjectPtr();
304 std::shared_ptr<GeomAPI_Pnt> aStart = aSketch->to3D(myStart->x(), myStart->y());
305 std::shared_ptr<GeomAPI_Pnt> anEnd = aSketch->to3D(myEnd->x(), myEnd->y());
306 std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
308 std::shared_ptr<GeomDataAPI_Dir> aNDir =
309 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
310 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
311 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
312 GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
313 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
314 : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
315 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
317 if(!anArcShape.get() || !aCenterPointShape.get()) {
318 return AISObjectPtr();
321 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
322 aShapes.push_back(anArcShape);
323 aShapes.push_back(aCenterPointShape);
325 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
326 AISObjectPtr anAIS = thePrevious;
328 anAIS.reset(new GeomAPI_AISObject());
330 anAIS->createShape(aCompound);
334 void SketchPlugin_MacroArc::execute()