Salome HOME
Update copyrights
[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     aMgr->startOperation("Activation");
93     isNewTransaction = true;
94   }
95   if (!aDocRef->value().get()) {  // create (or open) a document if it is not yet created
96     Handle(Model_Application) anApp = Model_Application::getApplication();
97     if (anApp->isLoadByDemand(data()->name(), aDocRef->docId())) {
98       anApp->loadDocument(data()->name(), aDocRef->docId()); // if it is just new part, load fails
99     } else {
100       anApp->createDocument(aDocRef->docId());
101     }
102     std::shared_ptr<ModelAPI_Document> aDoc = aDocRef->value();
103     if (aDoc.get()) {
104       aDoc->synchronizeTransactions();
105       aDocRef->setValue(aDoc);
106     }
107   }
108   if (aDocRef->value().get()) {
109     ModelAPI_Session::get()->setActiveDocument(aDocRef->value());
110   }
111   if (isNewTransaction) {
112     aMgr->finishOperation();
113   }
114 }
115
116 std::shared_ptr<ModelAPI_ResultPart> Model_ResultPart::original()
117 {
118   if (myTrsf.get() && baseRef().get()) {  // the second condition is due to #2035
119     return baseRef()->original();
120   }
121   return std::dynamic_pointer_cast<ModelAPI_ResultPart>(data()->owner());
122 }
123
124 bool Model_ResultPart::isActivated()
125 {
126   if (myTrsf.get()) {
127     if (!baseRef().get()) // may be on close
128       return false;
129     return baseRef()->isActivated();
130   }
131
132   std::shared_ptr<ModelAPI_AttributeDocRef> aDocRef = data()->document(DOC_REF());
133   return aDocRef->value().get() != NULL;
134 }
135
136 bool Model_ResultPart::setDisabled(std::shared_ptr<ModelAPI_Result> theThis,
137     const bool theFlag)
138 {
139   if (ModelAPI_ResultPart::setDisabled(theThis, theFlag)) {
140     if (!myTrsf.get()) { // disable of base result part
141       DocumentPtr aDoc = Model_ResultPart::partDoc();
142       if (aDoc.get() && aDoc->isOpened()) {
143         // make the current feature the last in any case: to update shapes before deactivation too
144         int aSize = aDoc->size(ModelAPI_Feature::group());
145         FeaturePtr aLastFeature;
146         if (aSize)
147           aLastFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aDoc->object(
148             ModelAPI_Feature::group(), aSize - 1));
149
150         aDoc->setCurrentFeature(aLastFeature, false);
151         if (theFlag) { // disable, so make all features disabled too
152           // update the shape just before the deactivation: it will be used outside of part
153           updateShape();
154           shape();
155           aDoc->setCurrentFeature(FeaturePtr(), false);
156           // in order to update OB sub-elements of document before the document closing
157           Events_Loop* aLoop = Events_Loop::loop();
158           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
159           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
160           aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
161         }
162       }
163     }
164     return true;
165   }
166   return false;
167 }
168
169 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shape()
170 {
171   std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
172   if (myShape.IsNull()) { // shape is not produced yet, create it
173     SessionPtr aMgr = ModelAPI_Session::get();
174     bool aToSendUpdate = aMgr->isOperation(); // inside of operation may send an update event
175     if (myTrsf.get()) { // get shape of the base result and apply the transformation
176       ResultPtr anOrigResult = baseRef();
177       std::shared_ptr<GeomAPI_Shape> anOrigShape = anOrigResult->shape();
178       if (anOrigShape.get()) {
179         TopoDS_Shape aShape = anOrigShape->impl<TopoDS_Shape>();
180         if (!aShape.IsNull()) {
181           aShape.Move(*(myTrsf.get()));
182           myShape = aShape;
183           aResult->setImpl(new TopoDS_Shape(aShape));
184         }
185       }
186       if (!myShape.IsNull() && aToSendUpdate) {
187         static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
188         ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
189       }
190       return aResult;
191     } else {
192       DocumentPtr aDoc = Model_ResultPart::partDoc();
193       if (aDoc.get() && aDoc->isOpened()) {
194         const std::string& aBodyGroup = ModelAPI_ResultBody::group();
195         TopoDS_Compound aResultComp;
196         BRep_Builder aBuilder;
197         aBuilder.MakeCompound(aResultComp);
198         int aNumSubs = 0;
199         for(int a = aDoc->size(aBodyGroup) - 1; a >= 0; a--) {
200           ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(aDoc->object(aBodyGroup, a));
201           // "object" method filters out disabled and concealed anyway, so don't check
202           if (aBody.get() && aBody->data()->isValid() && aBody->shape().get()) {
203             TopoDS_Shape aShape = *(aBody->shape()->implPtr<TopoDS_Shape>());
204             if (!aShape.IsNull()) {
205               aBuilder.Add(aResultComp, aShape);
206               aNumSubs++;
207             }
208           }
209         }
210         if (aNumSubs) {
211           myShape = aResultComp;
212         }
213       }
214     }
215     if (!myShape.IsNull() && aToSendUpdate) {
216       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
217       ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
218     }
219   }
220   if (!myShape.IsNull()) {
221     aResult->setImpl(new TopoDS_Shape(myShape));
222   }
223   return aResult;
224 }
225
226 // Returns true is transformation matrices are equal
227 static bool IsEqualTrsf(gp_Trsf& theT1, gp_Trsf theT2) {
228   for(int aRow = 1; aRow < 4; aRow++) {
229     for(int aCol = 1; aCol < 5; aCol++) {
230       double aDiff = theT1.Value(aRow, aCol) - theT2.Value(aRow, aCol);
231       if (Abs(aDiff) > 1.e-9)
232         return false;
233     }
234   }
235   return true;
236 }
237
238 std::string Model_ResultPart::nameInPart(const std::shared_ptr<GeomAPI_Shape>& theShape,
239   int& theIndex)
240 {
241   theIndex = 0; // not initialized
242
243   if (myTrsf.get()) { // if this is moved copy of part => return the name of original shape
244     ResultPartPtr anOrigResult = baseRef();
245     // searching in the origin the shape equal to the given but with myTrsf
246     TopoDS_Shape aSelection = theShape->impl<TopoDS_Shape>();
247     gp_Trsf aSelTrsf = aSelection.Location().Transformation();
248     TopoDS_Shape anOrigMain = anOrigResult->shape()->impl<TopoDS_Shape>();
249     if (!aSelection.IsNull() && !anOrigMain.IsNull()) {
250       TopExp_Explorer anExp(anOrigMain, aSelection.ShapeType());
251       for(; anExp.More(); anExp.Next()) {
252         if (anExp.Current().IsPartner(aSelection)) {
253           TopoDS_Shape anOrigMoved = anExp.Current().Moved(*(myTrsf.get()));
254           //if (anOrigMoved.IsSame(aSelection)) {
255           if (IsEqualTrsf(aSelTrsf, anOrigMoved.Location().Transformation())) {
256             std::shared_ptr<GeomAPI_Shape> anOrigSel(new GeomAPI_Shape);
257             anOrigSel->setImpl(new TopoDS_Shape(anExp.Current()));
258             return anOrigResult->nameInPart(anOrigSel, theIndex);
259           }
260         }
261       }
262     }
263     // something is not right
264     return "";
265   }
266
267   TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
268   if (aShape.IsNull())
269     return "";
270
271   // getting an access to the document of part
272   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
273   if (!aDoc.get()) // the part document is not presented for the moment
274     return "";
275   TDF_Label anAccessLabel = aDoc->generalLabel();
276   // make the selection attribute anyway:
277   // otherwise just by name it is not stable to search the result
278   std::string aName;
279   // for this the context result is needed
280   ResultPtr aContext;
281   const std::string& aBodyGroup = ModelAPI_ResultBody::group();
282   for(int a = aDoc->size(aBodyGroup) - 1; a >= 0; a--) {
283     ResultPtr aBody = std::dynamic_pointer_cast<ModelAPI_Result>(aDoc->object(aBodyGroup, a));
284     if (aBody.get() && aBody->shape().get() && !aBody->isDisabled()) {
285       TopoDS_Shape aBodyShape = *(aBody->shape()->implPtr<TopoDS_Shape>());
286       // check is body contain the selected sub-shape
287       for(TopExp_Explorer anExp(aBodyShape, aShape.ShapeType()); anExp.More(); anExp.Next()) {
288         if (aShape.IsEqual(anExp.Current())) {
289           aContext = aBody;
290           break;
291         }
292       }
293     }
294   }
295   if (aContext.get()) {
296     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
297     aSelAttr->append(aContext, theShape);
298     theIndex = aSelAttr->size();
299     AttributeSelectionPtr aNewAttr = aSelAttr->value(theIndex - 1);
300     return aNewAttr->namingName();
301   }
302   return aName;
303 }
304
305 bool Model_ResultPart::updateInPart(const int theIndex)
306 {
307   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
308   if (aDoc.get()) {
309     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
310     AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
311     if (aThisAttr.get()) {
312       return aThisAttr->update();
313     }
314   }
315   return false; // something is wrong
316 }
317
318 gp_Trsf Model_ResultPart::sumTrsf() {
319   gp_Trsf aResult;
320   if (myTrsf) {
321     aResult = *myTrsf;
322     aResult = aResult * baseRef()->sumTrsf();
323   }
324   return aResult;
325 }
326
327 bool Model_ResultPart::combineGeometrical(const int theIndex, std::string& theNewName)
328 {
329   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
330   if (aDoc.get()) {
331     AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
332     AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
333     if (aThisAttr.get()) {
334       aThisAttr->combineGeometrical();
335       if (aThisAttr->value().get()) {
336         int anIndex;
337         theNewName = nameInPart(aThisAttr->value(), anIndex);
338         return true;
339       }
340     }
341   }
342   return false; // something is wrong
343 }
344
345 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shapeInPart(
346   const std::string& theName, const std::string& theType, int& theIndex)
347 {
348   theIndex = 0; // not found yet
349   std::shared_ptr<GeomAPI_Shape> aResult;
350   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
351   if (!aDoc.get()) // the part document is not presented for the moment
352     return aResult;
353
354   AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
355   // check this selection is already there: reuse it
356   int aSize = aSelAttr->size();
357   for(int a = 0; a < aSize; a++) {
358     if (aSelAttr->value(a)->namingName() == theName) {
359       theIndex = a;
360       return aSelAttr->value(a)->value();
361     }
362   }
363
364   aSelAttr->append(theName, theType);
365   theIndex = aSelAttr->size();
366   aResult = aSelAttr->value(theIndex - 1)->value();
367   if (myTrsf.get() && aResult.get() && !aResult->isNull()) {
368     gp_Trsf aSumTrsf = sumTrsf();
369     TopoDS_Shape anOrigMoved = aResult->impl<TopoDS_Shape>().Moved(aSumTrsf);
370     aResult->setImpl(new TopoDS_Shape(anOrigMoved));
371   }
372   return aResult;
373 }
374
375 std::shared_ptr<GeomAPI_Shape> Model_ResultPart::selectionValue(const int theIndex)
376 {
377   std::shared_ptr<GeomAPI_Shape> aResult;
378   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
379   if (!aDoc.get()) // the part document is not presented for the moment
380     return aResult;
381
382   AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
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 void Model_ResultPart::colorConfigInfo(std::string& theSection, std::string& theName,
393   std::string& theDefault)
394 {
395   theSection = "Visualization";
396   theName = "result_part_color";
397   theDefault = DEFAULT_COLOR();
398 }
399
400 void Model_ResultPart::updateShape()
401 {
402   myShape.Nullify();
403   myTrsf.reset();
404 }
405
406 void Model_ResultPart::setTrsf(std::shared_ptr<ModelAPI_Result> theThis,
407     const std::shared_ptr<GeomAPI_Trsf>& theTransformation)
408 {
409   updateShape();
410   if (theTransformation.get()) {
411     myTrsf = std::shared_ptr<gp_Trsf>(new gp_Trsf(theTransformation->impl<gp_Trsf>()));
412   }
413   // the result must be explicitly updated
414   static Events_Loop* aLoop = Events_Loop::loop();
415   static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY);
416   ModelAPI_EventCreator::get()->sendUpdated(theThis, EVENT_DISP); // flush is in preview-update
417 }