1 // Copyright (C) 2014-2024 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SketchPlugin_Circle.h"
21 #include "SketchPlugin_Sketch.h"
22 #include "SketchPlugin_Tools.h"
23 #include <ModelAPI_Data.h>
24 #include <ModelAPI_ResultConstruction.h>
25 #include <ModelAPI_AttributeSelection.h>
26 #include <ModelAPI_AttributeReference.h>
27 #include <ModelAPI_AttributeInteger.h>
28 #include <ModelAPI_AttributeDouble.h>
29 #include <ModelAPI_AttributeString.h>
30 #include <ModelAPI_Events.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_Tools.h>
33 #include <ModelAPI_Validator.h>
34 #include <SketchPlugin_Point.h>
35 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
37 #include <GeomAPI_Pnt2d.h>
38 #include <GeomAPI_Circ.h>
39 #include <GeomAPI_Dir2d.h>
40 #include <GeomAPI_Circ2d.h>
41 #include <GeomAPI_Vertex.h>
42 #include <GeomAPI_XY.h>
43 #include <GeomDataAPI_Point2D.h>
44 #include <GeomDataAPI_Dir.h>
45 #include <GeomAlgoAPI_PointBuilder.h>
46 #include <GeomAlgoAPI_EdgeBuilder.h>
47 #include <GeomAlgoAPI_CompoundBuilder.h>
49 #include <Events_Loop.h>
53 const double tolerance = 1e-7;
54 const double paramTolerance = 1.e-4;
55 const double PI = 3.141592653589793238463;
57 //*************************************************************************************
58 SketchPlugin_Circle::SketchPlugin_Circle()
59 : SketchPlugin_SketchEntity()
63 //*************************************************************************************
64 void SketchPlugin_Circle::initDerivedClassAttributes()
66 data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
67 data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
68 data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
70 // Attrs for construction point
71 data()->addAttribute(CONSTRUCTION_POINT_REF_ID(), ModelAPI_AttributeReference::typeId());
72 data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
74 AttributeDoublePtr anAngleAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>
75 (data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId()));
76 if(!anAngleAttr->isInitialized())
78 anAngleAttr->setValue(0.0);
81 AttributeBooleanPtr isAddConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>
82 (data()->addAttribute(ADD_CONSTRUCTION_POINT_ID(), ModelAPI_AttributeBoolean::typeId()));
83 if (!isAddConstrAttr->isInitialized())
85 isAddConstrAttr->setValue(false);
88 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
89 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ADD_CONSTRUCTION_POINT_ID());
90 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CONSTRUCTION_POINT_REF_ID());
91 ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ANGLE_ID());
94 //*************************************************************************************
95 void SketchPlugin_Circle::execute()
97 SketchPlugin_Sketch* aSketch = sketch();
102 //manage construction point movement/deletion
103 bool isToAddPoint = boolean(ADD_CONSTRUCTION_POINT_ID())->value();
104 AttributeReferencePtr aConstrRefAttr = reference((CONSTRUCTION_POINT_REF_ID()));
105 if(aConstrRefAttr->isInitialized())
106 isToAddPoint ? computeAngle(): removeConstructionPoint();
108 // Compute a circle in 3D view.
109 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
110 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
111 AttributeDoublePtr aRadiusAttr = real(RADIUS_ID());
112 if (!aCenterAttr->isInitialized() || !aRadiusAttr->isInitialized()) {
116 double aRadius = aRadiusAttr->value();
117 if (aRadius < tolerance) {
121 // Make a visible center point.
122 SketchPlugin_Sketch::createPoint2DResult(this, sketch(), CENTER_ID(), 0);
124 // Make a visible circle.
125 std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y()));
126 std::shared_ptr<GeomDataAPI_Dir> aNDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
127 aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID()));
128 std::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
130 AttributeDoublePtr anAngleAttr = real(ANGLE_ID());
131 if (!anAngleAttr->isInitialized())
132 anAngleAttr->setValue(0);
133 double aValAn = anAngleAttr->value();
135 std::shared_ptr<GeomAPI_Edge> aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aRadius, aValAn / 180 * PI);
137 std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 1);
138 aResult->setShape(aCircleShape);
139 aResult->setIsInHistory(false);
140 setResult(aResult, 1);
142 if(isToAddPoint && !aConstrRefAttr->isInitialized())
143 setConstructionPoint();
146 //*************************************************************************************
147 std::shared_ptr<GeomAPI_Edge> SketchPlugin_Circle::getCircleShape()
149 std::shared_ptr<GeomAPI_Shape> aSelection;
150 ResultPtr aCircleRes = lastResult();
152 aSelection = aCircleRes->shape();
153 if (aSelection && !aSelection->isNull() && aSelection->isEdge())
155 return std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aSelection));
160 //*************************************************************************************
161 void SketchPlugin_Circle::computeAngle()
163 if(!boolean(ADD_CONSTRUCTION_POINT_ID())->value()){
167 AttributeReferencePtr aConstrRefAttr = reference((CONSTRUCTION_POINT_REF_ID()));
168 std::shared_ptr<GeomAPI_Edge> anCircEdge = getCircleShape();
169 if(anCircEdge && aConstrRefAttr->isInitialized())
171 std::shared_ptr<GeomAPI_Circ> aCirc = anCircEdge->circle();
173 // Get point and project it on line
174 FeaturePtr aPointFeature = ModelAPI_Feature::feature(aConstrRefAttr->value());
175 AttributePoint2DPtr aConstrPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
176 aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
177 GeomPointPtr aPntRot3D = aCirc->project( sketch()->to3D(aConstrPoint->x(), aConstrPoint->y()));
180 GeomPointPtr aNorm = sketch()->to3D(real(RADIUS_ID())->value(), 0);
181 double aStartParam, anEndParam;
182 aCirc->parameter(aPntRot3D, paramTolerance, anEndParam);
183 aCirc->parameter(aNorm, paramTolerance, aStartParam);
185 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
186 real(ANGLE_ID())->setValue((anEndParam - aStartParam) / PI * 180.0);
187 data()->blockSendAttributeUpdated(aWasBlocked, false);
191 //*************************************************************************************
192 void SketchPlugin_Circle::setConstructionPoint()
194 if(!boolean(ADD_CONSTRUCTION_POINT_ID())->value()){
198 SketchPlugin_Sketch* aSketch = sketch();
203 AttributeReferencePtr aConstrRefAttr = reference((CONSTRUCTION_POINT_REF_ID()));
204 if(!aConstrRefAttr->isInitialized())
206 bool aWasBlocked = data()->blockSendAttributeUpdated(true);
207 std::shared_ptr<GeomAPI_Edge> anCircEdge = getCircleShape();
208 GeomPnt2dPtr aCircleSewPoint = aSketch->to2D(anCircEdge->firstPoint());
210 FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
211 auto aCurCircle = this->document()->currentFeature(true);
212 aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aCurCircle);
213 AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
214 aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
215 aCoord->setValue(aCircleSewPoint);
216 aPointFeature->execute();
217 aConstrRefAttr->setValue(aPointFeature);
219 SketchPlugin_Tools::createConstraintAttrObject(aSketch,
220 SketchPlugin_ConstraintCoincidence::ID(), aCoord, lastResult());
221 data()->blockSendAttributeUpdated(aWasBlocked, false);
225 //*************************************************************************************
226 void SketchPlugin_Circle::removeConstructionPoint()
228 AttributeReferencePtr aConstrRefAttr = reference((CONSTRUCTION_POINT_REF_ID()));
229 FeaturePtr aPointFeature = ModelAPI_Feature::feature(aConstrRefAttr->value());
232 std::set<FeaturePtr> aDummySet;
233 aDummySet.insert(aPointFeature);
234 std::map<FeaturePtr, std::set<FeaturePtr>> aReferenceMap;
235 ModelAPI_Tools::findAllReferences(aDummySet, aReferenceMap, false, true);
236 std::set<FeaturePtr> aFeaturesRefsTo;
237 ModelAPI_Tools::findRefsToFeatures(aDummySet, aReferenceMap, aFeaturesRefsTo);
239 // remove all references to the point except the circle feature(this)
240 for(auto aFeature : aFeaturesRefsTo)
242 if (aFeature->getKind() != this->ID())
243 document()->removeFeature(aFeature);
245 document()->removeFeature(aPointFeature);
246 Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
248 aConstrRefAttr->setValue(FeaturePtr());
249 aConstrRefAttr->reset();
250 real(ANGLE_ID())->setValue(0.0);
253 //*************************************************************************************
254 bool SketchPlugin_Circle::isFixed() {
255 return data()->selection(EXTERNAL_ID())->context().get() != NULL;
258 //*************************************************************************************
259 void SketchPlugin_Circle::attributeChanged(const std::string& theID) {
260 // the second condition for unability to move external segments anywhere
261 if (theID == EXTERNAL_ID() || isFixed()) {
262 std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
264 // empty shape in selection shows that the shape is equal to context
265 ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
267 aSelection = anExtRes->shape();
269 // update arguments due to the selection value
270 if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
271 std::shared_ptr<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
272 std::shared_ptr<GeomAPI_Circ> aCirc = anEdge->circle();
273 std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
274 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
275 aCenterAttr->setValue(sketch()->to2D(aCirc->center()));
277 real(RADIUS_ID())->setValue(aCirc->radius());
278 real(ANGLE_ID())->setValue(0.0);