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_Circ2d.h>
16 #include <GeomAPI_Circ.h>
17 #include <GeomAPI_Pnt2d.h>
18 #include <GeomDataAPI_Point2D.h>
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomAlgoAPI_PointBuilder.h>
21 #include <GeomAlgoAPI_EdgeBuilder.h>
22 #include <GeomAlgoAPI_CompoundBuilder.h>
24 const double tolerance = 1e-7;
26 SketchPlugin_Arc::SketchPlugin_Arc()
27 : SketchPlugin_SketchEntity()
29 myStartUpdate = false;
36 void SketchPlugin_Arc::initAttributes()
38 SketchPlugin_SketchEntity::initAttributes();
40 data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
41 data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
42 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
43 GeomDataAPI_Point2D>(data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()));
44 data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
45 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
47 // get the initial values
48 if (anEndAttr->isInitialized()) {
49 myXEndBefore = anEndAttr->x();
50 myYEndBefore = anEndAttr->y();
54 void SketchPlugin_Arc::execute()
56 SketchPlugin_Sketch* aSketch = sketch();
57 // result for the arc is set only when all obligatory attributes are initialized,
58 // otherwise AIS object is used to visualize the arc's preview
59 if (aSketch && isFeatureValid()) {
60 // compute a circle point in 3D view
61 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
62 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
63 // compute the arc start point
64 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
65 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
67 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
68 // make a visible point
69 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
70 std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
72 aConstr1->setShape(aCenterPointShape);
73 aConstr1->setIsInHistory(false);
74 setResult(aConstr1, 0);
76 // make a visible circle
77 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
78 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
79 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
80 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
82 // compute and change the arc end point
83 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
84 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
85 /* must be automatically done in attributeChanged
86 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
87 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
88 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
89 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
90 anEndAttr->setValue(aProjection);
92 std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
94 std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
95 aCenter, aStartPoint, aEndPoint, aNormal);
97 std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
99 aConstr2->setShape(aCircleShape);
100 aConstr2->setIsInHistory(false);
101 setResult(aConstr2, 1);
106 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
108 SketchPlugin_Sketch* aSketch = sketch();
110 // if the feature is valid, the execute() method should be performed, AIS object is empty
111 if (!isFeatureValid()) {
112 // compute a circle point in 3D view
113 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
114 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
115 if (aCenterAttr->isInitialized()) {
116 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
118 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
119 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
120 if (aStartAttr->isInitialized()) {
121 // make a visible circle
122 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
123 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
124 bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
126 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
127 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
128 std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
129 aCenter, aStartPoint, aStartPoint, aNormal);
131 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
132 // make a visible point
133 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
134 aShapes.push_back(aCenterPointShape);
136 aShapes.push_back(aCircleShape);
137 if (!aShapes.empty())
139 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
140 AISObjectPtr anAIS = thePrevious;
142 anAIS = AISObjectPtr(new GeomAPI_AISObject);
143 anAIS->createShape(aCompound);
153 return AISObjectPtr();
156 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
158 std::shared_ptr<ModelAPI_Data> aData = data();
159 if (!aData->isValid())
162 myStartUpdate = true;
164 std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
165 aData->attribute(SketchPlugin_Arc::START_ID()));
166 aPoint2->move(theDeltaX, theDeltaY);
168 std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
169 aData->attribute(SketchPlugin_Arc::END_ID()));
170 aPoint3->move(theDeltaX, theDeltaY);
171 myStartUpdate = false;
174 std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
175 aData->attribute(SketchPlugin_Arc::CENTER_ID()));
176 aPoint1->move(theDeltaX, theDeltaY);
179 double SketchPlugin_Arc::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
182 std::shared_ptr<ModelAPI_Data> aData = data();
184 std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
185 aData->attribute(SketchPlugin_Arc::CENTER_ID()));
186 aDelta = aPoint1->pnt()->distance(thePoint);
188 std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
189 aData->attribute(SketchPlugin_Arc::START_ID()));
190 double aDistance = aPoint2->pnt()->distance(thePoint);
191 if (aDelta < aDistance)
194 std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
195 aData->attribute(SketchPlugin_Arc::END_ID()));
196 aDistance = aPoint3->pnt()->distance(thePoint);
197 if (aDelta < aDistance)
203 bool SketchPlugin_Arc::isFixed() {
204 return data()->selection(EXTERNAL_ID())->context().get() != NULL;
207 bool SketchPlugin_Arc::isFeatureValid()
209 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
210 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
211 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
212 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
213 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
214 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
216 return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
219 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
221 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
222 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
223 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
224 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
225 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
226 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
227 // the second condition for unability to move external segments anywhere
228 if (theID == EXTERNAL_ID() || isFixed()) {
229 std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
230 // update arguments due to the selection value
231 if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
232 std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
233 std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
235 aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
236 anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
237 aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
242 if (!aCenterAttr->isInitialized())
244 if (!aStartAttr->isInitialized())
246 if (!anEndAttr->isInitialized())
249 // update the points in accordance to the changed point changes
250 if (theID == END_ID() && !myEndUpdate) {
252 // compute and change the arc end point
253 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
254 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
255 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
256 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) {
257 // issue #855: trying to update only not-updated coordinate if it is possible
258 if (abs(myXEndBefore - anEndAttr->x()) < 1.e-10) { // keep Y unchanged
259 double aVy = aCenterAttr->y() - anEndAttr->y();
260 double aVy2 = aVy * aVy;
261 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
263 double aDX = sqrt(aR2 - aVy * aVy);
264 if (anEndAttr->x() > aCenterAttr->x())
265 aProjection->setX(aCenterAttr->x() + aDX);
267 aProjection->setX(aCenterAttr->x() - aDX);
268 aProjection->setY(anEndAttr->y());
270 } else if (abs(myYEndBefore - anEndAttr->y()) < 1.e-10) { // keep X unchanged
271 double aVx = aCenterAttr->x() - anEndAttr->x();
272 double aVx2 = aVx * aVx;
273 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
275 double aDY = sqrt(aR2 - aVx * aVx);
276 if (anEndAttr->y() > aCenterAttr->y())
277 aProjection->setY(aCenterAttr->y() + aDY);
279 aProjection->setY(aCenterAttr->y() - aDY);
280 aProjection->setX(anEndAttr->x());
284 anEndAttr->setValue(aProjection);
286 myXEndBefore = anEndAttr->x();
287 myYEndBefore = anEndAttr->y();
289 } else if (theID == START_ID() && !myStartUpdate) {
290 myStartUpdate = true;
291 // compute and change the arc start point
292 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
293 new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
294 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
295 if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
296 aStartAttr->setValue(aProjection);
297 myStartUpdate = false;
298 } else if (theID == CENTER_ID() && !myEndUpdate) {
300 // compute and change the arc end point
301 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
302 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
303 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
304 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
305 anEndAttr->setValue(aProjection);