Salome HOME
Issue #335 : generaet the shape for selection construction elements whole results...
[modules/shaper.git] / src / Model / Model_AttributeSelection.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_AttributeSelection.h
4 // Created:     2 Oct 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_AttributeSelection.h"
8 #include "Model_Application.h"
9 #include "Model_Events.h"
10 #include "Model_Data.h"
11 #include <ModelAPI_Feature.h>
12 #include <ModelAPI_ResultBody.h>
13 #include <ModelAPI_ResultConstruction.h>
14 #include <ModelAPI_CompositeFeature.h>
15 #include <GeomAPI_Shape.h>
16 #include <GeomAPI_PlanarEdges.h>
17 #include <GeomAlgoAPI_SketchBuilder.h>
18 #include <Events_Error.h>
19
20 #include <TNaming_Selector.hxx>
21 #include <TNaming_NamedShape.hxx>
22 #include <TNaming_Tool.hxx>
23 #include <TNaming_Builder.hxx>
24 #include <TNaming_Localizer.hxx>
25 #include <TopoDS_Shape.hxx>
26 #include <TopoDS_Compound.hxx>
27 #include <TDataStd_IntPackedMap.hxx>
28 #include <TDataStd_Integer.hxx>
29 #include <TDataStd_UAttribute.hxx>
30 #include <TDataStd_Name.hxx>
31 #include <TopTools_MapOfShape.hxx>
32 #include <TopTools_IndexedMapOfShape.hxx>
33 #include <TopTools_MapIteratorOfMapOfShape.hxx>
34 #include <TopTools_ListOfShape.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TDF_LabelMap.hxx>
37 #include <BRep_Tool.hxx>
38 #include <BRep_Builder.hxx>
39 #include <TopoDS_Edge.hxx>
40 #include <TopoDS.hxx>
41 #include <TopExp.hxx>
42 #include <TColStd_MapOfTransient.hxx>
43 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
44 #include <TopTools_ListIteratorOfListOfShape.hxx>
45 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
46 #include <gp_Pnt.hxx>
47 #include <Precision.hxx>
48 #include <TDF_ChildIterator.hxx>
49 #include <TDF_ChildIDIterator.hxx>
50 #include <TDataStd_Name.hxx>
51 #include <TopAbs_ShapeEnum.hxx>
52 #include <TopoDS_Iterator.hxx>
53 using namespace std;
54 /// adeed to the index in the packed map to signalize that the vertex of edge is seleted
55 /// (multiplied by the index of the edge)
56 static const int kSTART_VERTEX_DELTA = 1000000;
57 // identifier that there is simple reference: selection equals to context
58 Standard_GUID kSIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb29");
59
60 // on this label is stored:
61 // TNaming_NamedShape - selected shape
62 // TNaming_Naming - topological selection information (for the body)
63 // TDataStd_IntPackedMap - indexes of edges in composite element (for construction)
64 // TDataStd_Integer - type of the selected shape (for construction)
65 // TDF_Reference - from ReferenceAttribute, the context
66 #define DDDD 1
67 void Model_AttributeSelection::setValue(const ResultPtr& theContext,
68   const std::shared_ptr<GeomAPI_Shape>& theSubShape)
69 {
70   const std::shared_ptr<GeomAPI_Shape>& anOldShape = value();
71   bool isOldShape = 
72     (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape)));
73   if (isOldShape) return; // shape is the same, so context is also unchanged
74   // update the referenced object if needed
75   bool isOldContext = theContext == myRef.value();
76
77
78   if (!isOldContext)
79     myRef.setValue(theContext);
80
81   // do noth use naming if selected shape is result shape itself, but not sub-shape
82   TDF_Label aSelLab = selectionLabel();
83   aSelLab.ForgetAttribute(kSIMPLE_REF_ID);
84   if (theContext->groupName() == ModelAPI_ResultBody::group()) {
85     // do not select the whole shape for body:it is already must be in the data framework
86     if (theContext->shape().get() && theContext->shape()->isEqual(theSubShape)) {
87       aSelLab.ForgetAllAttributes(true);
88       TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
89     } else {
90       selectBody(theContext, theSubShape);
91     }
92   } else if (theContext->groupName() == ModelAPI_ResultConstruction::group()) {
93     selectConstruction(theContext, theSubShape);
94   }
95   myIsInitialized = true;
96
97   std::string aSelName = namingName();
98   if(!aSelName.empty())
99           TDataStd_Name::Set(selectionLabel(), aSelName.c_str()); //set name
100 #ifdef DDDD
101   //####
102   //selectSubShape("FACE",  "Extrusion_1/LateralFace_3");
103   //selectSubShape("FACE",  "Extrusion_1/TopFace");
104   //selectSubShape("EDGE", "Extrusion_1/TopFace|Extrusion_1/LateralFace_1");
105   //selectSubShape("EDGE", "Sketch_1/Edge_6");
106 #endif
107   owner()->data()->sendAttributeUpdated(this);
108 }
109
110 std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
111 {
112   std::shared_ptr<GeomAPI_Shape> aResult;
113   if (myIsInitialized) {
114     TDF_Label aSelLab = selectionLabel();
115     if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
116       ResultPtr aContext = context();
117       if (!aContext.get()) 
118         return aResult; // empty result
119       return aContext->shape();
120     }
121
122     Handle(TNaming_NamedShape) aSelection;
123     if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
124       TopoDS_Shape aSelShape = aSelection->Get();
125       aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
126       aResult->setImpl(new TopoDS_Shape(aSelShape));
127     } else { // for simple construction element: just shape of this construction element
128       ResultConstructionPtr aConstr = 
129         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(context());
130       if (aConstr) {
131         return aConstr->shape();
132       }
133     }
134   }
135   return aResult;
136 }
137
138 Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel)
139   : myRef(theLabel)
140 {
141   myIsInitialized = myRef.isInitialized();
142 }
143
144 ResultPtr Model_AttributeSelection::context() {
145   return std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
146 }
147
148
149 void Model_AttributeSelection::setObject(const std::shared_ptr<ModelAPI_Object>& theObject)
150 {
151   ModelAPI_AttributeSelection::setObject(theObject);
152   myRef.setObject(theObject);
153 }
154
155 TDF_LabelMap& Model_AttributeSelection::scope()
156 {
157   if (myScope.IsEmpty()) { // create a new scope if not yet done
158     // gets all labels with named shapes that are bofore this feature label (before in history)
159     TDF_Label aFeatureLab = std::dynamic_pointer_cast<Model_Data>(
160       owner()->data())->label().Father();
161     int aFeatureID = aFeatureLab.Tag();
162     TDF_ChildIterator aFeaturesIter(aFeatureLab.Father());
163     for(; aFeaturesIter.More(); aFeaturesIter.Next()) {
164       if (aFeaturesIter.Value().Tag() >= aFeatureID) // the left labels are created later
165         break;
166       TDF_ChildIDIterator aNSIter(aFeaturesIter.Value(), TNaming_NamedShape::GetID(), 1);
167       for(; aNSIter.More(); aNSIter.Next()) {
168         Handle(TNaming_NamedShape) aNS = Handle(TNaming_NamedShape)::DownCast(aNSIter.Value());
169         if (!aNS.IsNull() && aNS->Evolution() != TNaming_SELECTED) {
170           myScope.Add(aNS->Label());
171         }
172       }
173     }
174   }
175   return myScope;
176 }
177
178 bool Model_AttributeSelection::update()
179 {
180   ResultPtr aContext = context();
181   if (!aContext.get()) return false;
182   TDF_Label aSelLab = selectionLabel();
183   if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
184     return aContext->shape() && !aContext->shape()->isNull();
185   }
186
187   if (aContext->groupName() == ModelAPI_ResultBody::group()) {
188     // body: just a named shape, use selection mechanism from OCCT
189     TNaming_Selector aSelector(aSelLab);
190     bool aResult = aSelector.Solve(scope()) == Standard_True;
191     owner()->data()->sendAttributeUpdated(this);
192     return aResult;
193   } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) {
194     // construction: identification by the results indexes, recompute faces and
195     // take the face that more close by the indexes
196     std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr = 
197       std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(
198       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext)->shape());
199     if (aWirePtr && aWirePtr->hasPlane()) { // sketch sub-element
200       TDF_Label aLab = myRef.myRef->Label();
201       // getting a type of selected shape
202       Handle(TDataStd_Integer) aTypeAttr;
203       if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
204         return false;
205       }
206       TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
207       // selected indexes will be needed in each "if"
208       Handle(TDataStd_IntPackedMap) aSubIds;
209       std::shared_ptr<GeomAPI_Shape> aNewSelected;
210       bool aNoIndexes = 
211         !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
212       // for now working only with composite features
213       FeaturePtr aContextFeature = aContext->document()->feature(aContext);
214       CompositeFeaturePtr aComposite = 
215         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
216       if (!aComposite || aComposite->numberOfSubs() == 0) {
217         return false;
218       }
219
220       if (aShapeType == TopAbs_FACE) {
221         // If this is a wire with plane defined thin it is a sketch-like object
222         std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
223         GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
224           aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces);
225         if (aFaces.empty()) // no faces, update can not work correctly
226           return false;
227         // if there is no edges indexes, any face can be used: take the first
228         std::shared_ptr<GeomAPI_Shape> aNewSelected;
229         if (aNoIndexes) {
230           aNewSelected = *(aFaces.begin());
231         } else { // searching for most looks-like initial face by the indexes
232           // prepare edges of the current resut for the fast searching
233           TColStd_MapOfTransient allCurves;
234           const int aSubNum = aComposite->numberOfSubs();
235           for(int a = 0; a < aSubNum; a++) {
236             if (aSubIds->Contains(aComposite->subFeatureId(a))) {
237               FeaturePtr aSub = aComposite->subFeature(a);
238               const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
239               std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
240               for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
241                 ResultConstructionPtr aConstr = 
242                   std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
243                 if (aConstr->shape() && aConstr->shape()->isEdge()) {
244                   const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
245                   TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
246                   if (!anEdge.IsNull()) {
247                     Standard_Real aFirst, aLast;
248                     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
249                     allCurves.Add(aCurve);
250                   }
251                 }
252               }
253             }
254           }
255           // iterate new result faces and searching for these edges
256           std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFacesIter = aFaces.begin();
257           double aBestFound = 0; // best percentage of found edges
258           for(; aFacesIter != aFaces.end(); aFacesIter++) {
259             int aFound = 0, aNotFound = 0;
260             TopExp_Explorer anEdgesExp((*aFacesIter)->impl<TopoDS_Shape>(), TopAbs_EDGE);
261             for(; anEdgesExp.More(); anEdgesExp.Next()) {
262               TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current());
263               if (!anEdge.IsNull()) {
264                 Standard_Real aFirst, aLast;
265                 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
266                 if (allCurves.Contains(aCurve)) {
267                   aFound++;
268                 } else {
269                   aNotFound++;
270                 }
271               }
272             }
273             if (aFound + aNotFound != 0) {
274               double aPercentage = double(aFound) / double(aFound + aNotFound);
275               if (aPercentage > aBestFound) {
276                 aBestFound = aPercentage;
277                 aNewSelected = *aFacesIter;
278               }
279             }
280           }
281         }
282         if (aNewSelected) { // store this new selection
283           selectConstruction(aContext, aNewSelected);
284           owner()->data()->sendAttributeUpdated(this);
285           return true;
286         }
287       } else if (aShapeType == TopAbs_EDGE) {
288         // just reselect the edge by the id
289         const int aSubNum = aComposite->numberOfSubs();
290         for(int a = 0; a < aSubNum; a++) {
291           // if aSubIds take any, the first appropriate
292           if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
293             // found the appropriate feature
294             FeaturePtr aFeature = aComposite->subFeature(a);
295             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
296               aFeature->results().cbegin();
297             for(;aResIter != aFeature->results().cend(); aResIter++) {
298               ResultConstructionPtr aRes = 
299                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
300               if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
301                 selectConstruction(aContext, aRes->shape());
302                 owner()->data()->sendAttributeUpdated(this);
303                 return true;
304               }
305             }
306           }
307         }
308       } else if (aShapeType == TopAbs_VERTEX) {
309         // just reselect the vertex by the id of edge
310         const int aSubNum = aComposite->numberOfSubs();
311         for(int a = 0; a < aSubNum; a++) {
312           // if aSubIds take any, the first appropriate
313           int aFeatureID = aComposite->subFeatureId(a);
314           if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
315               aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
316               aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
317             // searching for deltas
318             int aVertexNum = 0;
319             if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
320             else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
321             // found the feature with appropriate edge
322             FeaturePtr aFeature = aComposite->subFeature(a);
323             std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
324               aFeature->results().cbegin();
325             for(;aResIter != aFeature->results().cend(); aResIter++) {
326               ResultConstructionPtr aRes = 
327                 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
328               if (aRes && aRes->shape()) {
329                 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
330                   selectConstruction(aContext, aRes->shape());
331                   owner()->data()->sendAttributeUpdated(this);
332                   return true;
333                 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
334                   const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
335                   int aVIndex = 1;
336                   for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
337                     if (aVIndex == aVertexNum) { // found!
338                       std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
339                       aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
340                       selectConstruction(aContext, aVertex);
341                       owner()->data()->sendAttributeUpdated(this);
342                       return true;
343                     }
344                     aVIndex++;
345                   }
346                 }
347               }
348             }
349           }
350         }
351       }
352     } else { // simple construction element: the selected is that needed
353       selectConstruction(aContext, aContext->shape());
354       owner()->data()->sendAttributeUpdated(this);
355       return true;
356     }
357   }
358   return false; // unknown case
359 }
360
361
362 void Model_AttributeSelection::selectBody(
363     const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
364 {
365   // perform the selection
366   TNaming_Selector aSel(selectionLabel());
367   TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : TopoDS_Shape();
368   TopoDS_Shape aContext;
369
370   ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(myRef.value());
371   if (aBody)
372     aContext = aBody->shape()->impl<TopoDS_Shape>();
373   else {
374     ResultConstructionPtr aConstr = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(myRef.value());
375     if (aConstr) {
376       aContext = aConstr->shape()->impl<TopoDS_Shape>();
377     } else {
378       Events_Error::send("A result with shape is expected");
379       return;
380     }
381   }
382   aSel.Select(aNewShape, aContext);
383 }
384
385 /// registers the name of the shape in the label (theID == 0) of sub label (theID is a tag)
386 /// if theID is zero, 
387 static void registerSubShape(TDF_Label& theMainLabel, TopoDS_Shape theShape,
388   const int theID, const FeaturePtr& theContextFeature, std::shared_ptr<Model_Document> theDoc,
389   std::string theAdditionalName,
390   Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)())
391 {
392   TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
393   TNaming_Builder aBuilder(aLab);
394   aBuilder.Generated(theShape);
395   std::stringstream aName;
396   aName<<theContextFeature->name()<<"/";
397   if (!theAdditionalName.empty())
398     aName<<theAdditionalName<<"/";
399   if (theShape.ShapeType() == TopAbs_FACE) aName<<"Face";
400   else if (theShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
401   else if (theShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
402
403   if (theRefs.IsNull()) {
404     aName<<theID;
405   } else { // make a compisite name from all sub-elements indexes: "1_2_3_4"
406     TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
407     for(; aRef.More(); aRef.Next()) {
408       aName<<"-"<<aRef.Key();
409     }
410   }
411
412   theDoc->addNamingName(aLab, aName.str());
413   TDataStd_Name::Set(aLab, aName.str().c_str());
414 }
415
416 void Model_AttributeSelection::selectConstruction(
417     const ResultPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape)
418 {
419   std::shared_ptr<Model_Document> aMyDoc = 
420     std::dynamic_pointer_cast<Model_Document>(owner()->document());
421   FeaturePtr aContextFeature = theContext->document()->feature(theContext);
422   CompositeFeaturePtr aComposite = 
423     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
424   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
425   if (!aComposite || aComposite->numberOfSubs() == 0) {
426     // saving of context is enough: result construction contains exactly the needed shape
427     TNaming_Builder aBuilder(selectionLabel());
428     aBuilder.Generated(aSubShape);
429     aMyDoc->addNamingName(selectionLabel(), theContext->data()->name());
430     TDataStd_Name::Set(selectionLabel(), theContext->data()->name().c_str());
431     return;
432   }
433   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(owner()->data());
434   TDF_Label aLab = myRef.myRef->Label();
435   // identify the reuslts of sub-object of the composite by edges
436   // save type of the selected shape in integer attribute
437   TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
438   TDataStd_Integer::Set(aLab, (int)aShapeType);
439   gp_Pnt aVertexPos;
440   TColStd_MapOfTransient allCurves;
441   if (aShapeType == TopAbs_VERTEX) { // compare positions
442     aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
443   } else { 
444     for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
445       TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
446       Standard_Real aFirst, aLast;
447       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
448       allCurves.Add(aCurve);
449     }
450   }
451   // iterate and store the result ids of sub-elements and sub-elements to sub-labels
452   Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
453   aRefs->Clear();
454   const int aSubNum = aComposite->numberOfSubs();
455   for(int a = 0; a < aSubNum; a++) {
456     FeaturePtr aSub = aComposite->subFeature(a);
457     const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
458     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
459     // there may be many shapes (circle and center): register if at least one is in selection
460     for(; aRes != aResults.cend(); aRes++) {
461       ResultConstructionPtr aConstr = 
462         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
463       if (!aConstr->shape()) {
464         continue;
465       }
466       if (aShapeType == TopAbs_VERTEX) {
467         if (aConstr->shape()->isVertex()) { // compare vertices positions
468           const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
469           gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
470           if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
471             aRefs->Add(aComposite->subFeatureId(a));
472           }
473         } else { // get first or last vertex of the edge: last is stored with negative sign
474           const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
475           int aDelta = kSTART_VERTEX_DELTA;
476           for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
477             gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
478             if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
479               aRefs->Add(aDelta + aComposite->subFeatureId(a));
480               break;
481             }
482             aDelta += kSTART_VERTEX_DELTA;
483           }
484         }
485       } else {
486         if (aConstr->shape()->isEdge()) {
487           const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
488           TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
489           if (!anEdge.IsNull()) {
490             Standard_Real aFirst, aLast;
491             Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
492             if (allCurves.Contains(aCurve)) {
493               int anID = aComposite->subFeatureId(a);
494               aRefs->Add(anID);
495               if (aShapeType != TopAbs_EDGE) { // edge do not need the sub-edges on sub-labels
496                 // add edges to sub-label to support naming for edges selection
497                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
498                 for(; anEdgeExp.More(); anEdgeExp.Next()) {
499                   TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
500                   Standard_Real aFirst, aLast;
501                   Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
502                   if (aFaceCurve == aCurve) {
503                     registerSubShape(selectionLabel(), anEdge, anID, aContextFeature, aMyDoc, "");
504                   }
505                 }
506               } else { // put vertices of the selected edge to sub-labels
507                 // add edges to sub-label to support naming for edges selection
508                 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
509                 int aTagIndex = anID + kSTART_VERTEX_DELTA;
510                 for(; anEdgeExp.More(); anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
511                   TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
512
513                   std::stringstream anAdditionalName; 
514                   registerSubShape(selectionLabel(), aV, aTagIndex, aContextFeature, aMyDoc,
515                     "");
516                 }
517               }
518             }
519           }
520         }
521       }
522     }
523   }
524   // store the selected as primitive
525   TNaming_Builder aBuilder(selectionLabel());
526   aBuilder.Generated(aSubShape);
527   registerSubShape(selectionLabel(), aSubShape, 0, aContextFeature, aMyDoc, "", aRefs);
528 }
529
530 TDF_Label Model_AttributeSelection::selectionLabel()
531 {
532   return myRef.myRef->Label().FindChild(1);
533 }
534
535 #define FIX_BUG1 1
536 std::string GetShapeName(std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape, 
537                                              const TDF_Label& theLabel)
538 {
539   std::string aName;
540   // check if the subShape is already in DF
541   Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(theShape, theLabel);
542   Handle(TDataStd_Name) anAttr;
543   if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document    
544         if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
545           aName = TCollection_AsciiString(anAttr->Get()).ToCString();
546           if(!aName.empty()) {      
547             const TDF_Label& aLabel = theDoc->findNamingName(aName);
548     /* MPV: the same shape with the same name may be duplicated on different labels (selection of the same construction object)
549                 if(!aLabel.IsEqual(aNS->Label())) {
550                   //aName.erase(); //something is wrong, to be checked!!!
551                   aName += "_SomethingWrong";
552                   return aName;
553                 }*/
554                 const TopoDS_Shape& aShape = aNS->Get();
555                 if(aShape.ShapeType() == TopAbs_COMPOUND) {
556                   std::string aPostFix("_");
557                   TopoDS_Iterator it(aShape);                   
558                   for (int i = 1;it.More();it.Next(), i++) {
559                     if(it.Value() == theShape) {
560                           aPostFix += TCollection_AsciiString (i).ToCString();
561                           aName    += aPostFix;
562                           break;
563                         }
564                         else continue;                                          
565                   }
566                 }
567           }     
568         }
569   }
570   return aName;
571 }
572
573 bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
574 {
575 // a trivial case: F1 & F2,  aNumber = 1, i.e. intersection gives 1 edge.
576   TopoDS_Compound aCmp;
577   BRep_Builder BB;
578   BB.MakeCompound(aCmp);
579   TopTools_ListIteratorOfListOfShape it(theAncestors);
580   for(;it.More();it.Next()) {
581         BB.Add(aCmp, it.Value());
582         theSMap.Add(it.Value());
583   }
584   int aNumber(0);
585   TopTools_IndexedDataMapOfShapeListOfShape aMap2;
586   TopExp::MapShapesAndAncestors(aCmp, TopAbs_EDGE, TopAbs_FACE, aMap2);
587   for (int i = 1; i <= aMap2.Extent(); i++) {
588         const TopoDS_Shape& aKey = aMap2.FindKey(i);
589         const TopTools_ListOfShape& anAncestors = aMap2.FindFromIndex(i);
590         if(anAncestors.Extent() > 1) aNumber++;
591   }
592   if(aNumber > 1) return false;
593   return true;
594 }
595 std::string Model_AttributeSelection::namingName()
596 {
597   std::shared_ptr<GeomAPI_Shape> aSubSh = value();
598   ResultPtr aCont = context();
599   std::string aName;
600   if(!aSubSh.get() || aSubSh->isNull() || !aCont.get() || aCont->shape()->isNull()) 
601     return aName;
602   TopoDS_Shape aSubShape = aSubSh->impl<TopoDS_Shape>();
603   TopoDS_Shape aContext  = aCont->shape()->impl<TopoDS_Shape>();
604   std::shared_ptr<Model_Document> aDoc = 
605     std::dynamic_pointer_cast<Model_Document>(aCont->document());
606
607   // check if the subShape is already in DF
608   aName = GetShapeName(aDoc, aSubShape, selectionLabel());
609   if(aName.empty() ) { // not in the document!
610     TopAbs_ShapeEnum aType = aSubShape.ShapeType();
611         switch (aType) {
612           case TopAbs_FACE:
613       // the Face should be in DF. If it is not a case, it is an error ==> to be dbugged                
614                 break;
615           case TopAbs_EDGE:
616                   {
617                   // name structure: F1 | F2 [| F3 | F4], where F1 & F2 the faces which gives the Edge in trivial case
618                   // if it is not atrivial case we use localization by neighbours. F3 & F4 - neighbour faces
619                   TopTools_IndexedMapOfShape aSMap; // map for ancestors of the sub-shape
620                   TopTools_IndexedDataMapOfShapeListOfShape aMap;
621                   TopExp::MapShapesAndAncestors(aContext, TopAbs_EDGE, TopAbs_FACE, aMap);
622                   bool isTrivialCase(true);
623                   for (int i = 1; i <= aMap.Extent(); i++) {
624                         const TopoDS_Shape& aKey = aMap.FindKey(i);
625                         if (aKey.IsNotEqual(aSubShape)) continue; // find exactly the selected key
626
627             const TopTools_ListOfShape& anAncestors = aMap.FindFromIndex(i);
628                         // check that it is not a trivial case (F1 & F2: aNumber = 1)
629                         isTrivialCase = isTrivial(anAncestors, aSMap);                  
630                         break;
631                   }
632
633                   TopTools_ListOfShape aListOfNbs;
634                   if(!isTrivialCase) { // find Neighbors
635                         TNaming_Localizer aLocalizer;
636                         TopTools_MapOfShape aMap3;
637                         aLocalizer.FindNeighbourg(aContext, aSubShape, aMap3);
638                         //int n = aMap3.Extent();
639                         TopTools_MapIteratorOfMapOfShape it(aMap3);
640                         for(;it.More();it.Next()) {
641                           const TopoDS_Shape& aNbShape = it.Key(); // neighbor edge
642                           //TopAbs_ShapeEnum aType = aNbShape.ShapeType();
643                           const TopTools_ListOfShape& aList  = aMap.FindFromKey(aNbShape);
644                           TopTools_ListIteratorOfListOfShape it2(aList);
645                           for(;it2.More();it2.Next()) {
646                                 if(aSMap.Contains(it2.Value())) continue; // skip this Face
647                                 aListOfNbs.Append(it2.Value());
648                           }
649                         }
650                   }  // else a trivial case
651                   
652                   // build name of the sub-shape Edge
653                   for(int i=1; i <= aSMap.Extent(); i++) {
654                         const TopoDS_Shape& aFace = aSMap.FindKey(i);
655                         std::string aFaceName = GetShapeName(aDoc, aFace, selectionLabel());
656                         if(i == 1)
657                           aName = aFaceName;
658                         else 
659                           aName += "|" + aFaceName;
660                   }
661                   TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
662                   for (;itl.More();itl.Next()) {
663                         std::string aFaceName = GetShapeName(aDoc, itl.Value(), selectionLabel());
664                         aName += "|" + aFaceName;
665                   }               
666                   }
667                   break;
668
669           case TopAbs_VERTEX:
670                   // name structure (Monifold Topology): 
671                   // 1) F1 | F2 | F3 - intersection of 3 faces defines a vertex - trivial case.
672                   // 2) F1 | F2      - intersection of 2 faces definses a vertex - applicable for case
673                   //                   when 1 faces is cylindrical, conical, spherical or revolution and etc.
674                   // 3) E1 | E2 | E3 - intersection of 3 edges defines a vertex - when we have case of a shell
675                   //                   or compound of 2 open faces.
676                   // 4) E1 | E2      - intesection of 2 edges defines a vertex - when we have a case of 
677                   //                   two independent edges (wire or compound)
678                   // implemented 2 first cases
679                   {
680                         TopTools_IndexedDataMapOfShapeListOfShape aMap;
681                     TopExp::MapShapesAndAncestors(aContext, TopAbs_VERTEX, TopAbs_FACE, aMap);
682                         const TopTools_ListOfShape& aList2  = aMap.FindFromKey(aSubShape);
683                         TopTools_ListOfShape aList;
684                         TopTools_MapOfShape aFMap;
685 #ifdef FIX_BUG1
686                         //int n = aList2.Extent(); //bug!
687                         // fix is below
688                         TopTools_ListIteratorOfListOfShape itl2(aList2);
689                     for (int i = 1;itl2.More();itl2.Next(),i++) {
690                           if(aFMap.Add(itl2.Value()))
691                                 aList.Append(itl2.Value());
692                         }
693                         //n = aList.Extent();
694 #endif
695                         TopTools_ListIteratorOfListOfShape itl(aList);
696                     for (int i = 1;itl.More();itl.Next(),i++) {
697                           const TopoDS_Shape& aFace = itl.Value();
698                           std::string aFaceName = GetShapeName(aDoc, aFace, selectionLabel());
699                           if(i == 1)
700                             aName = aFaceName;
701                           else 
702                             aName += "|" + aFaceName;
703                         }
704                   }
705                   break;
706         }
707     // register name                    
708     // aDoc->addNamingName(selectionLabel(), aName);
709         // the selected sub-shape will not be shared and as result it will not require registration
710   }
711   return aName;
712 }
713
714 TopAbs_ShapeEnum translateType (const std::string& theType)
715 {
716   TCollection_AsciiString aStr(theType.c_str());
717   aStr.UpperCase();
718   if(aStr.IsEqual("COMP"))
719         return TopAbs_COMPOUND;
720   else if(aStr.IsEqual("COMS"))
721         return TopAbs_COMPSOLID;
722   else if(aStr.IsEqual("SOLD"))
723         return TopAbs_SOLID;
724   else if(aStr.IsEqual("SHEL"))
725         return TopAbs_SHELL;
726   else if(aStr.IsEqual("FACE"))
727         return TopAbs_FACE;
728   else if(aStr.IsEqual("WIRE"))
729         return TopAbs_WIRE;
730   else if(aStr.IsEqual("EDGE"))
731         return TopAbs_EDGE;
732   else if(aStr.IsEqual("VERT"))
733         return TopAbs_VERTEX;  
734
735   return TopAbs_SHAPE;
736 }
737
738 const TopoDS_Shape getShapeFromCompound(const std::string& theSubShapeName, const TopoDS_Shape& theCompound)
739 {
740   TopoDS_Shape aSelection;
741   std::string::size_type n = theSubShapeName.rfind('/');                        
742   if (n == std::string::npos) n = 0;
743         std::string aSubString = theSubShapeName.substr(n + 1);
744         n = aSubString.rfind('_');
745         if (n == std::string::npos) return aSelection;
746         aSubString = aSubString.substr(n+1);
747         int indx = atoi(aSubString.c_str());
748         TopoDS_Iterator it(theCompound);                        
749         for (int i = 1;it.More();it.Next(), i++) {
750           if(i == indx) {                         
751             aSelection = it.Value();                      
752             break;
753           }
754           else continue;                                                
755         }
756   return aSelection;    
757 }
758
759 const TopoDS_Shape findFaceByName(const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc)
760 {
761   TopoDS_Shape aFace;
762   std::string::size_type n, nb = theSubShapeName.rfind('/');                    
763   if (nb == std::string::npos) nb = 0;
764   std::string aSubString = theSubShapeName.substr(nb + 1);
765   n = aSubString.rfind('_');
766   if (n != std::string::npos) {
767           std::string aSubStr2 = aSubString.substr(0, n);
768         aSubString  = theSubShapeName.substr(0, nb + 1);
769         aSubString = aSubString + aSubStr2;     
770   } else
771         aSubString = theSubShapeName;
772                                 
773   const TDF_Label& aLabel = theDoc->findNamingName(aSubString);
774   if(aLabel.IsNull()) return aFace;
775   Handle(TNaming_NamedShape) aNS;
776   if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
777         const TopoDS_Shape& aShape = aNS->Get();
778         if(!aShape.IsNull()) {
779           if(aShape.ShapeType() == TopAbs_COMPOUND) 
780             aFace = getShapeFromCompound(theSubShapeName, aShape);
781           else 
782                 aFace = aShape;   
783         }
784   }
785   return aFace;
786 }
787
788 int ParseEdgeName(const std::string& theSubShapeName,   std::list<std::string>& theList)
789 {
790   std::string aName = theSubShapeName;
791   std::string aLastName;
792   int n1(0), n2(0); // n1 - start position, n2 - position of the delimiter
793   while ((n2 = aName.find('|', n1)) != std::string::npos) {
794     const std::string aName1 = aName.substr(n1, n2); //name of face
795         theList.push_back(aName1);      
796         n1 = n2 + 1;
797         aLastName = aName.substr(n1);
798   }
799   if(!aLastName.empty())
800         theList.push_back(aLastName);
801   return theList.size();
802 }
803
804 const TopoDS_Shape findCommonShape(const TopAbs_ShapeEnum theType, const TopTools_ListOfShape& theList)
805 {
806   TopoDS_Shape aShape;
807   std::vector<TopTools_MapOfShape> aVec;
808   TopTools_MapOfShape aMap1, aMap2, aMap3, aMap4;
809   if(theList.Extent() > 1) {
810         aVec.push_back(aMap1);
811         aVec.push_back(aMap2);
812   }
813   if(theList.Extent() > 2)
814     aVec.push_back(aMap3);
815   if(theList.Extent() == 4)
816     aVec.push_back(aMap4);
817
818   //fill maps
819   TopTools_ListIteratorOfListOfShape it(theList);
820   for(int i = 0;it.More();it.Next(),i++) {
821         const TopoDS_Shape& aFace = it.Value();
822         TopExp_Explorer anExp (aFace, theType);
823         for(;anExp.More();anExp.Next()) {
824           const TopoDS_Shape& anEdge = anExp.Current();
825           if (!anEdge.IsNull())
826                 aVec[i].Add(anExp.Current());
827         }
828   }
829   //trivial case: 2 faces
830   TopTools_MapIteratorOfMapOfShape it2(aVec[0]);
831   for(;it2.More();it2.Next()) {
832           if(aVec[1].Contains(it2.Key())) {
833             aShape = it2.Key();
834                 break;
835           }
836   }
837   return aShape;
838 }
839 // type ::= COMP | COMS | SOLD | SHEL | FACE | WIRE | EDGE | VERT
840 void Model_AttributeSelection::selectSubShape(const std::string& theType, const std::string& theSubShapeName)
841 {
842   if(theSubShapeName.empty() || theType.empty()) return;
843   TopAbs_ShapeEnum aType = translateType(theType);
844   ResultPtr aCont = context();
845   if(!aCont.get() || aCont->shape()->isNull()) return;
846   TopoDS_Shape aContext  = aCont->shape()->impl<TopoDS_Shape>();
847   TopAbs_ShapeEnum aContType = aContext.ShapeType();
848   if(aType <= aContType) return; // not applicable
849
850   std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(aCont->document());
851   TopoDS_Shape aSelection;
852   switch (aType) 
853   {
854   case TopAbs_COMPOUND:
855     break;
856   case TopAbs_COMPSOLID:
857     break;
858   case TopAbs_SOLID:
859     break;
860   case TopAbs_SHELL:
861     break;
862   case TopAbs_FACE:
863     {
864           const TopoDS_Shape aSelection = findFaceByName(theSubShapeName, aDoc);
865           if(!aSelection.IsNull()) {// Select it
866                 std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
867         aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
868                 setValue(aCont, aShapeToBeSelected);
869           }
870         }
871     break;
872   case TopAbs_WIRE:
873         break;
874   case TopAbs_EDGE:
875         {  
876           TopoDS_Shape aSelection;// = findFaceByName(theSubShapeName, aDoc);
877           const TDF_Label& aLabel = aDoc->findNamingName(theSubShapeName);
878       if(!aLabel.IsNull()) {
879         Handle(TNaming_NamedShape) aNS;
880         if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
881               const TopoDS_Shape& aShape = aNS->Get();
882               if(!aShape.IsNull()) {
883                 if(aShape.ShapeType() == TopAbs_COMPOUND) 
884                   aSelection = getShapeFromCompound(theSubShapeName, aShape);
885                         else 
886                     aSelection = aShape;          
887                   }
888                 }
889           }
890           if(aSelection.IsNull()) {
891           std::list<std::string> aListofNames;
892           int n = ParseEdgeName(theSubShapeName, aListofNames);
893           if(n > 1 && n < 5) {
894                 TopTools_ListOfShape aList;
895         for(std::list<std::string>::iterator it =aListofNames.begin();it != aListofNames.end();it++){
896                   const TopoDS_Shape aFace = findFaceByName(*it, aDoc);
897                   aList.Append(aFace);          
898                 }
899                 aSelection = findCommonShape(TopAbs_EDGE, aList);
900           }
901           }
902           if(!aSelection.IsNull()) {// Select it
903                 std::shared_ptr<GeomAPI_Shape> aShapeToBeSelected(new GeomAPI_Shape());
904         aShapeToBeSelected->setImpl(new TopoDS_Shape(aSelection));
905                 setValue(aCont, aShapeToBeSelected);
906           }
907         }
908     break;
909   case TopAbs_VERTEX:
910         break;
911   default: //TopAbs_SHAPE
912         return;
913   }
914
915 }