]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_AttributeSelection.cpp
Salome HOME
Debug of selection and delete of feature
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
1 // File:        Model_AttributeSelection.h
2 // Created:     2 Oct 2014
3 // Author:      Mikhail PONIKAROV
4
5 #include "Model_AttributeSelection.h"
6 #include "Model_Application.h"
7 #include "Model_Events.h"
8 #include "Model_Data.h"
9 #include <ModelAPI_Feature.h>
10 #include <ModelAPI_ResultBody.h>
11 #include <ModelAPI_ResultConstruction.h>
12 #include <ModelAPI_CompositeFeature.h>
13 #include <GeomAPI_Shape.h>
14 #include <GeomAPI_Wire.h>
15 #include <GeomAlgoAPI_SketchBuilder.h>
16
17 #include <TNaming_Selector.hxx>
18 #include <TNaming_NamedShape.hxx>
19 #include <TNaming_Tool.hxx>
20 #include <TNaming_Builder.hxx>
21 #include <TopoDS_Shape.hxx>
22 #include <TDataStd_IntPackedMap.hxx>
23 #include <TopTools_MapOfShape.hxx>
24 #include <TopExp_Explorer.hxx>
25 #include <TDF_LabelMap.hxx>
26 #include <BRep_Tool.hxx>
27 #include <TopoDS_Edge.hxx>
28 #include <TopoDS.hxx>
29 #include <TColStd_MapOfTransient.hxx>
30
31 using namespace std;
32
33 void Model_AttributeSelection::setValue(const ResultPtr& theContext,
34   const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
35 {
36   const boost::shared_ptr<GeomAPI_Shape>& anOldShape = value();
37   bool isOldShape = 
38     (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
39   if (isOldShape) return; // shape is the same, so context is also unchanged
40   // update the referenced object if needed
41   bool isOldContext = theContext == myRef.value();
42   if (!isOldContext)
43     myRef.setValue(theContext);
44
45   if (theContext->groupName() == ModelAPI_ResultBody::group())
46     selectBody(theContext, theSubShape);
47   else if (theContext->groupName() == ModelAPI_ResultConstruction::group())
48     selectConstruction(theContext, theSubShape);
49
50   myIsInitialized = true;
51   owner()->data()->sendAttributeUpdated(this);
52 }
53
54 boost::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
55 {
56   boost::shared_ptr<GeomAPI_Shape> aResult;
57   if (myIsInitialized) {
58     Handle(TNaming_NamedShape) aSelection;
59     if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
60       TopoDS_Shape aSelShape = aSelection->Get();
61       aResult = boost::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
62       aResult->setImpl(new TopoDS_Shape(aSelShape));
63     }
64   }
65   return aResult;
66 }
67
68 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
69   : myRef(theLabel)
70 {
71   myIsInitialized = myRef.isInitialized();
72 }
73
74 ResultPtr Model_AttributeSelection::context() {
75   return boost::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
76 }
77
78
79 void Model_AttributeSelection::setObject(const boost::shared_ptr<ModelAPI_Object>& theObject)
80 {
81   ModelAPI_AttributeSelection::setObject(theObject);
82   myRef.setObject(theObject);
83 }
84
85 bool Model_AttributeSelection::update()
86 {
87   ResultPtr aContext = context();
88   if (!aContext) return false;
89   if (aContext->groupName() == ModelAPI_ResultBody::group()) {
90     // body: just a named shape, use selection mechanism from OCCT
91     TNaming_Selector aSelector(selectionLabel());
92     TDF_LabelMap aScope; // empty means the whole document
93     return aSelector.Solve(aScope) == Standard_True;
94    
95   } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
96     // construction: identification by the results indexes, recompute faces and
97     // take the face that more close by the indexes
98     boost::shared_ptr<GeomAPI_Wire> aWirePtr = boost::dynamic_pointer_cast<GeomAPI_Wire>(
99       boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
100     if (aWirePtr && aWirePtr->hasPlane()) {
101         // If this is a wire with plane defined thin it is a sketch-like object
102       std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
103       GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
104         aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
105       if (aFaces.empty()) // no faces, update can not work correctly
106         return false;
107       // if there is no edges indexes, any face can be used: take the first
108       boost::shared_ptr<Model_Data> aData = 
109         boost::dynamic_pointer_cast<Model_Data>(owner()->data());
110       TDF_Label aLab = aData->label();
111       Handle(TDataStd_IntPackedMap) aSubIds;
112       boost::shared_ptr<GeomAPI_Shape> aNewSelected;
113       if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) {
114         aNewSelected = *(aFaces.begin());
115       } else { // searching for most looks-like initial face by the indexes
116         // prepare edges of the current resut for the fast searching
117         TColStd_MapOfTransient allCurves;
118         FeaturePtr aContextFeature = owner()->document()->feature(aContext);
119         CompositeFeaturePtr aComposite = 
120           boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
121         if (!aComposite) // must be composite at least for the current implementation
122           return false;
123         const int aSubNum = aComposite->numberOfSubs();
124         for(int a = 0; a < aSubNum; a++) {
125           if (aSubIds->Contains(aComposite->subFeatureId(a))) {
126             FeaturePtr aSub = aComposite->subFeature(a);
127             const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
128             std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
129             for(; aRes != aResults.cend(); aRes++) {
130               ResultConstructionPtr aConstr = 
131                 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
132               if (aConstr->shape() && aConstr->shape()->isEdge()) {
133                 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
134                 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
135                 if (!anEdge.IsNull()) {
136                   Standard_Real aFirst, aLast;
137                   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
138                   allCurves.Add(aCurve);
139                 }
140               }
141             }
142           }
143         }
144         // iterate new result faces and searching for these edges
145         std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
146         double aBestFound = 0; // best percentage of found edges
147         for(; aFacesIter != aFaces.end(); aFacesIter++) {
148           int aFound = 0, aNotFound = 0;
149           TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
150           for(; anEdgesExp.More(); anEdgesExp.Next()) {
151             TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
152             if (!anEdge.IsNull()) {
153               Standard_Real aFirst, aLast;
154               Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
155               if (allCurves.Contains(aCurve)) {
156                 aFound++;
157               } else {
158                 aNotFound++;
159               }
160             }
161           }
162           if (aFound + aNotFound != 0) {
163             double aPercentage = double(aFound) / double(aFound + aNotFound);
164             if (aPercentage > aBestFound) {
165               aBestFound = aPercentage;
166               aNewSelected = *aFacesIter;
167             }
168           }
169         }
170         if (aNewSelected) { // store this new selection
171           selectConstruction(aContext, aNewSelected);
172           return true;
173         }
174       }
175     }
176   }
177   return false; // unknown case
178 }
179
180
181 void Model_AttributeSelection::selectBody(
182     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
183 {
184   // perform the selection
185   TNaming_Selector aSel(selectionLabel());
186   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
187   TopoDS_Shape aContext;
188
189   ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
190   if (aBody)
191     aContext = aBody->shape()->impl<TopoDS_Shape>();
192   else {
193     ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
194     if (aConstr)
195       aContext = aConstr->shape()->impl<TopoDS_Shape>();
196     else
197       throw std::invalid_argument("a result with shape is expected");
198   }
199   aSel.Select(aNewShape, aContext);
200 }
201
202 void Model_AttributeSelection::selectConstruction(
203     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
204 {
205   FeaturePtr aContextFeature = owner()->document()->feature(theContext);
206   CompositeFeaturePtr aComposite = 
207     boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
208   if (!aComposite || aComposite->numberOfSubs() == 0) {
209     return; // saving of context is enough: result construction contains exactly the needed shape
210   }
211   boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
212   TDF_Label aLab = aData->label();
213   // identify the reuslts of sub-object of the composite by edges
214   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
215   TColStd_MapOfTransient allCurves;
216   for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
217     TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
218     Standard_Real aFirst, aLast;
219     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
220     allCurves.Add(aCurve);
221   }
222   // iterate and store the result ids of sub-elements
223   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
224   const int aSubNum = aComposite->numberOfSubs();
225   for(int a = 0; a < aSubNum; a++) {
226     FeaturePtr aSub = aComposite->subFeature(a);
227     const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
228     std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
229     // there may be many shapes (circle and center): register if at least one is in selection
230     for(; aRes != aResults.cend(); aRes++) {
231       ResultConstructionPtr aConstr = 
232         boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
233       if (aConstr->shape() && aConstr->shape()->isEdge()) {
234         const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
235         TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
236         if (!anEdge.IsNull()) {
237           Standard_Real aFirst, aLast;
238           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
239           if (allCurves.Contains(aCurve)) {
240             boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
241             TDF_Label aSubLab = aSubData->label();
242             aRefs->Add(aComposite->subFeatureId(a));
243           }
244         }
245       }
246     }
247   }
248   // store the selected as primitive
249   TNaming_Builder aBuilder(selectionLabel());
250   aBuilder.Generated(aSubShape);
251 }
252
253 TDF_Label Model_AttributeSelection::selectionLabel()
254 {
255   return myRef.myRef->Label().FindChild(1);
256 }