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