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(),
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(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
65 data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
67 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
69 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
70 data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
71 data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
72 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
74 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
75 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
76 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
77 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
80 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
82 std::string anArcType = string(ARC_TYPE())->value();
84 // If arc type switched reset according attributes.
85 if(theID == ARC_TYPE()) {
86 std::string aType = string(ARC_TYPE())->value();
87 if(aType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
88 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
89 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
90 SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
91 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
92 SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
93 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
94 } else if(aType == ARC_TYPE_BY_THREE_POINTS()) {
95 SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
96 SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
97 SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
98 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
99 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
100 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
101 } else if(aType == ARC_TYPE_BY_TANGENT_EDGE()) {
102 SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
103 SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
104 SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
110 myIsInversed = false;
112 } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
113 std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
114 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
115 if(!aCenterPointAttr->isInitialized()) {
118 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
119 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
120 if(!aStartPointAttr->isInitialized()) {
124 myCenter = aCenterPointAttr->pnt();
125 myStart = aStartPointAttr->pnt();
128 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
129 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
130 if(anEndPointAttr->isInitialized()) {
131 // End point should be a projection on circle.
132 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
133 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc.project(anEndPointAttr->pnt());
134 if(aProjection.get()) {
135 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
136 anEndPointAttr->setValue(aProjection);
137 data()->blockSendAttributeUpdated(aWasBlocked, false);
139 myEnd = anEndPointAttr->pnt();
141 double aParameterNew = 0.0;
142 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
143 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
145 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
146 myIsInversed = false;
149 myParamBefore = aParameterNew;
151 } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
152 std::shared_ptr<GeomDataAPI_Point2D> aStartPointAttr =
153 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
154 if(!aStartPointAttr->isInitialized()) {
157 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
158 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
159 if(!anEndPointAttr->isInitialized()) {
163 myStart = aStartPointAttr->pnt();
164 myEnd = anEndPointAttr->pnt();
166 std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
167 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
168 if(aPassedPointAttr->isInitialized()) {
169 std::shared_ptr<GeomAPI_Pnt2d> aPassed = aPassedPointAttr->pnt();
170 GeomAPI_Circ2d aCircle(myStart, myEnd, aPassed);
171 myCenter = aCircle.center();
172 aCircle = GeomAPI_Circ2d(myCenter, myStart);
173 double anEndParam, aPassedParam;
174 aCircle.parameter(myEnd, paramTolerance, anEndParam);
175 aCircle.parameter(aPassed, paramTolerance, aPassedParam);
176 if(aPassedParam > anEndParam) {
179 myIsInversed = false;
182 std::shared_ptr<GeomAPI_XY> aDir = myEnd->xy()->decreased(myStart->xy())->multiplied(0.5);
183 double x = aDir->x();
184 double y = aDir->y();
187 myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(aDir)));
189 } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
190 AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
191 if(!aTangentAttr->isInitialized()) {
194 std::shared_ptr<GeomDataAPI_Point2D> aTangentPointAttr =
195 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
196 if(!aTangentPointAttr->isInitialized()) {
199 std::shared_ptr<GeomDataAPI_Point2D> anEndPointAttr =
200 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
201 if(!anEndPointAttr->isInitialized()) {
205 myStart = aTangentPointAttr->pnt();
206 myEnd = anEndPointAttr->pnt();
208 if(myStart->isEqual(myEnd)) {
212 SketchPlugin_Sketch* aSketch = sketch();
217 std::shared_ptr<GeomAPI_Dir2d> anOrthoDir;
218 FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
219 std::shared_ptr<GeomAPI_Edge> aTangEdge =
220 std::dynamic_pointer_cast<GeomAPI_Edge>(aTangFeature->lastResult()->shape());
221 if(aTangEdge->isLine()) {
222 std::shared_ptr<GeomAPI_Dir> aDir = aTangEdge->line()->direction();
223 std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aDir->x(), aDir->y(), aDir->z()));
224 std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aSketch->to2D(aPnt);
225 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(-aPnt2d->y(), aPnt2d->x()));
227 else if (aTangEdge->isArc()) {
228 std::shared_ptr<GeomAPI_Pnt> aCenter = aTangEdge->circle()->center();
229 std::shared_ptr<GeomAPI_Pnt2d> aCenter2d = aSketch->to2D(aCenter);
230 anOrthoDir = std::shared_ptr<GeomAPI_Dir2d>(
231 new GeomAPI_Dir2d(myStart->xy()->decreased(aCenter2d->xy())));
234 // compute parameters of the middle perpendicular
235 std::shared_ptr<GeomAPI_XY> aEndPntCoord = myEnd->xy();
236 std::shared_ptr<GeomAPI_XY> aTempDir = aEndPntCoord->decreased(myStart->xy());
237 std::shared_ptr<GeomAPI_Dir2d> aMidDir(new GeomAPI_Dir2d(-aTempDir->y(), aTempDir->x()));
238 std::shared_ptr<GeomAPI_Pnt2d> aMidPnt(
239 new GeomAPI_Pnt2d(aEndPntCoord->added(myStart->xy())->multiplied(0.5)));
241 // compute center of arc by calculating intersection of
242 // orthogonal line and middle perpendicular
243 std::shared_ptr<GeomAPI_Lin2d> anOrthoLine(new GeomAPI_Lin2d(myStart, anOrthoDir));
244 std::shared_ptr<GeomAPI_Lin2d> aMiddleLine(new GeomAPI_Lin2d(aMidPnt, aMidDir));
245 std::shared_ptr<GeomAPI_Pnt2d> aCenter = anOrthoLine->intersect(aMiddleLine);
250 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
251 double aParameterNew = 0.0;
252 if(aCircleForArc.parameter(myEnd, paramTolerance, aParameterNew)) {
253 if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
257 } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
259 myIsInversed = false;
263 myParamBefore = aParameterNew;
268 if(myCenter.get() && myStart.get()) {
269 aRadius = myCenter->distance(myStart);
271 if(myStart->isEqual(myEnd)) {
274 GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
275 double aStartParam, anEndParam;
276 aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
277 aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
278 anAngle = (anEndParam - aStartParam) / PI * 180.0;
279 if(myIsInversed) anAngle = 360.0 - anAngle;
284 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
285 real(RADIUS_ID())->setValue(aRadius);
286 real(ANGLE_ID())->setValue(anAngle);
287 data()->blockSendAttributeUpdated(aWasBlocked, false);
290 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
292 if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
293 return AISObjectPtr();
296 SketchPlugin_Sketch* aSketch = sketch();
298 return AISObjectPtr();
301 std::shared_ptr<GeomAPI_Pnt> aStart = aSketch->to3D(myStart->x(), myStart->y());
302 std::shared_ptr<GeomAPI_Pnt> anEnd = aSketch->to3D(myEnd->x(), myEnd->y());
303 std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
305 std::shared_ptr<GeomDataAPI_Dir> aNDir =
306 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
307 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
308 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
309 GeomShapePtr anArcShape = myIsInversed ?
310 GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
311 : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
312 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
314 if(!anArcShape.get() || !aCenterPointShape.get()) {
315 return AISObjectPtr();
318 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
319 aShapes.push_back(anArcShape);
320 aShapes.push_back(aCenterPointShape);
322 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
323 AISObjectPtr anAIS = thePrevious;
325 anAIS.reset(new GeomAPI_AISObject());
327 anAIS->createShape(aCompound);
331 void SketchPlugin_MacroArc::execute()