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>
26 const double tolerance = 1e-7;
28 SketchPlugin_Arc::SketchPlugin_Arc()
29 : SketchPlugin_SketchEntity()
31 myStartUpdate = false;
38 void SketchPlugin_Arc::initAttributes()
40 SketchPlugin_SketchEntity::initAttributes();
42 data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
43 data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
44 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
45 GeomDataAPI_Point2D>(data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()));
46 data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
47 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
49 // get the initial values
50 if (anEndAttr->isInitialized()) {
51 myXEndBefore = anEndAttr->x();
52 myYEndBefore = anEndAttr->y();
56 void SketchPlugin_Arc::execute()
58 SketchPlugin_Sketch* aSketch = sketch();
59 // result for the arc is set only when all obligatory attributes are initialized,
60 // otherwise AIS object is used to visualize the arc's preview
61 if (aSketch && isFeatureValid()) {
62 // compute a circle point in 3D view
63 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
64 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
65 // compute the arc start point
66 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
67 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
69 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
70 // make a visible point
71 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
72 std::shared_ptr<ModelAPI_ResultConstruction> aConstr1 = document()->createConstruction(
74 aConstr1->setShape(aCenterPointShape);
75 aConstr1->setIsInHistory(false);
76 setResult(aConstr1, 0);
78 // make a visible circle
79 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
80 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
81 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
82 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
84 // compute and change the arc end point
85 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
86 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
87 /* must be automatically done in attributeChanged
88 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
89 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
90 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
91 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
92 anEndAttr->setValue(aProjection);
94 std::shared_ptr<GeomAPI_Pnt> aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
96 std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
97 aCenter, aStartPoint, aEndPoint, aNormal);
99 std::shared_ptr<ModelAPI_ResultConstruction> aConstr2 = document()->createConstruction(
101 aConstr2->setShape(aCircleShape);
102 aConstr2->setIsInHistory(false);
103 setResult(aConstr2, 1);
108 AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious)
110 SketchPlugin_Sketch* aSketch = sketch();
112 // if the feature is valid, the execute() method should be performed, AIS object is empty
113 if (!isFeatureValid()) {
114 // compute a circle point in 3D view
115 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
116 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
117 if (aCenterAttr->isInitialized()) {
118 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
120 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
121 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
122 if (aStartAttr->isInitialized()) {
123 // make a visible circle
124 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
125 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
126 bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0);
128 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
129 std::shared_ptr<GeomAPI_Pnt> aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
130 std::shared_ptr<GeomAPI_Shape> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc(
131 aCenter, aStartPoint, aStartPoint, aNormal);
133 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
134 // make a visible point
135 std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
136 aShapes.push_back(aCenterPointShape);
138 aShapes.push_back(aCircleShape);
139 if (!aShapes.empty())
141 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
142 AISObjectPtr anAIS = thePrevious;
144 anAIS = AISObjectPtr(new GeomAPI_AISObject);
145 anAIS->createShape(aCompound);
155 return AISObjectPtr();
158 void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY)
160 std::shared_ptr<ModelAPI_Data> aData = data();
161 if (!aData->isValid())
164 myStartUpdate = true;
166 std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
167 aData->attribute(SketchPlugin_Arc::START_ID()));
168 aPoint2->move(theDeltaX, theDeltaY);
170 std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
171 aData->attribute(SketchPlugin_Arc::END_ID()));
172 aPoint3->move(theDeltaX, theDeltaY);
173 myStartUpdate = false;
176 std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
177 aData->attribute(SketchPlugin_Arc::CENTER_ID()));
178 aPoint1->move(theDeltaX, theDeltaY);
181 double SketchPlugin_Arc::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
184 std::shared_ptr<ModelAPI_Data> aData = data();
186 std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
187 aData->attribute(SketchPlugin_Arc::CENTER_ID()));
188 aDelta = aPoint1->pnt()->distance(thePoint);
190 std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
191 aData->attribute(SketchPlugin_Arc::START_ID()));
192 double aDistance = aPoint2->pnt()->distance(thePoint);
193 if (aDelta < aDistance)
196 std::shared_ptr<GeomDataAPI_Point2D> aPoint3 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
197 aData->attribute(SketchPlugin_Arc::END_ID()));
198 aDistance = aPoint3->pnt()->distance(thePoint);
199 if (aDelta < aDistance)
205 bool SketchPlugin_Arc::isFixed() {
206 return data()->selection(EXTERNAL_ID())->context().get() != NULL;
209 bool SketchPlugin_Arc::isFeatureValid()
211 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
212 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID()));
213 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
214 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID()));
215 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
216 GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID()));
218 return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized();
221 void SketchPlugin_Arc::attributeChanged(const std::string& theID)
223 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
224 GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
225 std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
226 GeomDataAPI_Point2D>(data()->attribute(START_ID()));
227 std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
228 GeomDataAPI_Point2D>(data()->attribute(END_ID()));
229 // the second condition for unability to move external segments anywhere
230 if (theID == EXTERNAL_ID() || isFixed()) {
231 std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
232 // update arguments due to the selection value
233 if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
234 std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
235 std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
237 aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
238 anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
239 aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
244 if (!aCenterAttr->isInitialized())
246 if (!aStartAttr->isInitialized())
248 if (!anEndAttr->isInitialized())
251 // update the points in accordance to the changed point changes
252 if (theID == END_ID() && !myEndUpdate) {
254 // compute and change the arc end point
255 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
256 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
257 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
258 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) {
259 // issue #855: trying to update only not-updated coordinate if it is possible
260 if (abs(myXEndBefore - anEndAttr->x()) < 1.e-10) { // keep Y unchanged
261 double aVy = aCenterAttr->y() - anEndAttr->y();
262 double aVy2 = aVy * aVy;
263 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
265 double aDX = sqrt(aR2 - aVy * aVy);
266 if (anEndAttr->x() > aCenterAttr->x())
267 aProjection->setX(aCenterAttr->x() + aDX);
269 aProjection->setX(aCenterAttr->x() - aDX);
270 aProjection->setY(anEndAttr->y());
272 } else if (abs(myYEndBefore - anEndAttr->y()) < 1.e-10) { // keep X unchanged
273 double aVx = aCenterAttr->x() - anEndAttr->x();
274 double aVx2 = aVx * aVx;
275 double aR2 = aCircleForArc->radius() * aCircleForArc->radius();
277 double aDY = sqrt(aR2 - aVx * aVx);
278 if (anEndAttr->y() > aCenterAttr->y())
279 aProjection->setY(aCenterAttr->y() + aDY);
281 aProjection->setY(aCenterAttr->y() - aDY);
282 aProjection->setX(anEndAttr->x());
286 anEndAttr->setValue(aProjection);
288 myXEndBefore = anEndAttr->x();
289 myYEndBefore = anEndAttr->y();
291 } else if (theID == START_ID() && !myStartUpdate) {
292 myStartUpdate = true;
293 // compute and change the arc start point
294 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
295 new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt()));
296 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(aStartAttr->pnt());
297 if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance)
298 aStartAttr->setValue(aProjection);
299 myStartUpdate = false;
300 } else if (theID == CENTER_ID() && !myEndUpdate) {
302 // compute and change the arc end point
303 std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
304 new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
305 std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
306 if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
307 anEndAttr->setValue(aProjection);