Salome HOME
Fix crash on constraints which use Projection feature
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Projection.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_Projection.cpp
4 // Created: 07 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include <SketchPlugin_Projection.h>
8
9 #include <SketchPlugin_Arc.h>
10 #include <SketchPlugin_Circle.h>
11 #include <SketchPlugin_Line.h>
12 #include <SketchPlugin_Sketch.h>
13 #include <SketchPlugin_ConstraintRigid.h>
14
15 #include <ModelAPI_AttributeRefAttr.h>
16 #include <ModelAPI_AttributeSelection.h>
17 #include <ModelAPI_AttributeDouble.h>
18 #include <ModelAPI_ResultConstruction.h>
19 #include <ModelAPI_Session.h>
20 #include <ModelAPI_Validator.h>
21
22 #include <GeomAPI_Circ.h>
23 #include <GeomAPI_Edge.h>
24 #include <GeomAPI_Lin.h>
25 #include <GeomAPI_Pnt.h>
26 #include <GeomAPI_Pnt2d.h>
27 #include <GeomAlgoAPI_EdgeBuilder.h>
28 #include <GeomDataAPI_Point2D.h>
29
30 #include <cmath>
31
32 static const double tolerance = 1.e-7;
33
34 static std::shared_ptr<GeomAPI_Edge> emptyEdge()
35 {
36   static std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge);
37   return anEdge;
38 }
39
40 SketchPlugin_Projection::SketchPlugin_Projection()
41     : SketchPlugin_SketchEntity(),
42       myIsComputing(false)
43 {
44 }
45
46 void SketchPlugin_Projection::initDerivedClassAttributes()
47 {
48   data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
49   data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
50   data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
51
52   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
53   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
54
55   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
56 }
57
58 void SketchPlugin_Projection::execute()
59 {
60   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
61   if (!aRefAttr || !aRefAttr->isInitialized())
62     return;
63   FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
64
65   if (!lastResult().get() && aProjection->lastResult().get()) {
66     ResultConstructionPtr aConstr = document()->createConstruction(data());
67     aConstr->setShape(emptyEdge());
68     aConstr->setIsInHistory(false);
69     aConstr->setDisplayed(false);
70     setResult(aConstr);
71
72     aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
73   }
74 }
75
76 void SketchPlugin_Projection::move(double theDeltaX, double theDeltaY)
77 {
78   // feature cannot be moved
79 }
80
81 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
82 {
83   if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
84     myIsComputing = true;
85     computeProjection(theID);
86     myIsComputing = false;
87   }
88 }
89
90 void SketchPlugin_Projection::computeProjection(const std::string& theID)
91 {
92   AttributeSelectionPtr aExtFeature =
93       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
94
95   std::shared_ptr<GeomAPI_Edge> anEdge;
96   if (aExtFeature && aExtFeature->value() && aExtFeature->value()->isEdge()) {
97     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->value()));
98   } else if (aExtFeature->context() && aExtFeature->context()->shape() && aExtFeature->context()->shape()->isEdge()) {
99     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aExtFeature->context()->shape()));
100   }
101   if (!anEdge.get())
102     return;
103
104   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
105   FeaturePtr aProjection;
106   if (aRefAttr && aRefAttr->isInitialized())
107     aProjection = ModelAPI_Feature::feature(aRefAttr->object());
108
109   // if the type of feature differs with already selected, remove it and create once again
110   bool hasPrevProj = aProjection.get() != 0;
111   if (hasPrevProj) {
112     if ((anEdge->isLine() && aProjection->getKind() != SketchPlugin_Line::ID()) ||
113         (anEdge->isCircle() && aProjection->getKind() != SketchPlugin_Circle::ID()) ||
114         (anEdge->isArc() && aProjection->getKind() != SketchPlugin_Arc::ID())) {
115       DocumentPtr aDoc = sketch()->document();
116       aDoc->removeFeature(aProjection);
117       aProjection = FeaturePtr();
118       aRefAttr->setObject(aProjection);
119     }
120   }
121
122   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
123
124   ResultConstructionPtr aResult =
125       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
126   if (aResult && aResult->shape()) {
127     aResult->setShape(std::shared_ptr<GeomAPI_Edge>());
128     aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
129   }
130
131   if (anEdge->isLine()) {
132     std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
133     std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
134
135     std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
136     std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
137     if (aFirstInSketch->distance(aLastInSketch) < tolerance)
138       return; // line is semi-orthogonal to the sketch plane
139
140     if (!hasPrevProj)
141       aProjection = sketch()->addFeature(SketchPlugin_Line::ID());
142
143     // update attributes of projection
144     std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
145         aProjection->attribute(SketchPlugin_Line::START_ID()));
146     std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
147         aProjection->attribute(SketchPlugin_Line::END_ID()));
148     aStartPnt->setValue(aFirstInSketch);
149     aEndPnt->setValue(aLastInSketch);
150   }
151   else if (anEdge->isCircle()) {
152     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
153     double aRadius = aCircle->radius();
154
155     std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
156     std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
157
158     if (!hasPrevProj)
159       aProjection = sketch()->addFeature(SketchPlugin_Circle::ID());
160
161     // update attributes of projection
162     std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
163         aProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
164     aCenterPnt->setValue(aCenterInSketch);
165     aProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aRadius);
166   }
167   else if (anEdge->isArc()) {
168     std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(anEdge->firstPoint());
169     std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(anEdge->lastPoint());
170     std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
171     std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
172
173     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
174     std::shared_ptr<GeomAPI_Pnt> aCenter = aSketchPlane->project(aCircle->center());
175     std::shared_ptr<GeomAPI_Pnt2d> aCenterInSketch = sketch()->to2D(aCenter);
176
177     if (!hasPrevProj)
178       aProjection = sketch()->addFeature(SketchPlugin_Arc::ID());
179
180     // update attributes of projection
181     std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
182         aProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
183     std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
184         aProjection->attribute(SketchPlugin_Arc::START_ID()));
185     std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
186         aProjection->attribute(SketchPlugin_Arc::END_ID()));
187     aStartPnt->setValue(aFirstInSketch);
188     aEndPnt->setValue(aLastInSketch);
189     aCenterPnt->setValue(aCenterInSketch);
190   }
191
192   aProjection->execute();
193   aRefAttr->setObject(aProjection);
194
195   if (!hasPrevProj) {
196     FeaturePtr aFixed = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID());
197     aFixed->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(aProjection->lastResult());
198     aFixed->execute();
199   }
200
201   if (theID == EXTERNAL_FEATURE_ID()) {
202     selection(EXTERNAL_ID())->setValue(aExtFeature->context(), aExtFeature->context()->shape());
203
204     if (aResult) {
205       aResult->setShape(emptyEdge());
206       setResult(aResult);
207       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
208     }
209   }
210 }