Salome HOME
Improve loading of parts
[modules/shaper.git] / src / Model / Model_ResultPart.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <Model_ResultPart.h>
21 #include <ModelAPI_Data.h>
22 #include <Model_Data.h>
23 #include <ModelAPI_AttributeDocRef.h>
24 #include <ModelAPI_Session.h>
25 #include <ModelAPI_Feature.h>
26 #include <ModelAPI_ResultBody.h>
27 #include <ModelAPI_AttributeIntArray.h>
28 #include <ModelAPI_AttributeSelectionList.h>
29 #include <ModelAPI_AttributeReference.h>
30 #include <ModelAPI_AttributeDouble.h>
31 #include <Model_Document.h>
32 #include <Model_Application.h>
33 #include <Events_Loop.h>
34 #include <ModelAPI_Events.h>
35
36 #include <GeomAPI_Trsf.h>
37
38 #include <TNaming_Tool.hxx>
39 #include <TNaming_NamedShape.hxx>
40 #include <TDataStd_Name.hxx>
41 #include <TopoDS_Compound.hxx>
42 #include <BRep_Builder.hxx>
43 #include <TopExp_Explorer.hxx>
44
45 #define baseRef() \
46   std::dynamic_pointer_cast<Model_ResultPart>(data()->reference(BASE_REF_ID())->value())
47
48 void Model_ResultPart::initAttributes()
49 {
50   // append the color attribute. It is empty, the attribute will be filled by a request
51   AttributeDocRefPtr aDocRef = std::dynamic_pointer_cast<ModelAPI_AttributeDocRef>(
52     data()->addAttribute(DOC_REF(), ModelAPI_AttributeDocRef::typeId()));
53   data()->addAttribute(COLOR_ID(), ModelAPI_AttributeIntArray::typeId());
54   data()->addAttribute(BASE_REF_ID(), ModelAPI_AttributeReference::typeId());
55   data()->addAttribute(DEFLECTION_ID(), ModelAPI_AttributeDouble::typeId());
56   data()->addAttribute(TRANSPARENCY_ID(), ModelAPI_AttributeDouble::typeId());
57
58   if (aDocRef->isInitialized() && // initialized immediately means already exist and will be loaded
59       !Model_Application::getApplication()->hasDocument(aDocRef->docId()))
60     Model_Application::getApplication()->setLoadByDemand(data()->name(), aDocRef->docId());
61 }
62
63 std::shared_ptr<ModelAPI_Document> Model_ResultPart::partDoc()
64 {
65   if (myTrsf.get() && baseRef().get()) { // the second condition is due to #2035
66     return baseRef()->partDoc();
67   }
68   if (!data()->isValid())
69     return DocumentPtr();
70   DocumentPtr aRes = data()->document(DOC_REF())->value();
71   return aRes;
72 }
73
74 Model_ResultPart::Model_ResultPart()
75 {
76 }
77
78 void Model_ResultPart::activate()
79 {
80   if (myTrsf.get()) {
81     baseRef()->activate();
82     return;
83   }
84
85   std::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = data()->document(DOC_REF());
86
87   // activation may cause changes in current features in document, so it must be in transaction
88   bool isNewTransaction = false;
89   SessionPtr aMgr = ModelAPI_Session::get();
90   if (!aMgr->isOperation()) {
91     // open transaction even document is not created to set current docs in setActiveDocument
92     std::string aMsg = "Activation " + data()->name();
93     aMgr->startOperation(aMsg);
94     isNewTransaction = true;
95   }
96   if (!aDocRef->value().get()) {  // create (or open) a document if it is not yet created
97     Handle(Model_Application) anApp = Model_Application::getApplication();
98     if (anApp->isLoadByDemand(data()->name(), aDocRef->docId())) {
99       anApp->loadDocument(data()->name(), aDocRef->docId()); // if it is just new part, load fails
100     } else {
101       anApp->createDocument(aDocRef->docId());
102     }
103     std::shared_ptr<ModelAPI_Document> aDoc = aDocRef->value();
104     if (aDoc.get()) {
105       aDoc->synchronizeTransactions();
106       aDocRef->setValue(aDoc);
107     }
108   }
109   if (aDocRef->value().get()) {
110     ModelAPI_Session::get()->setActiveDocument(aDocRef->value());
111   }
112   if (isNewTransaction) {
113     aMgr->finishOperation();
114   }
115 }
116
117
118 void Model_ResultPart::loadPart()
119 {
120   std::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = data()->document(DOC_REF());
121   if (!aDocRef->value().get()) {  // create (or open) a document if it is not yet created
122     Handle(Model_Application) anApp = Model_Application::getApplication();
123     if (anApp->isLoadByDemand(data()->name(), aDocRef->docId())) {
124       anApp->loadDocument(data()->name(), aDocRef->docId()); // if it is just new part, load fails
125     }
126     else {
127       anApp->createDocument(aDocRef->docId());
128     }
129   }
130 }
131
132
133 std::shared_ptr<ModelAPI_ResultPart> Model_ResultPart::original()
134 {
135   if (myTrsf.get() && baseRef().get()) {  // the second condition is due to #2035
136     return baseRef()->original();
137   }
138   return std::dynamic_pointer_cast<ModelAPI_ResultPart>(data()->owner());
139 }
140
141 bool Model_ResultPart::isActivated()
142 {
143   if (myTrsf.get()) {
144     if (!baseRef().get()) // may be on close
145       return false;
146     return baseRef()->isActivated();
147   }
148
149   std::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = data()->document(DOC_REF());
150   return aDocRef->value().get() != NULL;
151 }
152
153 bool Model_ResultPart::setDisabled(std::shared_ptr<ModelAPI_Result> theThis,
154     const bool theFlag)
155 {
156   if (ModelAPI_ResultPart::setDisabled(theThis, theFlag)) {
157     if (!myTrsf.get()) { // disable of base result part
158       DocumentPtr aDoc = Model_ResultPart::partDoc();
159       if (aDoc.get() && aDoc->isOpened()) {
160         // make the current feature the last in any case: to update shapes before deactivation too
161         int aSize = aDoc->size(ModelAPI_Feature::group());
162         FeaturePtr aLastFeature;
163         if (aSize)
164           aLastFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aDoc->object(
165             ModelAPI_Feature::group(), aSize - 1));
166
167         aDoc->setCurrentFeature(aLastFeature, false);
168         if (theFlag) { // disable, so make all features disabled too
169           // update the shape just before the deactivation: it will be used outside of part
170           updateShape();
171           shape();
172           aDoc->setCurrentFeature(FeaturePtr(), false);
173           // in order to update OB sub-elements of document before the document closing
174           Events_Loop* aLoop = Events_Loop::loop();
175           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
176           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
177           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
178         }
179       }
180     }
181     return true;
182   }
183   return false;
184 }
185
186 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shape()
187 {
188   std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
189   if (myShape.IsNull()) { // shape is not produced yet, create it
190     SessionPtr aMgr = ModelAPI_Session::get();
191     bool aToSendUpdate = aMgr->isOperation(); // inside of operation may send an update event
192     if (myTrsf.get()) { // get shape of the base result and apply the transformation
193       ResultPtr anOrigResult = baseRef();
194       std::shared_ptr<GeomAPI_Shape> anOrigShape = anOrigResult->shape();
195       if (anOrigShape.get()) {
196         TopoDS_Shape aShape = anOrigShape->impl<TopoDS_Shape>();
197         if (!aShape.IsNull()) {
198           aShape.Move(*(myTrsf.get()));
199           myShape = aShape;
200           aResult->setImpl(new TopoDS_Shape(aShape));
201         }
202       }
203       if (!myShape.IsNull() && aToSendUpdate) {
204         static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
205         ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
206       }
207       return aResult;
208     } else {
209       DocumentPtr aDoc = Model_ResultPart::partDoc();
210       if (aDoc.get() && aDoc->isOpened()) {
211         const std::string& aBodyGroup = ModelAPI_ResultBody::group();
212         TopoDS_Compound aResultComp;
213         BRep_Builder aBuilder;
214         aBuilder.MakeCompound(aResultComp);
215         int aNumSubs = 0;
216         for(int a = aDoc->size(aBodyGroup) - 1; a >= 0; a--) {
217           ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(aDoc->object(aBodyGroup, a));
218           // "object" method filters out disabled and concealed anyway, so don't check
219           if (aBody.get() && aBody->data()->isValid() && aBody->shape().get()) {
220             TopoDS_Shape aShape = *(aBody->shape()->implPtr<TopoDS_Shape>());
221             if (!aShape.IsNull()) {
222               aBuilder.Add(aResultComp, aShape);
223               aNumSubs++;
224             }
225           }
226         }
227         if (aNumSubs) {
228           myShape = aResultComp;
229         }
230       }
231     }
232     if (!myShape.IsNull() && aToSendUpdate) {
233       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
234       ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
235     }
236   }
237   if (!myShape.IsNull()) {
238     aResult->setImpl(new TopoDS_Shape(myShape));
239   }
240   return aResult;
241 }
242
243 // Returns true is transformation matrices are equal
244 static bool IsEqualTrsf(gp_Trsf& theT1, gp_Trsf theT2) {
245   for(int aRow = 1; aRow < 4; aRow++) {
246     for(int aCol = 1; aCol < 5; aCol++) {
247       double aDiff = theT1.Value(aRow, aCol) - theT2.Value(aRow, aCol);
248       if (Abs(aDiff) > 1.e-9)
249         return false;
250     }
251   }
252   return true;
253 }
254
255 std::string Model_ResultPart::nameInPart(const std::shared_ptr<GeomAPI_Shape>& theShape,
256   int& theIndex)
257 {
258   theIndex = 0; // not initialized
259
260   if (myTrsf.get()) { // if this is moved copy of part => return the name of original shape
261     ResultPartPtr anOrigResult = baseRef();
262     // searching in the origin the shape equal to the given but with myTrsf
263     TopoDS_Shape aSelection = theShape->impl<TopoDS_Shape>();
264     gp_Trsf aSelTrsf = aSelection.Location().Transformation();
265     TopoDS_Shape anOrigMain = anOrigResult->shape()->impl<TopoDS_Shape>();
266     if (!aSelection.IsNull() && !anOrigMain.IsNull()) {
267       TopExp_Explorer anExp(anOrigMain, aSelection.ShapeType());
268       for(; anExp.More(); anExp.Next()) {
269         if (anExp.Current().IsPartner(aSelection)) {
270           TopoDS_Shape anOrigMoved = anExp.Current().Moved(*(myTrsf.get()));
271           //if (anOrigMoved.IsSame(aSelection)) {
272           if (IsEqualTrsf(aSelTrsf, anOrigMoved.Location().Transformation())) {
273             std::shared_ptr<GeomAPI_Shape> anOrigSel(new GeomAPI_Shape);
274             anOrigSel->setImpl(new TopoDS_Shape(anExp.Current()));
275             return anOrigResult->nameInPart(anOrigSel, theIndex);
276           }
277         }
278       }
279     }
280     // something is not right
281     return "";
282   }
283
284   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
285   if (aShape.IsNull())
286     return "";
287
288   // getting an access to the document of part
289   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
290   if (!aDoc.get()) // the part document is not presented for the moment
291     return "";
292   TDF_Label anAccessLabel = aDoc->generalLabel();
293   // make the selection attribute anyway:
294   // otherwise just by name it is not stable to search the result
295   std::string aName;
296   // for this the context result is needed
297   ResultPtr aContext;
298   const std::string& aBodyGroup = ModelAPI_ResultBody::group();
299   for(int a = aDoc->size(aBodyGroup) - 1; a >= 0; a--) {
300     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(aDoc->object(aBodyGroup, a));
301     if (aBody.get() && aBody->shape().get() && !aBody->isDisabled()) {
302       TopoDS_Shape aBodyShape = *(aBody->shape()->implPtr<TopoDS_Shape>());
303       // check is body contain the selected sub-shape
304       for(TopExp_Explorer anExp(aBodyShape, aShape.ShapeType()); anExp.More(); anExp.Next()) {
305         if (aShape.IsSame(anExp.Current())) {
306           aContext = aBody;
307           break;
308         }
309       }
310     }
311   }
312   if (aContext.get()) {
313     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
314     aSelAttr->append(aContext, theShape);
315     theIndex = aSelAttr->size();
316     AttributeSelectionPtr aNewAttr = aSelAttr->value(theIndex - 1);
317     return aNewAttr->namingName();
318   }
319   return aName;
320 }
321
322 bool Model_ResultPart::updateInPart(const int theIndex)
323 {
324   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
325   if (aDoc.get()) {
326     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
327     AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
328     if (aThisAttr.get()) {
329       return aThisAttr->update();
330     }
331   }
332   return false; // something is wrong
333 }
334
335 gp_Trsf Model_ResultPart::sumTrsf() {
336   gp_Trsf aResult;
337   if (myTrsf) {
338     aResult = *myTrsf;
339     aResult = aResult * baseRef()->sumTrsf();
340   }
341   return aResult;
342 }
343
344 bool Model_ResultPart::combineGeometrical(const int theIndex, std::string& theNewName)
345 {
346   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
347   if (aDoc.get()) {
348     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
349     AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
350     if (aThisAttr.get()) {
351       aThisAttr->combineGeometrical();
352       if (aThisAttr->value().get()) {
353         int anIndex;
354         theNewName = nameInPart(aThisAttr->value(), anIndex);
355         return true;
356       }
357     }
358   }
359   return false; // something is wrong
360 }
361
362 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shapeInPart(
363   const std::string& theName, const std::string& theType, int& theIndex)
364 {
365   theIndex = 0; // not found yet
366   std::shared_ptr<GeomAPI_Shape> aResult;
367   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
368   if (!aDoc.get()) // the part document is not presented for the moment
369     return aResult;
370
371   AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
372   // check this selection is already there: reuse it
373   int aSize = aSelAttr->size();
374   for(int a = 0; a < aSize; a++) {
375     if (aSelAttr->value(a)->namingName() == theName) {
376       theIndex = a;
377       return aSelAttr->value(a)->value();
378     }
379   }
380
381   aSelAttr->append(theName, theType);
382   theIndex = aSelAttr->size();
383   aResult = aSelAttr->value(theIndex - 1)->value();
384   if (myTrsf.get() && aResult.get() && !aResult->isNull()) {
385     gp_Trsf aSumTrsf = sumTrsf();
386     TopoDS_Shape anOrigMoved = aResult->impl<TopoDS_Shape>().Moved(aSumTrsf);
387     aResult->setImpl(new TopoDS_Shape(anOrigMoved));
388   }
389   return aResult;
390 }
391
392 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::selectionValue(const int theIndex)
393 {
394   std::shared_ptr<GeomAPI_Shape> aResult;
395   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
396   if (!aDoc.get()) // the part document is not presented for the moment
397     return aResult;
398
399   AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
400   aResult = aSelAttr->value(theIndex - 1)->value();
401   if (myTrsf.get() && aResult.get() && !aResult->isNull()) {
402     gp_Trsf aSumTrsf = sumTrsf();
403     TopoDS_Shape anOrigMoved = aResult->impl<TopoDS_Shape>().Moved(aSumTrsf);
404     aResult->setImpl(new TopoDS_Shape(anOrigMoved));
405   }
406   return aResult;
407 }
408
409 void Model_ResultPart::colorConfigInfo(std::string& theSection, std::string& theName,
410   std::string& theDefault)
411 {
412   theSection = "Visualization";
413   theName = "result_part_color";
414   theDefault = DEFAULT_COLOR();
415 }
416
417 void Model_ResultPart::updateShape()
418 {
419   myShape.Nullify();
420   myTrsf.reset();
421 }
422
423 void Model_ResultPart::setTrsf(std::shared_ptr<ModelAPI_Result> theThis,
424     const std::shared_ptr<GeomAPI_Trsf>& theTransformation)
425 {
426   updateShape();
427   if (theTransformation.get()) {
428     myTrsf = std::shared_ptr<gp_Trsf>(new gp_Trsf(theTransformation->impl<gp_Trsf>()));
429   }
430   // the result must be explicitly updated
431   static Events_Loop* aLoop = Events_Loop::loop();
432   static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
433   ModelAPI_EventCreator::get()->sendUpdated(theThis, EVENT_DISP); // flush is in preview-update
434 }
435
436 std::shared_ptr<GeomAPI_Trsf> Model_ResultPart::summaryTrsf()
437 {
438   GeomTrsfPtr aResult(new GeomAPI_Trsf);
439   aResult->setImpl<gp_Trsf>(new gp_Trsf(sumTrsf()));
440   return aResult;
441 }