Salome HOME
2b45cb65a45458a6bbb61f182e10b2fee5c92a31
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Sketch.cpp
1 // File:        SketchPlugin_Sketch.cxx
2 // Created:     27 Mar 2014
3 // Author:      Mikhail PONIKAROV
4
5 #include <Config_PropManager.h>
6
7 #include <GeomAlgoAPI_CompoundBuilder.h>
8 #include <GeomAlgoAPI_FaceBuilder.h>
9
10 #include <GeomAPI_AISObject.h>
11 #include <GeomAPI_Dir.h>
12 #include <GeomAPI_PlanarEdges.h>
13 #include <GeomAPI_XYZ.h>
14
15 #include <GeomDataAPI_Dir.h>
16 #include <GeomDataAPI_Point.h>
17 #include <GeomAlgoAPI_FaceBuilder.h>
18
19 #include <ModelAPI_AttributeRefList.h>
20 #include <ModelAPI_Data.h>
21 #include <ModelAPI_Document.h>
22 #include <ModelAPI_Feature.h>
23 #include <ModelAPI_Object.h>
24 #include <ModelAPI_ResultConstruction.h>
25 #include <ModelAPI_Validator.h>
26 #include <ModelAPI_Session.h>
27
28 #include <SketchPlugin_Sketch.h>
29 #include <SketchPlugin_Feature.h>
30
31 #include <boost/smart_ptr/shared_ptr.hpp>
32
33 #include <math.h>
34 #include <vector>
35
36 using namespace std;
37
38 SketchPlugin_Sketch::SketchPlugin_Sketch()
39 {
40 }
41
42 void SketchPlugin_Sketch::initAttributes()
43 {
44   data()->addAttribute(SketchPlugin_Sketch::ORIGIN_ID(), GeomDataAPI_Point::type());
45   data()->addAttribute(SketchPlugin_Sketch::DIRX_ID(), GeomDataAPI_Dir::type());
46   data()->addAttribute(SketchPlugin_Sketch::DIRY_ID(), GeomDataAPI_Dir::type());
47   data()->addAttribute(SketchPlugin_Sketch::NORM_ID(), GeomDataAPI_Dir::type());
48   data()->addAttribute(SketchPlugin_Sketch::FEATURES_ID(), ModelAPI_AttributeRefList::type());
49   // the selected face, base for the sketcher plane, not obligatory
50   data()->addAttribute(SketchPlugin_Feature::EXTERNAL_ID(), ModelAPI_AttributeSelection::type());
51   ModelAPI_Session::get()->validators()->registerNotObligatory(
52     getKind(), SketchPlugin_Feature::EXTERNAL_ID());
53 }
54
55 void SketchPlugin_Sketch::execute()
56 {
57   if (!data()->isValid())
58     return;
59   boost::shared_ptr<ModelAPI_AttributeRefList> aRefList = boost::dynamic_pointer_cast<
60       ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
61
62   boost::shared_ptr<GeomDataAPI_Point> anOrigin = boost::dynamic_pointer_cast<GeomDataAPI_Point>(
63       data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
64   boost::shared_ptr<GeomDataAPI_Dir> aDirX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
65       data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
66   boost::shared_ptr<GeomDataAPI_Dir> aDirY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
67       data()->attribute(SketchPlugin_Sketch::DIRY_ID()));
68   boost::shared_ptr<GeomDataAPI_Dir> aNorm = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
69       data()->attribute(SketchPlugin_Sketch::NORM_ID()));
70
71   std::list<ObjectPtr> aFeatures = aRefList->list();
72   if (aFeatures.empty())
73     return;
74
75   std::list<ObjectPtr>::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end();
76   boost::shared_ptr<SketchPlugin_Feature> aFeature;
77   std::list<boost::shared_ptr<GeomAPI_Shape> > aFeaturesPreview;
78   for (; anIt != aLast; anIt++) {
79     aFeature = boost::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
80     if (aFeature) {
81       // do not include the external edges into the result
82       if (aFeature->data()->attribute(SketchPlugin_Feature::EXTERNAL_ID())) {
83         if (aFeature->data()->selection(SketchPlugin_Feature::EXTERNAL_ID())->value())
84           continue;
85       }
86
87       const std::list<boost::shared_ptr<ModelAPI_Result> >& aRes = aFeature->results();
88       std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aResIter = aRes.cbegin();
89       for (; aResIter != aRes.cend(); aResIter++) {
90         boost::shared_ptr<ModelAPI_ResultConstruction> aConstr = boost::dynamic_pointer_cast<
91             ModelAPI_ResultConstruction>(*aResIter);
92         if (aConstr) {
93           boost::shared_ptr<GeomAPI_Shape> aShape = aConstr->shape();
94           if (aShape)
95             aFeaturesPreview.push_back(aShape);
96         }
97       }
98     }
99   }
100
101   if (aFeaturesPreview.empty())
102     return;
103
104   // Collect all edges as one big wire
105   boost::shared_ptr<GeomAPI_PlanarEdges> aBigWire(new GeomAPI_PlanarEdges);
106   std::list<boost::shared_ptr<GeomAPI_Shape> >::const_iterator aShapeIt = aFeaturesPreview.begin();
107   for (; aShapeIt != aFeaturesPreview.end(); ++aShapeIt) {
108     aBigWire->addEdge(*aShapeIt);
109   }
110   aBigWire->setOrigin(anOrigin->pnt());
111   aBigWire->setDirX(aDirX->dir());
112   aBigWire->setDirY(aDirY->dir());
113   aBigWire->setNorm(aNorm->dir());
114
115 //  GeomAlgoAPI_SketchBuilder::createFaces(anOrigin->pnt(), aDirX->dir(), aDirY->dir(), aNorm->dir(),
116 //                                         aFeaturesPreview, aLoops, aWires);
117   boost::shared_ptr<ModelAPI_ResultConstruction> aConstr = document()->createConstruction(data());
118   aConstr->setShape(aBigWire);
119   setResult(aConstr);
120 }
121
122 boost::shared_ptr<ModelAPI_Feature> SketchPlugin_Sketch::addFeature(std::string theID)
123 {
124   boost::shared_ptr<ModelAPI_Feature> aNew = document()->addFeature(theID);
125   if (aNew) {
126     boost::dynamic_pointer_cast<SketchPlugin_Feature>(aNew)->setSketch(this);
127     data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->append(aNew);
128   }
129   return aNew;
130 }
131
132 int SketchPlugin_Sketch::numberOfSubs() const
133 {
134   return data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->size();
135 }
136
137 boost::shared_ptr<ModelAPI_Feature> SketchPlugin_Sketch::subFeature(const int theIndex) const
138 {
139   ObjectPtr anObj = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->object(theIndex);
140   return boost::dynamic_pointer_cast<ModelAPI_Feature>(anObj);
141 }
142
143 int SketchPlugin_Sketch::subFeatureId(const int theIndex) const
144 {
145   return subFeature(theIndex)->data()->featureId();
146 }
147
148 bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const
149 {
150   // check is this feature of result
151   FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
152   if (!aFeature) {
153     ResultPtr aRes = boost::dynamic_pointer_cast<ModelAPI_Result>(theObject);
154     if (aRes)
155       aFeature = document()->feature(aRes);
156   }
157   if (aFeature) {
158     list<ObjectPtr> aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list();
159     for(list<ObjectPtr>::iterator aSubIt = aSubs.begin(); aSubIt != aSubs.end(); aSubIt++) {
160       if (*aSubIt == aFeature)
161         return true;
162     }
163   }
164   return false;
165 }
166
167 boost::shared_ptr<GeomAPI_Pnt> SketchPlugin_Sketch::to3D(const double theX, const double theY)
168 {
169   boost::shared_ptr<GeomDataAPI_Point> aC = boost::dynamic_pointer_cast<GeomDataAPI_Point>(
170       data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
171   boost::shared_ptr<GeomDataAPI_Dir> aX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
172       data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
173   boost::shared_ptr<GeomDataAPI_Dir> aY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
174       data()->attribute(SketchPlugin_Sketch::DIRY_ID()));
175
176   boost::shared_ptr<GeomAPI_XYZ> aSum = aC->pnt()->xyz()->added(aX->dir()->xyz()->multiplied(theX))
177       ->added(aY->dir()->xyz()->multiplied(theY));
178
179   return boost::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aSum));
180 }
181
182 boost::shared_ptr<GeomAPI_Pnt2d> SketchPlugin_Sketch::to2D(
183   const boost::shared_ptr<GeomAPI_Pnt>& thePnt)
184 {
185   boost::shared_ptr<GeomDataAPI_Point> aC = boost::dynamic_pointer_cast<GeomDataAPI_Point>(
186       data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
187   boost::shared_ptr<GeomDataAPI_Dir> aX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
188       data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
189   boost::shared_ptr<GeomDataAPI_Dir> aY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
190       data()->attribute(SketchPlugin_Sketch::DIRY_ID()));
191   return thePnt->to2D(aC->pnt(), aX->dir(), aY->dir());
192 }
193
194
195 bool SketchPlugin_Sketch::isPlaneSet()
196 {
197   boost::shared_ptr<GeomDataAPI_Dir> aNormal = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
198       data()->attribute(SketchPlugin_Sketch::NORM_ID()));
199
200   return aNormal && !(aNormal->x() == 0 && aNormal->y() == 0 && aNormal->z() == 0);
201 }
202
203 boost::shared_ptr<GeomAPI_Pln> SketchPlugin_Sketch::plane()
204 {
205   boost::shared_ptr<GeomDataAPI_Point> anOrigin = boost::dynamic_pointer_cast<GeomDataAPI_Point>(
206       data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
207   boost::shared_ptr<GeomDataAPI_Dir> aNorm = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
208       data()->attribute(SketchPlugin_Sketch::NORM_ID()));
209
210   if (!anOrigin || !aNorm)
211     return boost::shared_ptr<GeomAPI_Pln>();
212
213   return boost::shared_ptr<GeomAPI_Pln>(new GeomAPI_Pln(anOrigin->pnt(), aNorm->dir()));
214 }
215
216 void addPlane(double theX, double theY, double theZ,
217               std::list<boost::shared_ptr<GeomAPI_Shape> >& theShapes)
218 {
219   boost::shared_ptr<GeomAPI_Pnt> anOrigin(new GeomAPI_Pnt(0, 0, 0));
220   boost::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(theX, theY, theZ));
221   double aSize = Config_PropManager::integer("Sketch planes", "Size of planes", PLANE_SIZE);
222   boost::shared_ptr<GeomAPI_Shape> aFace = GeomAlgoAPI_FaceBuilder::square(anOrigin, aNormal,
223                                                                            aSize);
224   theShapes.push_back(aFace);
225 }
226
227 AISObjectPtr SketchPlugin_Sketch::getAISObject(AISObjectPtr thePrevious)
228 {
229   boost::shared_ptr<GeomDataAPI_Dir> aNorm = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
230       data()->attribute(SketchPlugin_Sketch::NORM_ID()));
231
232   if (!aNorm || (aNorm->x() == 0 && aNorm->y() == 0 && aNorm->z() == 0)) {
233     AISObjectPtr aAIS = thePrevious;
234     if (!aAIS) {
235       std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
236
237       addPlane(1, 0, 0, aFaces);  // YZ plane
238       addPlane(0, 1, 0, aFaces);  // XZ plane
239       addPlane(0, 0, 1, aFaces);  // XY plane
240       boost::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aFaces);
241       aAIS = AISObjectPtr(new GeomAPI_AISObject());
242       aAIS->createShape(aCompound);
243
244       std::vector<int> aRGB = Config_PropManager::color("Sketch planes", "planes_color",
245       SKETCH_PLANE_COLOR);
246       aAIS->setColor(aRGB[0], aRGB[1], aRGB[2]);
247
248       aAIS->setWidth(Config_PropManager::integer("Sketch planes", "planes_thickness",
249       SKETCH_WIDTH));
250     }
251     return aAIS;
252   }
253   return AISObjectPtr();
254 }
255
256 void SketchPlugin_Sketch::erase()
257 {
258   boost::shared_ptr<ModelAPI_AttributeRefList> aRefList = boost::dynamic_pointer_cast<
259       ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
260   std::list<ObjectPtr> aFeatures = aRefList->list();
261   std::list<ObjectPtr>::const_iterator anIt = aFeatures.begin();
262   for (; anIt != aFeatures.end(); anIt++) {
263     FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
264     if (aFeature) {
265        // subs are referenced from sketch, but must be removed for sure, so not checkings
266       document()->removeFeature(aFeature, false);
267     }
268   }
269   ModelAPI_CompositeFeature::erase();
270 }
271
272 void SketchPlugin_Sketch::attributeChanged() {
273   static bool kIsUpdated = false; // to avoid infinitive cycle on attrubtes change
274   static bool kIsAttrChanged = false;
275   boost::shared_ptr<GeomAPI_Shape> aSelection = 
276     data()->selection(SketchPlugin_Feature::EXTERNAL_ID())->value();
277   if (aSelection && !kIsUpdated) { // update arguments due to the selection value
278     kIsUpdated = true;
279     // update the sketch plane
280     boost::shared_ptr<GeomAPI_Pln> aPlane = GeomAlgoAPI_FaceBuilder::plane(aSelection);
281     if (aPlane) {
282       double anA, aB, aC, aD;
283       aPlane->coefficients(anA, aB, aC, aD);
284
285       // calculate attributes of the sketch
286       boost::shared_ptr<GeomAPI_Dir> aNormDir(new GeomAPI_Dir(anA, aB, aC));
287       boost::shared_ptr<GeomAPI_XYZ> aCoords = aNormDir->xyz();
288       boost::shared_ptr<GeomAPI_XYZ> aZero(new GeomAPI_XYZ(0, 0, 0));
289       aCoords = aCoords->multiplied(-aD * aCoords->distance(aZero));
290       boost::shared_ptr<GeomAPI_Pnt> anOrigPnt(new GeomAPI_Pnt(aCoords));
291       // X axis is preferable to be dirX on the sketch
292       static const double tol = 1.e-7;
293       bool isX = fabs(anA - 1.0) < tol && fabs(aB) < tol && fabs(aC) < tol;
294       boost::shared_ptr<GeomAPI_Dir> aTempDir(
295         isX ? new GeomAPI_Dir(0, 1, 0) : new GeomAPI_Dir(1, 0, 0));
296       boost::shared_ptr<GeomAPI_Dir> aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir)));
297       boost::shared_ptr<GeomAPI_Dir> aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir)));
298
299       kIsAttrChanged = false; // track the attributes were really changed during the plane update
300       boost::shared_ptr<GeomDataAPI_Point> anOrigin = boost::dynamic_pointer_cast
301         <GeomDataAPI_Point>(data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
302       anOrigin->setValue(anOrigPnt);
303       boost::shared_ptr<GeomDataAPI_Dir> aNormal = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
304         data()->attribute(SketchPlugin_Sketch::NORM_ID()));
305       aNormal->setValue(aNormDir);
306       boost::shared_ptr<GeomDataAPI_Dir> aDirX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
307         data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
308       aDirX->setValue(aXDir);
309       boost::shared_ptr<GeomDataAPI_Dir> aDirY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(
310         data()->attribute(SketchPlugin_Sketch::DIRY_ID()));
311       aDirY->setValue(aYDir);
312       boost::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
313
314       if (kIsAttrChanged) {
315         // the plane was changed, so reexecute sub-elements to update shapes (located in new plane)
316         ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
317         list<ObjectPtr> aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list();
318         for(list<ObjectPtr>::iterator aSubIt = aSubs.begin(); aSubIt != aSubs.end(); aSubIt++) {
319           boost::shared_ptr<SketchPlugin_Feature> aFeature = 
320             boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aSubIt);
321           if (aFeature && aFactory->validate(aFeature)) {
322             aFeature->execute();
323           }
324         }
325         kIsAttrChanged = false;
326       }
327     }
328     kIsUpdated = false;
329   } else if (kIsUpdated) { // other attributes are updated during the selection comupation
330     kIsAttrChanged = true;
331   }
332 }