1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: ModelAPI_ResultConstruction.cpp
4 // Created: 07 Jul 2014
5 // Author: Mikhail PONIKAROV
7 #include <Model_ResultConstruction.h>
9 #include <Model_Data.h>
10 #include <ModelAPI_CompositeFeature.h>
11 #include <Model_SelectionNaming.h>
12 #include <ModelAPI_Events.h>
13 #include <Config_PropManager.h>
14 #include <GeomAPI_PlanarEdges.h>
15 #include <GeomAPI_Shape.h>
16 #include <GeomAlgoAPI_SketchBuilder.h>
17 #include <Events_Loop.h>
19 #include <TDF_Reference.hxx>
20 #include <TDF_ChildIterator.hxx>
21 #include <TNaming_NamedShape.hxx>
22 #include <TNaming_Builder.hxx>
23 #include <TDataStd_Integer.hxx>
24 #include <TDataStd_IntPackedMap.hxx>
25 #include <TDataStd_Name.hxx>
26 #include <TDataStd_UAttribute.hxx>
27 #include <TColStd_MapOfTransient.hxx>
28 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
29 #include <BRep_Tool.hxx>
30 #include <BRep_Builder.hxx>
32 #include <TopoDS_Shape.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <TopoDS_Vertex.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TNaming_Tool.hxx>
37 #include <Precision.hxx>
39 // identifier that it is full result selected, but in external document (for internal index is 0)
40 Standard_GUID kFULL_RESULT_ID("ee87e529-da6f-46af-be25-5e0fefde52f7");
43 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
44 std::string& theDefault)
46 theSection = "Visualization";
47 theName = "result_construction_color";
48 theDefault = DEFAULT_COLOR();
51 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
53 if (myShape != theShape) {
54 if (!theShape.get() || !theShape->isEqual(myShape)) {
55 static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
56 ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
60 myFacesUpToDate = false;
66 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
71 Model_ResultConstruction::Model_ResultConstruction()
75 myFacesUpToDate = false;
78 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
80 myIsInHistory = isInHistory;
83 int Model_ResultConstruction::facesNum()
85 if (!myFacesUpToDate) {
86 std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
87 std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(myShape);
89 std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
90 GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
91 aWirePtr->norm(), aWirePtr, aFaces);
92 std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFIter = aFaces.begin();
93 for(; aFIter != aFaces.end(); aFIter++) {
94 std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
95 if (aFace.get() && !aFace->isNull())
96 myFaces.push_back(aFace);
99 myFacesUpToDate = true;
101 return int(myFaces.size());
104 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
106 return myFaces[theIndex];
109 bool Model_ResultConstruction::isInfinite()
114 void Model_ResultConstruction::setInfinite(const bool theInfinite)
116 myIsInfinite = theInfinite;
119 void Model_ResultConstruction::setIsConcealed(const bool theValue)
121 // do nothing: the construction element is never consealed
124 static const int kSTART_VERTEX_DELTA = 1000000;
126 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, std::string theFullName,
127 const int theID, std::shared_ptr<Model_Document> theDoc,
128 bool theSelectionMode)
130 TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
131 TNaming_Builder aBuilder(aLab);
132 // wire never happens as sub, it must be generated to be found
133 // by SelectionNaming TNaming_Tool::NamedShape
134 if (theSelectionMode && theShape.ShapeType() != TopAbs_WIRE)
135 aBuilder.Select(theShape, theShape);
137 aBuilder.Generated(theShape);
139 theDoc->addNamingName(aLab, theFullName);
140 TDataStd_Name::Set(aLab, theFullName.c_str());
143 // generates a full-name for sub-element of the composite feature (sketch)
144 std::string fullName(CompositeFeaturePtr theComposite, const TopoDS_Shape& theSubShape,
145 Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)())
147 TopAbs_ShapeEnum aShapeType = theSubShape.ShapeType();
149 TColStd_MapOfTransient allCurves;
150 if (aShapeType == TopAbs_VERTEX) { // compare positions
151 aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(theSubShape));
153 for(TopExp_Explorer anEdgeExp(theSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
154 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
155 Standard_Real aFirst, aLast;
156 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
157 allCurves.Add(aCurve);
160 std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
161 std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
162 TColStd_PackedMapOfInteger aRefs; // indixes of sub-elements in composite
164 const int aSubNum = theComposite->numberOfSubs();
165 for(int a = 0; a < aSubNum; a++) {
166 FeaturePtr aSub = theComposite->subFeature(a);
167 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
168 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
169 // there may be many shapes (circle and center): register if at least one is in selection
170 for(; aRes != aResults.cend(); aRes++) {
171 ResultConstructionPtr aConstr =
172 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
173 if (!aConstr->shape()) {
176 if (aShapeType == TopAbs_VERTEX) {
177 if (aConstr->shape()->isVertex()) { // compare vertices positions
178 const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
179 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
180 if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
181 aRefs.Add(theComposite->subFeatureId(a));
182 aSubNames[theComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
184 } else { // get first or last vertex of the edge: last is stored with additional delta
185 const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
186 int aDelta = kSTART_VERTEX_DELTA;
187 for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
188 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
189 if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
190 aRefs.Add(aDelta + theComposite->subFeatureId(a));
191 aSubNames[aDelta + theComposite->subFeatureId(a)] =
192 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
195 aDelta += kSTART_VERTEX_DELTA;
199 if (aConstr->shape()->isEdge()) {
200 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
201 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
202 if (!anEdge.IsNull()) {
203 Standard_Real aFirst, aLast;
204 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
205 if (allCurves.Contains(aCurve)) {
206 int anID = theComposite->subFeatureId(a);
208 aSubNames[anID] = Model_SelectionNaming::shortName(aConstr);
209 if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
210 // add edges to sub-label to support naming for edges selection
211 TopExp_Explorer anEdgeExp(theSubShape, TopAbs_EDGE);
212 for(; anEdgeExp.More(); anEdgeExp.Next()) {
213 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
214 Standard_Real aFirst, aLast;
215 Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
216 if (aFaceCurve == aCurve) {
217 int anOrient = Model_SelectionNaming::edgeOrientation(theSubShape, anEdge);
218 anOrientations[anID] = anOrient;
228 std::stringstream aName;
229 // #1839 : do not store name of the feature in the tree, since this name could be changed
230 if (theSubShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole construction result
231 if (theSubShape.ShapeType() == TopAbs_FACE) aName<<"Face";
232 else if (theSubShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
233 else if (theSubShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
234 else if (theSubShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
236 // make a composite name from all sub-elements indexes: "1_2_3_4"
237 TColStd_MapIteratorOfPackedMapOfInteger aRef(aRefs);
238 for(; aRef.More(); aRef.Next()) {
239 aName<<"-"<<aSubNames[aRef.Key()];
240 if (anOrientations.find(aRef.Key()) != anOrientations.end()) {
241 if (anOrientations[aRef.Key()] == 1)
243 else if (anOrientations[aRef.Key()] == -1)
248 if (!theRefs.IsNull()) {
249 Handle(TColStd_HPackedMapOfInteger) aMap = new TColStd_HPackedMapOfInteger(aRefs);
250 theRefs->ChangeMap(aMap);
255 // stores shape and name on sub-label of the main stored shape
256 static void saveSubName(TDF_Label& theLab, const bool isSelectionMode, const TopoDS_Shape& aSub,
257 std::shared_ptr<Model_Document> theDoc, std::string theFullName)
259 TNaming_Builder aBuilder(theLab);
261 aBuilder.Select(aSub, aSub);
263 aBuilder.Generated(aSub);
264 theDoc->addNamingName(theLab, theFullName.c_str());
265 TDataStd_Name::Set(theLab, theFullName.c_str());
269 TDF_Label Model_ResultConstruction::startLabel(
270 const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theExternal)
272 theExternal = theExtDoc.get() && theExtDoc != document();
273 if (theExternal) { // external document is used
274 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theExtDoc);
275 return aDoc->extConstructionsLabel();
277 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
278 return aData->label();
281 int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSubShape,
282 const std::shared_ptr<ModelAPI_Document> theExtDoc, const int theIndex)
284 int anIndex; // resulting index of the sub-label
285 TopoDS_Shape aSubShape;
286 if (theSubShape.get()) {
287 aSubShape = theSubShape->impl<TopoDS_Shape>();
288 } else if (shape().get()) {
289 aSubShape = shape()->impl<TopoDS_Shape>();
291 // if external document requires this selection, put the naming structures to this doc
292 // to support the naming mechanism in this document correctly
294 TDF_Label aDataLab = startLabel(theExtDoc, anExternal);
295 if (theIndex == -1) {
296 anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape
298 if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext)
299 // iterate all the already presented shapes to see the same
300 TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
301 for(; aSubsIter.More(); aSubsIter.Next()) {
302 const TDF_Label aLab = aSubsIter.Value();
303 if (aLab.Tag() == 1) // skip the root shape label
305 Handle(TNaming_NamedShape) aNS;
306 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
307 if (aNS->Get().IsSame(aSubShape)) {
308 return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do
311 anIndex = aLab.Tag(); // searching for the latest index
313 anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all
316 anIndex = theIndex + 1;
319 // set the naming structure at index
320 TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True);
322 // if the subshape is part of a result face, select the whole face (#1997)
323 bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
324 if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
325 for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
326 TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
327 for(; anExp.More(); anExp.Next()) {
328 if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
329 // here just store the face index (to update face if update of edge is needed)
330 TNaming_Builder aBuilder(aLab);
331 aBuilder.Select(aSubShape, aSubShape);
332 int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
333 TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
334 isSelectionMode = true;
341 // external full result is not identified by index == 0, so, add here the ID
342 if (!theSubShape.get()) {
343 TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID);
345 TNaming_Builder aBuilder(aLab);
346 // store all sub-faces naming since faces may be used for extrusion, where all edges are needed
347 Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab);
348 std::list<int> aFacesIndexes;
349 for(int a = 0; a < facesNum(); a++) {
350 anIndices->Add(select(face(a), theExtDoc, -1));
355 { // this to have erased Builder after the shape was generated (NS on this label may be changed)
356 TNaming_Builder aBuilder(aLab);
357 if (aSubShape.IsNull()) {
358 return anIndex - 1; // just keep empty named shape
360 // wire never happens as sub, it must be generated to be found
361 // by SelectionNaming TNaming_Tool::NamedShape
362 if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) {
363 aBuilder.Select(aSubShape, aSubShape);
365 aBuilder.Generated(aSubShape);
369 if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection
372 ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
373 FeaturePtr aThisFeature = document()->feature(aThisPtr);
374 CompositeFeaturePtr aComposite =
375 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
376 if (!aComposite || aComposite->numberOfSubs() == 0) {
377 // saving of context is enough: result construction contains exactly the needed shape
381 // identify the results of sub-object of the composite by edges
382 // save type of the selected shape in integer attribute
383 TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
384 TDataStd_Integer::Set(aLab, (int)aShapeType);
386 TColStd_MapOfTransient allCurves;
387 if (aShapeType == TopAbs_VERTEX) { // compare positions
388 aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
390 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
391 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
392 Standard_Real aFirst, aLast;
393 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
394 allCurves.Add(aCurve);
397 std::shared_ptr<Model_Document> aMyDoc =
398 std::dynamic_pointer_cast<Model_Document>(document());
399 // iterate and store the result ids of sub-elements and sub-elements to sub-labels
400 Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
401 const int aSubNum = aComposite->numberOfSubs();
402 for(int a = 0; a < aSubNum; a++) {
403 FeaturePtr aSub = aComposite->subFeature(a);
404 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
405 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
406 // there may be many shapes (circle and center): register if at least one is in selection
407 for(; aRes != aResults.cend(); aRes++) {
408 ResultConstructionPtr aConstr =
409 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
410 if (!aConstr->shape()) {
413 if (aShapeType != TopAbs_VERTEX) {
414 if (aConstr->shape()->isEdge()) {
415 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
416 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
417 if (!anEdge.IsNull()) {
418 Standard_Real aFirst, aLast;
419 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
420 if (allCurves.Contains(aCurve)) {
421 int anID = aComposite->subFeatureId(a);
422 if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
423 // add edges to sub-label to support naming for edges selection
424 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
425 for(; anEdgeExp.More(); anEdgeExp.Next()) {
426 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
427 Standard_Real aFirst, aLast;
428 Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
429 if (aFaceCurve == aCurve) {
430 TDF_Label aSubLab = aLab.FindChild(anID);
431 std::string aFullNameSub = fullName(aComposite, anEdge);
432 saveSubName(aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
434 int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
436 // store the orientation of edge relatively to face if needed
437 TDataStd_Integer::Set(aSubLab, anOrient);
441 } else { // put vertices of the selected edge to sub-labels
442 // add edges to sub-label to support naming for edges selection
443 int aTagIndex = anID + kSTART_VERTEX_DELTA;
444 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
446 anEdgeExp.Next(), aTagIndex += kSTART_VERTEX_DELTA) {
447 TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
448 TDF_Label aSubLab = aLab.FindChild(aTagIndex);
449 std::string aFullNameSub = fullName(aComposite, aV);
450 saveSubName(aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
459 std::string aFullName = fullName(aComposite, aSubShape, aRefs);
460 // store the selected as primitive
461 registerSubShape(aLab, aSubShape, aFullName, 0, aMyDoc, isSelectionMode);
465 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape(const int theIndex,
466 const std::shared_ptr<ModelAPI_Document> theExtDoc)
468 std::shared_ptr<GeomAPI_Shape> aResult;
470 return aResult; // the whole shape, so, NULL
473 TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1);
474 if (!aLab.IsNull()) { // index is not bad
475 Handle(TNaming_NamedShape) aSelection;
476 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
477 TopoDS_Shape aSelShape = aSelection->Get();
478 if (aSelShape.IsNull())
479 return aResult; // shape equal to context => null
480 aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
481 aResult->setImpl(new TopoDS_Shape(aSelShape));
488 bool Model_ResultConstruction::update(const int theIndex,
489 const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theModified)
493 TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True);
494 if (theIndex == 0 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0
495 // it is just reference to construction, not sub-shape
496 // if there is a sketch, the sketch-naming must be updated
498 // update all faces named by the whole result
500 Handle(TDataStd_IntPackedMap) anIndices;
501 if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) {
502 NCollection_Map<TopoDS_Shape> aFaces; // collect faces, updated in the tree
503 TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap());
504 Handle(TColStd_HPackedMapOfInteger) aNewPackedMap =
505 new TColStd_HPackedMapOfInteger; // with only faces that are ok
506 // iterate to find existing faces, updated
507 for(; anIndexIter.More(); anIndexIter.Next()) {
508 if (update(anIndexIter.Key(), theExtDoc, theModified)) {
509 GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc);
510 if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
511 aNewPackedMap->ChangeMap().Add(anIndexIter.Key());
512 aFaces.Add(aFace->impl<TopoDS_Shape>());
516 // then iterate all existing faces to find new faces
517 int aCurrentFacesNum = facesNum();
518 for(int a = 0; a < aCurrentFacesNum; a++) {
519 GeomShapePtr aFace = face(a);
520 if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
522 int aNewFaceIndex = select(aFace, theExtDoc, -1);
523 if (aNewFaceIndex > 0) {
524 aNewPackedMap->ChangeMap().Add(aNewFaceIndex);
528 anIndices->ChangeMap(aNewPackedMap);
532 // For correct naming selection, put the shape into the naming structure.
533 // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
534 TNaming_Builder aBuilder(aLab);
535 aBuilder.Generated(shape()->impl<TopoDS_Shape>());
537 return shape() && !shape()->isNull();
539 // construction: identification by the results indexes, recompute faces and
540 // take the face that more close by the indexes
541 ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
542 FeaturePtr aContextFeature = document()->feature(aThisPtr);
544 // sketch sub-element
545 if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
547 // update the referenced object if it is sub
548 Handle(TDF_Reference) aRef;
549 if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
550 int aFaceIndex = aRef->Get().Tag();
551 // don't check selection ,since face may disappear, but the shape stays correct
552 Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
554 // getting a type of selected shape
555 Handle(TDataStd_Integer) aTypeAttr;
556 if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
559 TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
560 // selected indexes will be needed in each "if"
561 Handle(TDataStd_IntPackedMap) aSubIds;
562 std::shared_ptr<GeomAPI_Shape> aNewSelected;
564 !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
565 // for now working only with composite features
566 CompositeFeaturePtr aComposite =
567 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
568 if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
572 if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) {
573 // compound is for the whole sketch selection
574 // If this is a wire with plane defined then it is a sketch-like object
575 if (!facesNum()) // no faces, update can not work correctly
577 // if there is no edges indexes, any face can be used: take the first
578 std::shared_ptr<GeomAPI_Shape> aNewSelected;
580 aNewSelected = face(0);
581 } else { // searching for most looks-like initial face by the indexes
582 // prepare edges of the current result for the fast searching
583 // curves and orientations of edges
584 NCollection_DataMap<Handle(Geom_Curve), int> allCurves;
585 const int aSubNum = aComposite->numberOfSubs();
586 for(int a = 0; a < aSubNum; a++) {
587 int aSubID = aComposite->subFeatureId(a);
588 if (aSubIds->Contains(aSubID)) {
589 FeaturePtr aSub = aComposite->subFeature(a);
590 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
591 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
592 for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
593 ResultConstructionPtr aConstr =
594 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
595 if (aConstr->shape() && aConstr->shape()->isEdge()) {
596 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
597 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
598 if (!anEdge.IsNull()) {
599 Standard_Real aFirst, aLast;
600 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
601 // searching for orientation information
603 Handle(TDataStd_Integer) anInt;
604 if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) {
605 anOrient = anInt->Get();
607 allCurves.Bind(aCurve, anOrient);
613 aNewSelected = Model_SelectionNaming::findAppropriateFace(
614 aThisPtr, allCurves, aShapeType == TopAbs_WIRE);
616 if (aNewSelected) { // store this new selection
617 select(aNewSelected, theExtDoc, theIndex);
621 // if the selection is not found, put the empty shape:
622 // it's better to have disappeared shape, than the old, the lost one
623 TNaming_Builder anEmptyBuilder(aLab);
626 } else if (aShapeType == TopAbs_EDGE) {
627 // just reselect the edge by the id
628 const int aSubNum = aComposite->numberOfSubs();
629 for(int a = 0; a < aSubNum; a++) {
630 // if aSubIds take any, the first appropriate
631 if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
632 // found the appropriate feature
633 FeaturePtr aFeature = aComposite->subFeature(a);
634 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
635 aFeature->results().cbegin();
636 for(;aResIter != aFeature->results().cend(); aResIter++) {
637 ResultConstructionPtr aRes =
638 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
639 if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
640 select(aRes->shape(), theExtDoc, theIndex);
647 } else if (aShapeType == TopAbs_VERTEX) {
648 // just reselect the vertex by the id of edge
649 const int aSubNum = aComposite->numberOfSubs();
650 for(int a = 0; a < aSubNum; a++) {
651 // if aSubIds take any, the first appropriate
652 int aFeatureID = aComposite->subFeatureId(a);
653 if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
654 aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
655 aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
656 // searching for deltas
658 if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
659 else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
660 // found the feature with appropriate edge
661 FeaturePtr aFeature = aComposite->subFeature(a);
662 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
663 aFeature->results().cbegin();
664 for(;aResIter != aFeature->results().cend(); aResIter++) {
665 ResultConstructionPtr aRes =
666 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
667 if (aRes && aRes->shape()) {
668 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
669 select(aRes->shape(), theExtDoc, theIndex);
672 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
673 const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
675 for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
676 if (aVIndex == aVertexNum) { // found!
677 std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
678 aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
679 select(aVertex, theExtDoc, theIndex);
691 } else { // simple construction element: the selected is that needed
692 select(shape(), theExtDoc, theIndex);
696 return false; // unknown case