1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_MacroCircle.cpp
4 // Created: 26 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchPlugin_MacroCircle.h"
9 #include "SketchPlugin_Circle.h"
10 #include "SketchPlugin_Point.h"
11 #include "SketchPlugin_Tools.h"
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeRefAttr.h>
15 #include <ModelAPI_AttributeString.h>
16 #include <ModelAPI_Session.h>
17 #include <ModelAPI_Validator.h>
19 #include <GeomDataAPI_Dir.h>
20 #include <GeomDataAPI_Point2D.h>
22 #include <GeomAPI_Circ2d.h>
23 #include <GeomAPI_Pnt2d.h>
24 #include <GeomAPI_Vertex.h>
26 #include <GeomAlgoAPI_CompoundBuilder.h>
27 #include <GeomAlgoAPI_EdgeBuilder.h>
28 #include <GeomAlgoAPI_PointBuilder.h>
31 const double tolerance = 1e-7;
34 static const std::string& POINT_ID(int theIndex)
37 case 1: return SketchPlugin_MacroCircle::FIRST_POINT_ID();
38 case 2: return SketchPlugin_MacroCircle::SECOND_POINT_ID();
39 case 3: return SketchPlugin_MacroCircle::THIRD_POINT_ID();
42 static const std::string DUMMY;
48 SketchPlugin_MacroCircle::SketchPlugin_MacroCircle()
49 : SketchPlugin_SketchEntity()
53 void SketchPlugin_MacroCircle::initAttributes()
55 data()->addAttribute(CIRCLE_TYPE(), ModelAPI_AttributeString::typeId());
57 data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
58 data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
59 data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
60 data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
62 data()->addAttribute(FIRST_POINT_ID(), GeomDataAPI_Point2D::typeId());
63 data()->addAttribute(SECOND_POINT_ID(), GeomDataAPI_Point2D::typeId());
64 data()->addAttribute(THIRD_POINT_ID(), GeomDataAPI_Point2D::typeId());
65 data()->addAttribute(FIRST_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
66 data()->addAttribute(SECOND_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
67 data()->addAttribute(THIRD_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
69 data()->addAttribute(CIRCLE_RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
70 data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
72 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
73 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
74 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIRST_POINT_REF_ID());
75 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SECOND_POINT_REF_ID());
76 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), THIRD_POINT_REF_ID());
79 void SketchPlugin_MacroCircle::execute()
81 std::string aType = string(CIRCLE_TYPE())->value();
82 if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
83 createCircleByCenterAndPassed();
84 else if (aType == CIRCLE_TYPE_BY_THREE_POINTS())
85 createCircleByThreePoints();
88 static void convertToPointOrTangent(const AttributeRefAttrPtr& theRefAttr,
89 const AttributePtr& theBaseAttr,
90 std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint,
91 std::shared_ptr<GeomAPI_Shape>& theTangentCurve)
93 AttributePtr anAttr = theBaseAttr;
94 if (theRefAttr->isObject()) {
95 FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
97 if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
98 theTangentCurve = aTgFeature->lastResult()->shape();
101 anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
104 anAttr = theRefAttr->attr();
106 thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
109 void SketchPlugin_MacroCircle::createCircleByCenterAndPassed()
111 // Create circle feature.
112 std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByCenterAndPassed();
113 FeaturePtr aCircleFeature = createCircleFeature(aCircle);
115 // Create constraints.
116 SketchPlugin_Tools::createConstraint(this,
117 CENTER_POINT_REF_ID(),
118 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
121 SketchPlugin_Tools::createConstraint(this,
122 PASSED_POINT_REF_ID(),
124 aCircleFeature->lastResult(),
128 void SketchPlugin_MacroCircle::createCircleByThreePoints()
130 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
131 SECOND_POINT_REF_ID(),
132 THIRD_POINT_REF_ID() };
134 // Create circle feature.
135 std::shared_ptr<GeomAPI_Circ2d> aCircle = shapeByThreePoints();
136 FeaturePtr aCircleFeature = createCircleFeature(aCircle);
137 ResultPtr aCircleResult = aCircleFeature->lastResult();
139 // Create constraints.
140 for (int i = 0; i < 3; ++i)
141 SketchPlugin_Tools::createConstraint(this, aPointRef[i], AttributePtr(), aCircleResult, true);
144 FeaturePtr SketchPlugin_MacroCircle::createCircleFeature(
145 const std::shared_ptr<GeomAPI_Circ2d>& theCircle)
147 FeaturePtr aCircleFeature = sketch()->addFeature(SketchPlugin_Circle::ID());
148 std::shared_ptr<GeomAPI_Pnt2d> aCenter = theCircle->center();
149 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
150 aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCenter->x(),
152 aCircleFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(theCircle->radius());
153 aCircleFeature->boolean(SketchPlugin_Circle::AUXILIARY_ID())
154 ->setValue(boolean(AUXILIARY_ID())->value());
155 aCircleFeature->execute();
156 return aCircleFeature;
159 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByCenterAndPassed()
161 AttributePtr aCenterAttr = attribute(CENTER_POINT_ID());
162 AttributePtr aPassedAttr = attribute(PASSED_POINT_ID());
163 if (!aCenterAttr->isInitialized() || !aPassedAttr->isInitialized())
164 return std::shared_ptr<GeomAPI_Circ2d>();
166 AttributeRefAttrPtr aPassedRef = refattr(PASSED_POINT_REF_ID());
167 // Calculate circle parameters
168 std::shared_ptr<GeomAPI_Pnt2d> aCenter =
169 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterAttr)->pnt();
170 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
171 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
172 convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
175 std::shared_ptr<GeomAPI_Circ2d> aCircle;
177 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
178 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aTangentCurve, anAxis));
180 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoint));
184 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByThreePoints()
186 std::string aPointAttr[3] = { FIRST_POINT_ID(),
189 std::string aPointRef[3] = { FIRST_POINT_REF_ID(),
190 SECOND_POINT_REF_ID(),
191 THIRD_POINT_REF_ID() };
192 std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
193 for (int aPntIndex = 0; aPntIndex < 3; ++aPntIndex) {
194 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
195 if (!aPassedAttr->isInitialized())
198 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
199 // calculate circle parameters
200 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
201 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
202 convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
205 aPassedEntities[aPntIndex] = aPassedPoint;
207 aPassedEntities[aPntIndex] = aTangentCurve;
210 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
211 std::shared_ptr<GeomAPI_Circ2d> aCircle = std::shared_ptr<GeomAPI_Circ2d>(
212 new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
213 if (!aCircle->implPtr<char>())
214 return std::shared_ptr<GeomAPI_Circ2d>();
218 std::shared_ptr<GeomAPI_Circ2d> SketchPlugin_MacroCircle::shapeByTwoPassedPoints()
220 std::string aPointAttr[2] = { FIRST_POINT_ID(),
222 std::string aPointRef[2] = { FIRST_POINT_REF_ID(),
223 SECOND_POINT_REF_ID() };
224 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoints[2]; // there is possible only two passed points
225 std::shared_ptr<GeomAPI_Interface> aPassedEntities[3];
227 for (; aPntIndex < 2; ++aPntIndex) {
228 AttributePtr aPassedAttr = attribute(aPointAttr[aPntIndex]);
229 if (!aPassedAttr->isInitialized())
232 AttributeRefAttrPtr aPassedRef = refattr(aPointRef[aPntIndex]);
233 // calculate circle parameters
234 std::shared_ptr<GeomAPI_Pnt2d> aPassedPoint;
235 std::shared_ptr<GeomAPI_Shape> aTangentCurve;
236 convertToPointOrTangent(aPassedRef, aPassedAttr, aPassedPoint, aTangentCurve);
239 aPassedEntities[aPntIndex] = aPassedPoint;
240 aPassedPoints[aPntIndex] = aPassedPoint;
242 aPassedEntities[aPntIndex] = aTangentCurve;
243 // if the circle is tangent to any curve,
244 // the third point will be initialized by the tangent point
245 aPassedEntities[2] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPassedAttr)->pnt();
249 return std::shared_ptr<GeomAPI_Circ2d>();
251 std::shared_ptr<GeomAPI_Circ2d> aCircle;
252 if (aPassedEntities[2]) {
253 std::shared_ptr<GeomAPI_Ax3> anAxis = SketchPlugin_Sketch::plane(sketch());
254 aCircle = std::shared_ptr<GeomAPI_Circ2d>(
255 new GeomAPI_Circ2d(aPassedEntities[0], aPassedEntities[1], aPassedEntities[2], anAxis));
257 // the circle is defined by two points, calculate its parameters manually
258 std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(
259 (aPassedPoints[0]->x() + aPassedPoints[1]->x()) * 0.5,
260 (aPassedPoints[0]->y() + aPassedPoints[1]->y()) * 0.5));
261 aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(aCenter, aPassedPoints[0]));
263 if (!aCircle->implPtr<char>())
264 return std::shared_ptr<GeomAPI_Circ2d>();
268 AISObjectPtr SketchPlugin_MacroCircle::getAISObject(AISObjectPtr thePrevious)
270 SketchPlugin_Sketch* aSketch = sketch();
272 return AISObjectPtr();
275 // Create circle on the sketch plane
276 std::shared_ptr<GeomAPI_Circ2d> aCircleOnSketch;
277 std::string aType = string(CIRCLE_TYPE())->value();
278 if (aType == CIRCLE_TYPE_BY_CENTER_AND_PASSED_POINTS())
279 aCircleOnSketch = shapeByCenterAndPassed();
280 else if (aType == CIRCLE_TYPE_BY_THREE_POINTS()) {
281 if (attribute(THIRD_POINT_ID())->isInitialized())
282 aCircleOnSketch = shapeByThreePoints();
284 aCircleOnSketch = shapeByTwoPassedPoints();
287 if (!aCircleOnSketch)
288 return AISObjectPtr();
290 std::shared_ptr<GeomAPI_Pnt2d> aCenter2D = aCircleOnSketch->center();
291 double aRadius = aCircleOnSketch->radius();
293 // Compute a circle in 3D view.
294 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenter2D->x(), aCenter2D->y()));
295 std::shared_ptr<GeomDataAPI_Dir> aNDir =
296 std::dynamic_pointer_cast<GeomDataAPI_Dir>(
297 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
298 std::shared_ptr<GeomAPI_Dir> aNormal = aNDir->dir();
299 GeomShapePtr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius);
300 GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
301 if(!aCircleShape.get() || !aCenterPointShape.get()) {
302 return AISObjectPtr();
305 std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
306 aShapes.push_back(aCircleShape);
307 aShapes.push_back(aCenterPointShape);
309 std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
310 AISObjectPtr anAIS = thePrevious;
312 anAIS.reset(new GeomAPI_AISObject());
314 anAIS->createShape(aCompound);
318 void SketchPlugin_MacroCircle::attributeChanged(const std::string& theID) {
319 double aRadius = 0.0;
320 // If circle type switched reset all attributes.
321 if(theID == CIRCLE_TYPE()) {
322 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
323 SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
324 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
325 SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
326 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_ID());
327 SketchPlugin_Tools::resetAttribute(this, FIRST_POINT_REF_ID());
328 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_ID());
329 SketchPlugin_Tools::resetAttribute(this, SECOND_POINT_REF_ID());
330 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_ID());
331 SketchPlugin_Tools::resetAttribute(this, THIRD_POINT_REF_ID());
332 } else if(theID == CENTER_POINT_ID() || theID == PASSED_POINT_ID()) {
333 std::shared_ptr<GeomDataAPI_Point2D> aCenterPointAttr =
334 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
335 if(!aCenterPointAttr->isInitialized()) {
338 std::shared_ptr<GeomDataAPI_Point2D> aPassedPointAttr =
339 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
340 if(!aPassedPointAttr->isInitialized()) {
344 aRadius = aCenterPointAttr->pnt()->distance(aPassedPointAttr->pnt());
345 } else if(theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
346 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
347 int aNbInitialized = 0;
348 for(int i = 1; i <= 3; ++i) {
349 std::shared_ptr<GeomDataAPI_Point2D> aCurPnt =
350 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(POINT_ID(i)));
351 if(aCurPnt->isInitialized())
352 aPoints[aNbInitialized++] = aCurPnt->pnt();
355 std::shared_ptr<GeomAPI_Circ2d> aCircle;
356 if(aNbInitialized == 1)
358 else if(aNbInitialized == 2)
359 aCircle = shapeByTwoPassedPoints();
361 aCircle = shapeByThreePoints();
363 aRadius = aCircle->radius();
366 AttributeDoublePtr aRadiusAttr = real(CIRCLE_RADIUS_ID());
367 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
368 aRadiusAttr->setValue(aRadius);
369 data()->blockSendAttributeUpdated(aWasBlocked, false);