]> SALOME platform Git repositories - modules/shaper.git/blob - src/Model/Model_AttributeSelection.cpp
Salome HOME
Implementation of naming parametrisation of sketch result
[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 (myRef.myRef->Label().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->groupName() == ModelAPI_ResultBody::group()) {
89     // body: just a named shape, use selection mechanism from OCCT
90     TNaming_Selector aSelector(myRef.myRef->Label());
91     TDF_LabelMap aScope; // empty means the whole document
92     return aSelector.Solve(aScope) == Standard_True;
93    
94   } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
95     // construction: identification by the results indexes, recompute faces and
96     // take the face that more close by the indexes
97     boost::shared_ptr<GeomAPI_Wire> aWirePtr = boost::dynamic_pointer_cast<GeomAPI_Wire>(
98       boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
99     if (aWirePtr && aWirePtr->hasPlane()) {
100         // If this is a wire with plane defined thin it is a sketch-like object
101       std::list<boost::shared_ptr<GeomAPI_Shape> > aFaces;
102       GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
103         aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
104       if (aFaces.empty()) // no faces, update can not work correctly
105         return false;
106       // if there is no edges indexes, any face can be used: take the first
107       boost::shared_ptr<Model_Data> aData = 
108         boost::dynamic_pointer_cast<Model_Data>(owner()->data());
109       TDF_Label aLab = aData->label();
110       Handle(TDataStd_IntPackedMap) aSubIds;
111       boost::shared_ptr<GeomAPI_Shape> aNewSelected;
112       if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) {
113         aNewSelected = *(aFaces.begin());
114       } else { // searching for most looks-like initial face by the indexes
115         // prepare edges of the current resut for the fast searching
116         TColStd_MapOfTransient allCurves;
117         FeaturePtr aContextFeature = owner()->document()->feature(aContext);
118         CompositeFeaturePtr aComposite = 
119           boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
120         if (!aComposite) // must be composite at least for the current implementation
121           return false;
122         const int aSubNum = aComposite->numberOfSubs();
123         for(int a = 0; a < aSubNum; a++) {
124           if (aSubIds->Contains(aComposite->subFeatureId(a))) {
125             FeaturePtr aSub = aComposite->subFeature(a);
126             const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
127             std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
128             for(; aRes != aResults.cend(); aRes++) {
129               ResultConstructionPtr aConstr = 
130                 boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
131               if (aConstr->shape()) {
132                 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
133                 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
134                 if (!anEdge.IsNull()) {
135                   Standard_Real aFirst, aLast;
136                   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
137                   allCurves.Add(aCurve);
138                 }
139               }
140             }
141           }
142         }
143         // iterate new result faces and searching for these edges
144         std::list<boost::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
145         double aBestFound = 0; // best percentage of found edges
146         for(; aFacesIter != aFaces.end(); aFacesIter++) {
147           int aFound = 0, aNotFound = 0;
148           TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
149           for(; anEdgesExp.More(); anEdgesExp.Next()) {
150             TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
151             if (!anEdge.IsNull()) {
152               Standard_Real aFirst, aLast;
153               Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
154               if (allCurves.Contains(aCurve)) {
155                 aFound++;
156               } else {
157                 aNotFound++;
158               }
159             }
160           }
161           if (aFound + aNotFound != 0) {
162             double aPercentage = double(aFound) / double(aFound + aNotFound);
163             if (aPercentage > aBestFound) {
164               aBestFound = aPercentage;
165               aNewSelected = *aFacesIter;
166             }
167           }
168         }
169         if (aNewSelected) { // store this new selection
170           selectConstruction(aContext, aNewSelected);
171           return true;
172         }
173       }
174     }
175   }
176   return false; // unknown case
177 }
178
179
180 void Model_AttributeSelection::selectBody(
181     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
182 {
183   // perform the selection
184   TNaming_Selector aSel(myRef.myRef->Label());
185   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
186   TopoDS_Shape aContext;
187
188   ResultBodyPtr aBody = boost::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
189   if (aBody)
190     aContext = aBody->shape()->impl<TopoDS_Shape>();
191   else {
192     ResultConstructionPtr aConstr = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
193     if (aConstr)
194       aContext = aConstr->shape()->impl<TopoDS_Shape>();
195     else
196       throw std::invalid_argument("a result with shape is expected");
197   }
198   Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aNewShape, myRef.myRef->Label());
199   TDF_Label aLab = aNS->Label();
200
201   aSel.Select(aNewShape, aContext);
202 }
203
204 void Model_AttributeSelection::selectConstruction(
205     const ResultPtr& theContext, const boost::shared_ptr<GeomAPI_Shape>& theSubShape)
206 {
207   FeaturePtr aContextFeature = owner()->document()->feature(theContext);
208   CompositeFeaturePtr aComposite = 
209     boost::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
210   if (!aComposite || aComposite->numberOfSubs() == 0) {
211     return; // saving of context is enough: result construction contains exactly the needed shape
212   }
213   boost::shared_ptr<Model_Data> aData = boost::dynamic_pointer_cast<Model_Data>(owner()->data());
214   TDF_Label aLab = aData->label();
215   // identify the reuslts of sub-object of the composite by edges
216   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
217   TColStd_MapOfTransient allCurves;
218   for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
219     TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
220     Standard_Real aFirst, aLast;
221     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
222     allCurves.Add(aCurve);
223   }
224   // iterate and store the result ids of sub-elements
225   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
226   const int aSubNum = aComposite->numberOfSubs();
227   for(int a = 0; a < aSubNum; a++) {
228     FeaturePtr aSub = aComposite->subFeature(a);
229     const std::list<boost::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
230     std::list<boost::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
231     // there may be many shapes (circle and center): register if at least one is in selection
232     for(; aRes != aResults.cend(); aRes++) {
233       ResultConstructionPtr aConstr = 
234         boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
235       if (aConstr->shape()) {
236         const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
237         TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
238         if (!anEdge.IsNull()) {
239           Standard_Real aFirst, aLast;
240           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
241           if (allCurves.Contains(aCurve)) {
242             boost::shared_ptr<Model_Data> aSubData = boost::dynamic_pointer_cast<Model_Data>(aSub->data());
243             TDF_Label aSubLab = aSubData->label();
244             aRefs->Add(aComposite->subFeatureId(a));
245           }
246         }
247       }
248     }
249   }
250   // store the selected as primitive
251   TNaming_Builder aBuilder(myRef.myRef->Label());
252   aBuilder.Generated(aSubShape);
253 }