]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_AttributeSelection.cpp
Salome HOME
Merge branch 'master' of newgeom:newgeom
[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     return aSelector.Solve(aScope) == Standard_True;
95    
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         if (aNewSelected) { // store this new selection
172           selectConstruction(aContext, aNewSelected);
173           return true;
174         }
175       }
176     }
177   }
178   return false; // unknown case
179 }
180
181
182 void Model_AttributeSelection::selectBody(
183     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
184 {
185   // perform the selection
186   TNaming_Selector aSel(selectionLabel());
187   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
188   TopoDS_Shape aContext;
189
190   ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
191   if (aBody)
192     aContext = aBody->shape()->impl<TopoDS_Shape>();
193   else {
194     ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
195     if (aConstr) {
196       aContext = aConstr->shape()->impl<TopoDS_Shape>();
197     } else {
198       Events_Error::send("A result with shape is expected");
199       return;
200     }
201   }
202   aSel.Select(aNewShape, aContext);
203 }
204
205 void Model_AttributeSelection::selectConstruction(
206     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
207 {
208   FeaturePtr aContextFeature = owner()->document()->feature(theContext);
209   CompositeFeaturePtr aComposite = 
210     boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
211   if (!aComposite || aComposite->numberOfSubs() == 0) {
212     return; // saving of context is enough: result construction contains exactly the needed shape
213   }
214   boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
215   TDF_Label aLab = aData->label();
216   // identify the reuslts of sub-object of the composite by edges
217   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
218   TColStd_MapOfTransient allCurves;
219   for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
220     TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
221     Standard_Real aFirst, aLast;
222     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
223     allCurves.Add(aCurve);
224   }
225   // iterate and store the result ids of sub-elements
226   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
227   const int aSubNum = aComposite->numberOfSubs();
228   for(int a = 0; a < aSubNum; a++) {
229     FeaturePtr aSub = aComposite->subFeature(a);
230     const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
231     std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
232     // there may be many shapes (circle and center): register if at least one is in selection
233     for(; aRes != aResults.cend(); aRes++) {
234       ResultConstructionPtr aConstr = 
235         boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
236       if (aConstr->shape() && aConstr->shape()->isEdge()) {
237         const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
238         TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
239         if (!anEdge.IsNull()) {
240           Standard_Real aFirst, aLast;
241           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
242           if (allCurves.Contains(aCurve)) {
243             boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
244             TDF_Label aSubLab = aSubData->label();
245             aRefs->Add(aComposite->subFeatureId(a));
246           }
247         }
248       }
249     }
250   }
251   // store the selected as primitive
252   TNaming_Builder aBuilder(selectionLabel());
253   aBuilder.Generated(aSubShape);
254 }
255
256 TDF_Label Model_AttributeSelection::selectionLabel()
257 {
258   return myRef.myRef->Label().FindChild(1);
259 }