1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 #include <Model_ResultConstruction.h>
23 #include <Model_Data.h>
24 #include <ModelAPI_CompositeFeature.h>
25 #include <Model_SelectionNaming.h>
26 #include <ModelAPI_Events.h>
27 #include <Config_PropManager.h>
28 #include <GeomAPI_PlanarEdges.h>
29 #include <GeomAPI_Shape.h>
30 #include <GeomAlgoAPI_SketchBuilder.h>
31 #include <Events_Loop.h>
33 #include <TDF_Reference.hxx>
34 #include <TDF_ChildIterator.hxx>
35 #include <TNaming_NamedShape.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TDataStd_Integer.hxx>
38 #include <TDataStd_IntPackedMap.hxx>
39 #include <TDataStd_Name.hxx>
40 #include <TDataStd_UAttribute.hxx>
41 #include <TColStd_MapOfTransient.hxx>
42 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
43 #include <BRep_Tool.hxx>
44 #include <BRep_Builder.hxx>
46 #include <TopoDS_Shape.hxx>
47 #include <TopoDS_Edge.hxx>
48 #include <TopoDS_Vertex.hxx>
49 #include <TopExp_Explorer.hxx>
50 #include <TNaming_Tool.hxx>
51 #include <Precision.hxx>
53 // identifier that it is full result selected, but in external document (for internal index is 0)
54 Standard_GUID kFULL_RESULT_ID("ee87e529-da6f-46af-be25-5e0fefde52f7");
57 void Model_ResultConstruction::colorConfigInfo(std::string& theSection, std::string& theName,
58 std::string& theDefault)
60 theSection = "Visualization";
61 theName = "result_construction_color";
62 theDefault = DEFAULT_COLOR();
65 void Model_ResultConstruction::setShape(std::shared_ptr<GeomAPI_Shape> theShape)
67 if (myShape != theShape) {
68 if (!theShape.get() || !theShape->isEqual(myShape)) {
69 static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
70 ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), anEvent);
72 myFacesUpToDate = false;
80 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape()
85 Model_ResultConstruction::Model_ResultConstruction()
89 myFacesUpToDate = false;
92 void Model_ResultConstruction::setIsInHistory(const bool isInHistory)
94 myIsInHistory = isInHistory;
97 int Model_ResultConstruction::facesNum(const bool theUpdateNaming)
99 if (!myFacesUpToDate) {
100 std::shared_ptr<GeomAPI_PlanarEdges> aWirePtr =
101 std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(myShape);
102 if (aWirePtr.get()) {
103 std::list<std::shared_ptr<GeomAPI_Shape> > aFaces;
104 GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(),
105 aWirePtr->norm(), aWirePtr, aFaces);
106 std::list<std::shared_ptr<GeomAPI_Shape> >::iterator aFIter = aFaces.begin();
107 for(; aFIter != aFaces.end(); aFIter++) {
108 std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(*aFIter));
109 if (aFace.get() && !aFace->isNull())
110 myFaces.push_back(aFace);
113 myFacesUpToDate = true;
115 // update all the faces and sub-elements in the naming structure
116 if (theUpdateNaming) {
117 DocumentPtr anEmptyExt;
118 bool aNotExt = false;
119 TDF_Label aDataLab = startLabel(anEmptyExt, aNotExt);
120 TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
121 for(; aSubsIter.More(); aSubsIter.Next()) {
122 const TDF_Label aLab = aSubsIter.Value();
123 if (aLab.Tag() == 1) // skip the root shape label
125 Handle(TNaming_NamedShape) aNS;
126 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
127 update(aLab.Tag() - 1, anEmptyExt, aNotExt);
132 return int(myFaces.size());
135 std::shared_ptr<GeomAPI_Face> Model_ResultConstruction::face(const int theIndex)
137 return myFaces[theIndex];
140 bool Model_ResultConstruction::isInfinite()
145 void Model_ResultConstruction::setInfinite(const bool theInfinite)
147 myIsInfinite = theInfinite;
150 void Model_ResultConstruction::setIsConcealed(const bool theValue)
152 // do nothing: the construction element is never concealed
155 static const int kSTART_VERTEX_DELTA = 1000000;
157 static void registerSubShape(TDF_Label theMainLabel, TopoDS_Shape theShape, std::string theFullName,
158 const int theID, std::shared_ptr<Model_Document> theDoc,
159 bool theSelectionMode)
161 TDF_Label aLab = theID == 0 ? theMainLabel : theMainLabel.FindChild(theID);
162 TNaming_Builder aBuilder(aLab);
163 // wire never happens as sub, it must be generated to be found
164 // by SelectionNaming TNaming_Tool::NamedShape
165 if (theSelectionMode && theShape.ShapeType() != TopAbs_WIRE)
166 aBuilder.Select(theShape, theShape);
168 aBuilder.Generated(theShape);
170 theDoc->addNamingName(aLab, theFullName);
171 TDataStd_Name::Set(aLab, theFullName.c_str());
174 #include <TopTools_OrientedShapeMapHasher.hxx>
176 // generates a full-name for sub-element of the composite feature (sketch)
177 std::string fullName(CompositeFeaturePtr theComposite, const TopoDS_Shape& theSubShape,
178 Handle(TDataStd_IntPackedMap) theRefs = Handle(TDataStd_IntPackedMap)())
180 TopAbs_ShapeEnum aShapeType = theSubShape.ShapeType();
182 NCollection_Map<TopoDS_Edge> allExactEdges;
183 NCollection_DataMap<TopoDS_Edge, TopoDS_Edge, Model_EdgesHasher> allEdges;
184 NCollection_DataMap<Handle(Geom_Curve), TopoDS_Edge, Model_CurvesHasher> allCurves;
185 /// map from edges from theSubShape to the found corresponded indices of the sub-components
186 NCollection_DataMap<TopoDS_Edge, NCollection_List<int>, TopTools_OrientedShapeMapHasher>
187 anEdgesCorrespondence;
188 if (aShapeType == TopAbs_VERTEX) { // compare positions
189 aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(theSubShape));
191 for(TopExp_Explorer anEdgeExp(theSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
192 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
193 allExactEdges.Add(anEdge);
194 allEdges.Bind(anEdge, anEdge);
195 Standard_Real aFirst, aLast;
196 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
197 allCurves.Bind(aCurve, anEdge);
198 anEdgesCorrespondence.Bind(anEdge, NCollection_List<int>());
201 std::map<int, int> anOrientations; //map from edges IDs to orientations of these edges in face
202 std::map<int, std::string> aSubNames; //map from edges IDs to names of edges
203 TColStd_PackedMapOfInteger aRefs; // indixes of sub-elements in composite
206 const int aSubNum = theComposite->numberOfSubs();
207 for(int a = 0; a < aSubNum; a++) {
208 FeaturePtr aSub = theComposite->subFeature(a);
209 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
210 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
211 // there may be many shapes (circle and center): register if at least one is in selection
212 for(; aRes != aResults.cend(); aRes++) {
213 ResultConstructionPtr aConstr =
214 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
215 if (!aConstr->shape()) {
218 if (aShapeType == TopAbs_VERTEX) {
219 if (aConstr->shape()->isVertex()) { // compare vertices positions
220 const TopoDS_Shape& aVertex = aConstr->shape()->impl<TopoDS_Shape>();
221 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex));
222 if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
223 aRefs.Add(theComposite->subFeatureId(a));
224 aSubNames[theComposite->subFeatureId(a)] = Model_SelectionNaming::shortName(aConstr);
226 } else { // get first or last vertex of the edge: last is stored with additional delta
227 const TopoDS_Shape& anEdge = aConstr->shape()->impl<TopoDS_Shape>();
228 int aDelta = kSTART_VERTEX_DELTA;
229 for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
230 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current()));
231 if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) {
232 aRefs.Add(aDelta + theComposite->subFeatureId(a));
233 aSubNames[aDelta + theComposite->subFeatureId(a)] =
234 Model_SelectionNaming::shortName(aConstr, aDelta / kSTART_VERTEX_DELTA);
237 aDelta += kSTART_VERTEX_DELTA;
241 if (aConstr->shape()->isEdge()) {
242 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
243 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
246 if (allEdges.IsBound(anEdge)) {
247 anEdgesCorrespondence.ChangeFind(allEdges.Find(anEdge)).Append(a);
249 Standard_Real aFirst, aLast;
250 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
251 if (allCurves.IsBound(aCurve)) {
252 anEdgesCorrespondence.ChangeFind(allCurves.Find(aCurve)).Append(a);
260 if (aShapeType != TopAbs_VERTEX) { // get best candidates from the correspondances
261 NCollection_DataMap<TopoDS_Edge, NCollection_List<int>, TopTools_OrientedShapeMapHasher>
262 ::Iterator aCorIter(anEdgesCorrespondence);
263 for(; aCorIter.More(); aCorIter.Next()) {
264 TopoDS_Edge anOrig = aCorIter.Key();
265 NCollection_List<int>::Iterator aCandidate(aCorIter.Value());
268 ResultConstructionPtr aBestConstr;
269 for(; aCandidate.More(); aCandidate.Next()) {
270 FeaturePtr aSub = theComposite->subFeature(aCandidate.Value());
271 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
272 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
273 // there may be many shapes (circle and center): register if at least one is in selection
274 for(; aRes != aResults.cend(); aRes++) {
275 ResultConstructionPtr aConstr =
276 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
277 if (!aConstr->shape() || !aConstr->shape()->isEdge())
279 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
280 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
283 // detect score of the candidate
285 if (anEdge.IsEqual(anOrig))
287 else if (anEdge.IsSame(anOrig))
290 Standard_Real aFirst, aLast;
291 Handle(Geom_Curve) anOrigCurve = BRep_Tool::Curve(anOrig, aFirst, aLast);
292 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
293 if (anOrigCurve == aCurve) {
294 if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) {
300 if (Model_EdgesHasher::IsEqual(anEdge, anOrig)) {
302 } else if (Model_CurvesHasher::IsEqual(aCurve, anOrigCurve)) {
307 if (aScore > aBestScore) {
308 aBestIndex = aCandidate.Value();
310 aBestConstr = aConstr;
314 if (aBestIndex >= 0) {
315 int anID = theComposite->subFeatureId(aBestIndex);
317 aSubNames[anID] = Model_SelectionNaming::shortName(aBestConstr);
318 if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
319 // add edges to sub-label to support naming for edges selection
320 int anOrient = Model_SelectionNaming::edgeOrientation(theSubShape, anOrig);
321 anOrientations[anID] = anOrient;
326 std::stringstream aName;
327 // #1839 : do not store name of the feature in the tree, since this name could be changed
328 if (theSubShape.ShapeType() != TopAbs_COMPOUND) { // compound means the whole construction result
329 if (theSubShape.ShapeType() == TopAbs_FACE) aName<<"Face";
330 else if (theSubShape.ShapeType() == TopAbs_WIRE) aName<<"Wire";
331 else if (theSubShape.ShapeType() == TopAbs_EDGE) aName<<"Edge";
332 else if (theSubShape.ShapeType() == TopAbs_VERTEX) aName<<"Vertex";
334 // make a composite name from all sub-elements indexes: "1_2_3_4"
335 TColStd_MapIteratorOfPackedMapOfInteger aRef(aRefs);
336 for(; aRef.More(); aRef.Next()) {
337 aName<<"-"<<aSubNames[aRef.Key()];
338 if (anOrientations.find(aRef.Key()) != anOrientations.end()) {
339 if (anOrientations[aRef.Key()] == 1)
341 else if (anOrientations[aRef.Key()] == -1)
346 if (!theRefs.IsNull()) {
347 Handle(TColStd_HPackedMapOfInteger) aMap = new TColStd_HPackedMapOfInteger(aRefs);
348 theRefs->ChangeMap(aMap);
353 // stores shape and name on sub-label of the main stored shape
354 static void saveSubName(CompositeFeaturePtr theComposite,
355 TDF_Label& theLab, const bool isSelectionMode, TopoDS_Shape aSub,
356 std::shared_ptr<Model_Document> theDoc, std::string theFullName)
358 // trying to store the edge of composite result, not sketch sub as it is
359 if (aSub.ShapeType() == TopAbs_EDGE) {
360 ResultPtr aRes = theComposite->firstResult();
361 ResultConstructionPtr aConstr = std::dynamic_pointer_cast<Model_ResultConstruction>(aRes);
363 Standard_Real aSubFirst, aSubLast;
364 TopoDS_Edge aSubEdge = TopoDS::Edge(aSub);
365 Handle(Geom_Curve) aSubCurve = BRep_Tool::Curve(aSubEdge, aSubFirst, aSubLast);
366 for(int aFaceIndex = 0; aFaceIndex < aConstr->facesNum(); aFaceIndex++) {
367 GeomShapePtr aGFace = aConstr->face(aFaceIndex);
368 TopoDS_Shape aFace = aGFace->impl<TopoDS_Shape>();
369 for(TopExp_Explorer anExp(aFace, TopAbs_EDGE); anExp.More(); anExp.Next()) {
370 TopoDS_Edge anEdge = TopoDS::Edge(anExp.Current());
371 Standard_Real aFirst, aLast;
372 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
373 if (Model_CurvesHasher::IsEqual(aCurve, aSubCurve) &&
374 ((fabs(aFirst - aSubFirst) < 1.e-9 && fabs(aLast - aSubLast) < 1.e-9)) ||
375 (fabs(aFirst - aSubLast) < 1.e-9 && fabs(aLast - aSubFirst) < 1.e-9)) {
384 TNaming_Builder aBuilder(theLab);
386 aBuilder.Select(aSub, aSub);
388 aBuilder.Generated(aSub);
389 theDoc->addNamingName(theLab, theFullName.c_str());
390 TDataStd_Name::Set(theLab, theFullName.c_str());
394 TDF_Label Model_ResultConstruction::startLabel(
395 const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theExternal)
397 theExternal = theExtDoc.get() && theExtDoc != document();
398 if (theExternal) { // external document is used
399 std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(theExtDoc);
400 return aDoc->extConstructionsLabel();
402 std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
403 return aData->label();
406 int Model_ResultConstruction::select(const std::shared_ptr<GeomAPI_Shape>& theSubShape,
407 const std::shared_ptr<ModelAPI_Document> theExtDoc, const int theIndex)
409 int anIndex; // resulting index of the sub-label
410 TopoDS_Shape aSubShape;
411 if (theSubShape.get()) {
412 aSubShape = theSubShape->impl<TopoDS_Shape>();
413 } else if (shape().get()) {
414 aSubShape = shape()->impl<TopoDS_Shape>();
416 // if external document requires this selection, put the naming structures to this doc
417 // to support the naming mechanism in this document correctly
419 TDF_Label aDataLab = startLabel(theExtDoc, anExternal);
420 if (theIndex == -1) {
421 anIndex = anExternal ? 2 : 1; // for the external doc don't mind about the main shape
423 if (theSubShape.get() || anExternal) { // searching for already selected sub (or whole for ext)
424 // iterate all the already presented shapes to see the same
425 TDF_ChildIterator aSubsIter(aDataLab, Standard_False);
426 for(; aSubsIter.More(); aSubsIter.Next()) {
427 const TDF_Label aLab = aSubsIter.Value();
428 if (aLab.Tag() == 1) // skip the root shape label
430 Handle(TNaming_NamedShape) aNS;
431 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
432 if (aNS->Get().IsSame(aSubShape)) {
433 return aLab.Tag() - 1; // found exactly the needed shape, nothing else to do
436 anIndex = aLab.Tag(); // searching for the latest index
438 anIndex = (anIndex == 1) ? 2 : (anIndex + 1); // next after 1-root, or next after all
441 anIndex = theIndex + 1;
444 // set the naming structure at index
445 TDF_Label aLab = aDataLab.FindChild(anIndex, Standard_True);
447 // if the subshape is part of a result face, select the whole face (#1997)
448 bool isSelectionMode = false; // and other don't set shapes - all the naming is in face label
449 if (!aSubShape.IsNull() && aSubShape.ShapeType() > TopAbs_FACE) {
450 // but before check that sub-vertex correctly detected as intersection of sketch edges (#2389)
452 if (aSubShape.ShapeType() == TopAbs_VERTEX) {
454 ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
455 FeaturePtr aThisFeature = document()->feature(aThisPtr);
456 CompositeFeaturePtr aComposite =
457 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
458 if (aComposite.get()) {
459 const int aSubNum = aComposite->numberOfSubs();
460 for(int a = 0; a < aSubNum; a++) {
461 int aSubID = aComposite->subFeatureId(a);
462 FeaturePtr aSub = aComposite->subFeature(a);
463 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
464 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
465 for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
466 ResultConstructionPtr aConstr =
467 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
468 if (aConstr->shape() && aConstr->shape()->isEdge()) {
469 TopoDS_Shape aResShape = aConstr->shape()->impl<TopoDS_Shape>();
470 for(TopExp_Explorer anExp(aResShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) {
471 if (aSubShape.IsSame(anExp.Current())) {
481 if (anEdgesNum > 1) {
482 for(int aFaceIndex = 0; aFaceIndex < facesNum(); aFaceIndex++) {
483 TopExp_Explorer anExp(face(aFaceIndex)->impl<TopoDS_Shape>(), aSubShape.ShapeType());
484 for(; anExp.More(); anExp.Next()) {
485 if (aSubShape.IsSame(anExp.Current())) { // this is the case: select the whole face
486 // here just store the face index (to update face if update of edge is needed)
487 TNaming_Builder aBuilder(aLab);
488 aBuilder.Select(aSubShape, aSubShape);
489 int aFaceSelID = select(face(aFaceIndex), theExtDoc, -1);
490 TDF_Reference::Set(aLab, aLab.Father().FindChild(aFaceSelID));
491 isSelectionMode = true;
499 // external full result is not identified by index == 0, so, add here the ID
500 if (!theSubShape.get()) {
501 TDataStd_UAttribute::Set(aLab, kFULL_RESULT_ID);
503 TNaming_Builder aBuilder(aLab);
504 // store all sub-faces naming since faces may be used for extrusion, where all edges are needed
505 Handle(TDataStd_IntPackedMap) anIndices = TDataStd_IntPackedMap::Set(aLab);
506 std::list<int> aFacesIndexes;
507 for(int a = 0; a < facesNum(); a++) {
508 anIndices->Add(select(face(a), theExtDoc, -1));
513 { // this to have erased Builder after the shape was generated (NS on this label may be changed)
514 TNaming_Builder aBuilder(aLab);
515 if (aSubShape.IsNull()) {
516 return anIndex - 1; // just keep empty named shape
518 // wire never happens as sub, it must be generated to be found
519 // by SelectionNaming TNaming_Tool::NamedShape
520 if (isSelectionMode && aSubShape.ShapeType() != TopAbs_WIRE) {
521 aBuilder.Select(aSubShape, aSubShape);
523 aBuilder.Generated(aSubShape);
527 if (anIndex == 1 && isInfinite()) { // infinitive results has no sub-selection
530 ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
531 FeaturePtr aThisFeature = document()->feature(aThisPtr);
532 CompositeFeaturePtr aComposite =
533 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aThisFeature);
534 if (!aComposite || aComposite->numberOfSubs() == 0) {
535 // saving of context is enough: result construction contains exactly the needed shape
539 // identify the results of sub-object of the composite by edges
540 // save type of the selected shape in integer attribute
541 TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
542 TDataStd_Integer::Set(aLab, (int)aShapeType);
544 // curves of the sketch sub-elements are used, so, edges are not equal
545 TColStd_MapOfTransient allCurves;
546 if (aShapeType == TopAbs_VERTEX) { // compare positions
547 aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape));
549 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) {
550 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
551 Standard_Real aFirst, aLast;
552 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
553 allCurves.Add(aCurve);
556 std::shared_ptr<Model_Document> aMyDoc =
557 std::dynamic_pointer_cast<Model_Document>(document());
558 // iterate and store the result ids of sub-elements and sub-elements to sub-labels
559 Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab);
560 const int aSubNum = aComposite->numberOfSubs();
561 // subs are placed on unique labels because of #2248: sketch curve may produce several edges,
562 // but #2401 - on stable labels
563 NCollection_Map<int> aUsedIDMap; // already used lab tags for placement of shapes
565 for(int a = 0; a < aSubNum; a++) {
566 FeaturePtr aSub = aComposite->subFeature(a);
567 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
568 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
569 // there may be many shapes (circle and center): register if at least one is in selection
570 for(; aRes != aResults.cend(); aRes++) {
571 ResultConstructionPtr aConstr =
572 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
573 if (!aConstr->shape()) {
576 if (aShapeType != TopAbs_VERTEX) {
577 if (aConstr->shape()->isEdge()) {
578 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
579 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
580 if (!anEdge.IsNull()) {
581 Standard_Real aFirst, aLast;
582 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
583 if (allCurves.Contains(aCurve)) {
584 int anID = aComposite->subFeatureId(a);
585 if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
586 // add edges to sub-label to support naming for edges selection
587 TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
588 for(; anEdgeExp.More(); anEdgeExp.Next()) {
589 TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current());
590 Standard_Real aFirst, aLast;
591 Handle(Geom_Curve) aFaceCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
592 if (Model_CurvesHasher::IsEqual(aFaceCurve, aCurve)) {
593 while(aUsedIDMap.Contains(anID))
595 aUsedIDMap.Add(anID);
596 TDF_Label aSubLab = aLab.FindChild(anID);
597 std::string aFullNameSub = fullName(aComposite, anEdge);
598 saveSubName(aComposite, aSubLab, isSelectionMode, anEdge, aMyDoc, aFullNameSub);
600 int anOrient = Model_SelectionNaming::edgeOrientation(aSubShape, anEdge);
602 // store the orientation of edge relatively to face if needed
603 TDataStd_Integer::Set(aSubLab, anOrient);
607 } else { // put vertices of the selected edge to sub-labels
608 // add edges to sub-label to support naming for edges selection
609 for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_VERTEX);
610 anEdgeExp.More(); anEdgeExp.Next()) {
611 TopoDS_Vertex aV = TopoDS::Vertex(anEdgeExp.Current());
612 while(aUsedIDMap.Contains(anID))
614 aUsedIDMap.Add(anID);
615 TDF_Label aSubLab = aLab.FindChild(anID);
616 std::string aFullNameSub = fullName(aComposite, aV);
617 saveSubName(aComposite, aSubLab, isSelectionMode, aV, aMyDoc, aFullNameSub);
626 std::string aFullName = fullName(aComposite, aSubShape, aRefs);
627 // store the selected as primitive
628 registerSubShape(aLab, aSubShape, aFullName, 0, aMyDoc, isSelectionMode);
632 std::shared_ptr<GeomAPI_Shape> Model_ResultConstruction::shape(const int theIndex,
633 const std::shared_ptr<ModelAPI_Document> theExtDoc)
635 std::shared_ptr<GeomAPI_Shape> aResult;
637 return aResult; // the whole shape, so, NULL
640 TDF_Label aLab = startLabel(theExtDoc, isExt).FindChild(theIndex + 1);
641 if (!aLab.IsNull()) { // index is not bad
642 Handle(TNaming_NamedShape) aSelection;
643 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
644 TopoDS_Shape aSelShape = aSelection->Get();
645 if (aSelShape.IsNull())
646 return aResult; // shape equal to context => null
647 aResult = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
648 aResult->setImpl(new TopoDS_Shape(aSelShape));
655 bool Model_ResultConstruction::update(const int theIndex,
656 const std::shared_ptr<ModelAPI_Document> theExtDoc, bool& theModified)
660 TDF_Label aLab = startLabel(theExtDoc, anExt).FindChild(theIndex + 1, Standard_True);
661 if (theIndex == 0 || aLab.IsAttribute(kFULL_RESULT_ID)) { // full for external same as index == 0
662 // it is just reference to construction, not sub-shape
663 // if there is a sketch, the sketch-naming must be updated
665 // update all faces named by the whole result
667 Handle(TDataStd_IntPackedMap) anIndices;
668 if (aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), anIndices)) {
669 NCollection_Map<TopoDS_Shape> aFaces; // collect faces, updated in the tree
670 TColStd_MapIteratorOfPackedMapOfInteger anIndexIter(anIndices->GetMap());
671 Handle(TColStd_HPackedMapOfInteger) aNewPackedMap =
672 new TColStd_HPackedMapOfInteger; // with only faces that are ok
673 // iterate to find existing faces, updated
674 for(; anIndexIter.More(); anIndexIter.Next()) {
675 if (update(anIndexIter.Key(), theExtDoc, theModified)) {
676 GeomShapePtr aFace = shape(anIndexIter.Key(), theExtDoc);
677 if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
678 aNewPackedMap->ChangeMap().Add(anIndexIter.Key());
679 aFaces.Add(aFace->impl<TopoDS_Shape>());
683 // then iterate all existing faces to find new faces
684 int aCurrentFacesNum = facesNum();
685 for(int a = 0; a < aCurrentFacesNum; a++) {
686 GeomShapePtr aFace = face(a);
687 if (!aFaces.Contains(aFace->impl<TopoDS_Shape>())) {
689 int aNewFaceIndex = select(aFace, theExtDoc, -1);
690 if (aNewFaceIndex > 0) {
691 aNewPackedMap->ChangeMap().Add(aNewFaceIndex);
695 anIndices->ChangeMap(aNewPackedMap);
699 // check is this modified or not
700 std::shared_ptr<GeomAPI_Shape> aNewShape = shape();
701 TopoDS_Shape anOldSh;
702 Handle(TNaming_NamedShape) aNS;
703 if (aLab.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
704 anOldSh = aNS->Get();
706 if (aNewShape.get()) {
707 if (anOldSh.IsNull())
710 std::shared_ptr<GeomAPI_Shape> anOldShape(new GeomAPI_Shape);
711 anOldShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(anOldSh));
712 theModified = !anOldShape->isEqual(aNewShape);
715 else if (!anOldSh.IsNull()) {
719 // For correct naming selection, put the shape into the naming structure.
720 // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
721 TNaming_Builder aBuilder(aLab);
722 aBuilder.Generated(aNewShape->impl<TopoDS_Shape>());
724 return shape() && !shape()->isNull();
726 // construction: identification by the results indexes, recompute faces and
727 // take the face that more close by the indexes
728 ResultPtr aThisPtr = std::dynamic_pointer_cast<ModelAPI_Result>(data()->owner());
729 FeaturePtr aContextFeature = document()->feature(aThisPtr);
731 // sketch sub-element
732 if (std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature).get())
734 // update the referenced object if it is sub
735 Handle(TDF_Reference) aRef;
736 if (aLab.FindAttribute(TDF_Reference::GetID(), aRef)) {
737 int aFaceIndex = aRef->Get().Tag();
738 // don't check selection since face may disappear, but the shape stays correct
739 Model_ResultConstruction::update(aFaceIndex, theExtDoc, theModified);
741 // getting a type of selected shape
742 Handle(TDataStd_Integer) aTypeAttr;
743 if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
746 TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
747 // selected indexes will be needed in each "if"
748 Handle(TDataStd_IntPackedMap) aSubIds;
749 std::shared_ptr<GeomAPI_Shape> aNewSelected;
751 !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0;
752 // for now working only with composite features
753 CompositeFeaturePtr aComposite =
754 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
755 if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
759 if (aShapeType == TopAbs_FACE || aShapeType == TopAbs_WIRE) {
760 // compound is for the whole sketch selection
761 // If this is a wire with plane defined then it is a sketch-like object
762 if (!facesNum()) // no faces, update can not work correctly
764 // if there is no edges indexes, any face can be used: take the first
765 std::shared_ptr<GeomAPI_Shape> aNewSelected;
767 aNewSelected = face(0);
768 } else { // searching for most looks-like initial face by the indexes
769 // prepare edges of the current result for the fast searching
770 // curves and orientations of edges
771 NCollection_DataMap<Handle(Geom_Curve), int, Model_CurvesHasher> allCurves;
772 const int aSubNum = aComposite->numberOfSubs();
773 for(int a = 0; a < aSubNum; a++) {
774 int aSubID = aComposite->subFeatureId(a);
775 if (aSubIds->Contains(aSubID)) {
776 FeaturePtr aSub = aComposite->subFeature(a);
777 const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
778 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
779 for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
780 ResultConstructionPtr aConstr =
781 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
782 if (aConstr->shape() && aConstr->shape()->isEdge()) {
783 const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
784 TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
785 if (!anEdge.IsNull()) {
786 Standard_Real aFirst, aLast;
787 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
788 // searching for orientation information
790 Handle(TDataStd_Integer) anInt;
791 if (aLab.FindChild(aSubID).FindAttribute(TDataStd_Integer::GetID(), anInt)) {
792 anOrient = anInt->Get();
794 allCurves.Bind(aCurve, anOrient);
800 aNewSelected = Model_SelectionNaming::findAppropriateFace(
801 aThisPtr, allCurves, aShapeType == TopAbs_WIRE);
803 if (aNewSelected) { // store this new selection
804 select(aNewSelected, theExtDoc, theIndex);
808 // if the selection is not found, put the empty shape:
809 // it's better to have disappeared shape, than the old, the lost one
810 TNaming_Builder anEmptyBuilder(aLab);
813 } else if (aShapeType == TopAbs_EDGE) {
814 // just reselect the edge by the id
815 const int aSubNum = aComposite->numberOfSubs();
816 for(int a = 0; a < aSubNum; a++) {
817 // if aSubIds take any, the first appropriate
818 if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) {
819 // found the appropriate feature
820 FeaturePtr aFeature = aComposite->subFeature(a);
821 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
822 aFeature->results().cbegin();
823 for(;aResIter != aFeature->results().cend(); aResIter++) {
824 ResultConstructionPtr aRes =
825 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
826 if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
827 select(aRes->shape(), theExtDoc, theIndex);
834 } else if (aShapeType == TopAbs_VERTEX) {
835 // just reselect the vertex by the id of edge
836 const int aSubNum = aComposite->numberOfSubs();
837 for(int a = 0; a < aSubNum; a++) {
838 // if aSubIds take any, the first appropriate
839 int aFeatureID = aComposite->subFeatureId(a);
840 if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID) ||
841 aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA) ||
842 aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) {
843 // searching for deltas
845 if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1;
846 else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA * 2)) aVertexNum = 2;
847 // found the feature with appropriate edge
848 FeaturePtr aFeature = aComposite->subFeature(a);
849 std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aResIter =
850 aFeature->results().cbegin();
851 for(;aResIter != aFeature->results().cend(); aResIter++) {
852 ResultConstructionPtr aRes =
853 std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aResIter);
854 if (aRes && aRes->shape()) {
855 if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
856 select(aRes->shape(), theExtDoc, theIndex);
859 } else if (aRes->shape()->isEdge() && aVertexNum > 0) {
860 const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
862 for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) {
863 if (aVIndex == aVertexNum) { // found!
864 std::shared_ptr<GeomAPI_Shape> aVertex(new GeomAPI_Shape);
865 aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
866 select(aVertex, theExtDoc, theIndex);
878 } else { // simple construction element: the selected is that needed
879 select(shape(), theExtDoc, theIndex);
883 return false; // unknown case