1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_Arc.cpp
4 // Created: 26 Apr 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchPlugin_Arc.h"
8 #include "SketchPlugin_Sketch.h"
9 #include <ModelAPI_Data.h>
10 #include <ModelAPI_ResultConstruction.h>
11 #include <ModelAPI_AttributeSelection.h>
12 #include <ModelAPI_Validator.h>
13 #include <ModelAPI_Session.h>
15 #include <GeomAPI_Ax2.h>
16 #include <GeomAPI_Circ2d.h>
17 #include <GeomAPI_Circ.h>
18 #include <GeomAPI_Pnt2d.h>
19 #include <GeomDataAPI_Point2D.h>
20 #include <GeomDataAPI_Dir.h>
21 #include <GeomAlgoAPI_PointBuilder.h>
22 #include <GeomAlgoAPI_EdgeBuilder.h>
23 #include <GeomAlgoAPI_CompoundBuilder.h>
27 const double tolerance = 1e-7;
28 const double paramTolerance = 1.e-4;
29 const double PI =3.141592653589793238463;
32 static const std::string& INVERSED_ID()
34 static const std::string MY_INVERSED_ID("InversedArc");
35 return MY_INVERSED_ID;
38 SketchPlugin_Arc::SketchPlugin_Arc()
39 : SketchPlugin_SketchEntity()
41 myStartUpdate = false;
50 void SketchPlugin_Arc::initAttributes()
52 SketchPlugin_SketchEntity::initAttributes();
54 data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
55 data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
56 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
57 GeomDataAPI_Point2D>(data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()));
58 data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
59 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
61 data()->addAttribute(INVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
62 AttributeBooleanPtr isInversed =
63 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
64 if (!isInversed->isInitialized())
65 isInversed->setValue(false);
67 // get the initial values
68 if (anEndAttr->isInitialized()) {
69 myXEndBefore = anEndAttr->x();
70 myYEndBefore = anEndAttr->y();
74 void SketchPlugin_Arc::execute()
76 SketchPlugin_Sketch* aSketch = sketch();
77 // result for the arc is set only when all obligatory attributes are initialized,
78 // otherwise AIS object is used to visualize the arc's preview
79 if (aSketch && isFeatureValid()) {
80 // compute a circle point in 3D view
81 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
82 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
83 // compute the arc start point
84 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
85 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
87 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
88 // make a visible point
89 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
90 std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
92 aConstr1->setShape(aCenterPointShape);
93 aConstr1->setIsInHistory(false);
94 setResult(aConstr1, 0);
96 // make a visible circle
97 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
98 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
99 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
100 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
102 // compute and change the arc end point
103 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
104 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
105 /* must be automatically done in attributeChanged
106 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
107 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
108 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
109 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
110 anEndAttr->setValue(aProjection);
112 std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
113 AttributeBooleanPtr isInversed =
114 std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(attribute(INVERSED_ID()));
116 std::shared_ptr<GeomAPI_Dir> anXDir(new GeomAPI_Dir(aStartPoint->xyz()->decreased(aCenter->xyz())));
117 std::shared_ptr<GeomAPI_Ax2> anAx2(new GeomAPI_Ax2(aCenter, aNormal, anXDir));
118 std::shared_ptr<GeomAPI_Circ> aCirc(new GeomAPI_Circ(anAx2, aCenter->distance(aStartPoint)));
119 double aParameterNew = 0.0;
120 if(aCirc->parameter(aEndPoint, paramTolerance, aParameterNew)) {
121 if(0 <= myParamBefore && myParamBefore <= PI / 2.0
122 && PI * 1.5 <= aParameterNew && aParameterNew <= PI * 2.0) {
123 isInversed->setValue(true);
124 } else if(PI * 1.5 <= myParamBefore && myParamBefore <= PI * 2.0
125 && 0 <= aParameterNew && aParameterNew <= PI / 2.0) {
126 isInversed->setValue(false);
129 myParamBefore = aParameterNew;
131 std::shared_ptr<GeomAPI_Shape> aCircleShape;
132 if(!isInversed->value()) {
133 aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStartPoint, aEndPoint, aNormal);
135 aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aEndPoint, aStartPoint, aNormal);
139 std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
141 aConstr2->setShape(aCircleShape);
142 aConstr2->setIsInHistory(false);
143 setResult(aConstr2, 1);
148 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
150 SketchPlugin_Sketch* aSketch = sketch();
152 // if the feature is valid, the execute() method should be performed, AIS object is empty
153 if (!isFeatureValid()) {
154 // compute a circle point in 3D view
155 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
156 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
157 if (aCenterAttr->isInitialized()) {
158 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
160 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
161 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
162 if (aStartAttr->isInitialized()) {
163 // make a visible circle
164 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
165 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
166 bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
168 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
169 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
170 std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
171 aCenter, aStartPoint, aStartPoint, aNormal);
173 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
174 // make a visible point
175 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
176 aShapes.push_back(aCenterPointShape);
178 aShapes.push_back(aCircleShape);
179 if (!aShapes.empty())
181 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
182 AISObjectPtr anAIS = thePrevious;
184 anAIS = AISObjectPtr(new GeomAPI_AISObject);
185 anAIS->createShape(aCompound);
195 return AISObjectPtr();
198 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
200 std::shared_ptr<ModelAPI_Data> aData = data();
201 if (!aData->isValid())
204 myStartUpdate = true;
206 std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
207 aData->attribute(SketchPlugin_Arc::START_ID()));
208 aPoint2->move(theDeltaX, theDeltaY);
210 std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
211 aData->attribute(SketchPlugin_Arc::END_ID()));
212 aPoint3->move(theDeltaX, theDeltaY);
213 myStartUpdate = false;
216 std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
217 aData->attribute(SketchPlugin_Arc::CENTER_ID()));
218 aPoint1->move(theDeltaX, theDeltaY);
221 bool SketchPlugin_Arc::isFixed() {
222 return data()->selection(EXTERNAL_ID())->context().get() != NULL;
225 bool SketchPlugin_Arc::isFeatureValid()
227 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
228 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
229 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
230 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
231 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
232 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
234 return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
237 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
239 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
240 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
241 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
242 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
243 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
244 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
245 // the second condition for unability to move external segments anywhere
246 if (theID == EXTERNAL_ID() || isFixed()) {
247 std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
248 // update arguments due to the selection value
249 if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
250 std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
251 std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
253 aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
254 anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
255 aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
260 if (!aCenterAttr->isInitialized())
262 if (!aStartAttr->isInitialized())
264 if (!anEndAttr->isInitialized())
267 // update the points in accordance to the changed point changes
268 if (theID == END_ID() && !myEndUpdate) {
270 // compute and change the arc end point
271 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
272 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
273 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
274 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) {
275 if (!isStable()) { // issue #855: trying to update only not-updated coordinate if it is possible
276 if (fabs(myXEndBefore - anEndAttr->x()) < 1.e-10) { // keep Y unchanged
277 double aVy = aCenterAttr->y() - anEndAttr->y();
278 double aVy2 = aVy * aVy;
279 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
281 double aDX = sqrt(aR2 - aVy * aVy);
282 if (anEndAttr->x() > aCenterAttr->x())
283 aProjection->setX(aCenterAttr->x() + aDX);
285 aProjection->setX(aCenterAttr->x() - aDX);
286 aProjection->setY(anEndAttr->y());
288 } else if (fabs(myYEndBefore - anEndAttr->y()) < 1.e-10) { // keep X unchanged
289 double aVx = aCenterAttr->x() - anEndAttr->x();
290 double aVx2 = aVx * aVx;
291 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
293 double aDY = sqrt(aR2 - aVx * aVx);
294 if (anEndAttr->y() > aCenterAttr->y())
295 aProjection->setY(aCenterAttr->y() + aDY);
297 aProjection->setY(aCenterAttr->y() - aDY);
298 aProjection->setX(anEndAttr->x());
303 anEndAttr->setValue(aProjection);
305 myXEndBefore = anEndAttr->x();
306 myYEndBefore = anEndAttr->y();
308 } else if (theID == START_ID() && !myStartUpdate) {
309 myStartUpdate = true;
310 // compute and change the arc start point
311 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
312 new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
313 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
314 if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
315 aStartAttr->setValue(aProjection);
316 myStartUpdate = false;
317 } else if (theID == CENTER_ID() && !myEndUpdate) {
319 // compute and change the arc end point
320 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
321 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
322 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
323 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
324 anEndAttr->setValue(aProjection);