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 <Selector_Algo.h>
23 #include <Selector_Primitive.h>
24 #include <Selector_Intersect.h>
25 #include <Selector_Modify.h>
26 #include <Selector_Container.h>
27 #include <Selector_FilterByNeighbors.h>
28 #include <Selector_WeakName.h>
30 #include <TDF_Tool.hxx>
31 #include <TopoDS_Face.hxx>
32 #include <TopoDS_Edge.hxx>
34 #include <Geom_Surface.hxx>
35 #include <BRep_Tool.hxx>
36 #include <TNaming_Builder.hxx>
37 #include <TNaming_Tool.hxx>
38 #include <TNaming_SameShapeIterator.hxx>
39 #include <TNaming_Iterator.hxx>
40 #include <TDataStd_ReferenceArray.hxx>
41 #include <TDataStd_ExtStringList.hxx>
42 #include <TDataStd_Integer.hxx>
43 #include <TDataStd_UAttribute.hxx>
46 /// type of the selection, integer keeps the Selector_Type value
47 static const Standard_GUID kSEL_TYPE("db174d59-c2e3-4a90-955e-55544df090d6");
48 // geometrical naming indicator
49 static const Standard_GUID kGEOMETRICAL_NAMING("a5322d02-50fb-43ed-9255-75c7b93f6657");
52 // reference attribute that contains the reference to labels where the "from" or "base" shapes
53 // of selection are located
54 static const Standard_GUID kBASE_ARRAY("7c515b1a-9549-493d-9946-a4933a22f45f");
55 // if the base array contains reference to the root label, this means that it refers to an
56 // external document and this list contains a tag in the document
57 static const Standard_GUID kBASE_LIST("7c515b1a-9549-493d-9946-a4933a22f45a");
59 Selector_Algo::Selector_Algo()
61 myGeometricalNaming = false; // default values
62 myAlwaysGeometricalNaming = false;
65 #define SET_ALGO_FLAGS(algo) \
66 algo->myLab = theAccess; \
67 algo->myBaseDocumentLab = theBaseDocument; \
68 algo->myGeometricalNaming = theGeometricalNaming; \
69 algo->myUseNeighbors = theUseNeighbors; \
70 algo->myUseIntersections = theUseIntersections; \
71 algo->myAlwaysGeometricalNaming = theAlwaysGeometricalNaming;
73 Selector_Algo* Selector_Algo::select(const TopoDS_Shape theContext, const TopoDS_Shape theValue,
74 const TDF_Label theAccess, const TDF_Label theBaseDocument,
75 const bool theGeometricalNaming, const bool theUseNeighbors, const bool theUseIntersections,
76 const bool theAlwaysGeometricalNaming)
78 Selector_Algo* aResult = NULL;
79 if (theValue.IsNull() || theContext.IsNull())
82 // check the value shape can be named as it is, or it is needed to construct it from the
83 // higher level shapes (like a box vertex by faces that form this vertex)
84 bool aIsFound = TNaming_Tool::HasLabel(theAccess, theValue);
85 if (aIsFound) { // additional check for selection and delete evolution only: also could not use
87 for(TNaming_SameShapeIterator aShapes(theValue, theAccess); aShapes.More(); aShapes.Next())
89 Handle(TNaming_NamedShape) aNS;
90 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
91 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
92 aNS->Evolution() == TNaming_PRIMITIVE) {
99 // searching in the base document
100 if (!aIsFound && !theBaseDocument.IsNull() && TNaming_Tool::HasLabel(theBaseDocument, theValue))
102 TNaming_SameShapeIterator aShapes(theValue, theBaseDocument);
103 for(; aShapes.More(); aShapes.Next())
105 Handle(TNaming_NamedShape) aNS;
106 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
107 if (aNS->Evolution() == TNaming_MODIFY || aNS->Evolution() == TNaming_GENERATED ||
108 aNS->Evolution() == TNaming_PRIMITIVE) {
116 TopAbs_ShapeEnum aSelectionType = theValue.ShapeType();
117 if (aSelectionType == TopAbs_COMPOUND || aSelectionType == TopAbs_COMPSOLID ||
118 aSelectionType == TopAbs_SHELL || aSelectionType == TopAbs_WIRE)
120 Selector_Container* aContainer = new Selector_Container;
121 SET_ALGO_FLAGS(aContainer);
122 if (aContainer->select(theContext, theValue))
128 Selector_Intersect* anIntersect = new Selector_Intersect;
129 SET_ALGO_FLAGS(anIntersect);
130 bool aGoodIntersector = anIntersect->select(theContext, theValue);
131 // weak intersector is bad for not use neighbors and has lower priority than neighbors
132 if (aGoodIntersector && anIntersect->myWeakIndex == -1) {
135 if (!theUseNeighbors) {
139 // searching by neighbors
140 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
141 SET_ALGO_FLAGS(aNBs);
142 if (aNBs->select(theContext, theValue)) {
147 if (aGoodIntersector) { // if neighbors are bad, use intersector with weak index
152 // pure weak naming: there is no sense to use pure weak naming for neighbors selection
153 if (theUseNeighbors) {
154 Selector_WeakName* aWeak = new Selector_WeakName;
155 SET_ALGO_FLAGS(aWeak);
156 if (aWeak->select(theContext, theValue)) {
161 return NULL; // not found value in the tree, not found context shape in the tree also
163 // searching for the base shapes of the value
164 Handle(TNaming_NamedShape) aPrimitiveNS;
165 NCollection_List<Handle(TNaming_NamedShape)> aModifList;
166 for(int aUseExternal = 0; aUseExternal < 2; aUseExternal++) {
167 TDF_Label aLab = aUseExternal == 0 ? theAccess : theBaseDocument;
168 if (aLab.IsNull() || !TNaming_Tool::HasLabel(aLab, theValue))
170 for(TNaming_SameShapeIterator aShapes(theValue, aLab); aShapes.More(); aShapes.Next())
172 Handle(TNaming_NamedShape) aNS;
173 if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
174 TNaming_Evolution anEvolution = aNS->Evolution();
175 if (anEvolution == TNaming_PRIMITIVE) { // the value shape is declared as PRIMITIVE
178 } else if (anEvolution == TNaming_GENERATED || anEvolution == TNaming_MODIFY) {
179 // check this is a new shape
180 TNaming_Iterator aNSIter(aNS);
181 for(; aNSIter.More(); aNSIter.Next())
182 if (aNSIter.NewShape().IsSame(theValue))
184 if (aNSIter.More()) // new was found
185 aModifList.Append(aNS);
191 if (!aPrimitiveNS.IsNull()) {
192 Selector_Primitive* aPrimitive = new Selector_Primitive;
193 SET_ALGO_FLAGS(aPrimitive);
194 aPrimitive->select(aPrimitiveNS->Label());
197 Selector_Modify* aModify = new Selector_Modify;
198 SET_ALGO_FLAGS(aModify);
199 bool aGoodModify = aModify->select(aModifList, theContext, theValue);
200 // weak intersector is bad for not use neighbors and has lower priority than neighbors
201 if (aGoodModify && aModify->myWeakIndex == -1) {
204 if (!theUseNeighbors) {
208 // searching by neighbors
209 Selector_FilterByNeighbors* aNBs = new Selector_FilterByNeighbors;
210 SET_ALGO_FLAGS(aNBs);
211 if (aNBs->select(theContext, theValue)) {
217 if (aGoodModify) { // if neighbors are bad, use modify algo with weak index
223 return NULL; // invalid case
226 Selector_Algo* Selector_Algo::relesectWithAllGeometry(
227 Selector_Algo* theOldAlgo, const TopoDS_Shape theContext)
229 return select(theContext, theOldAlgo->value(),
230 theOldAlgo->myLab, theOldAlgo->myBaseDocumentLab, true, true, true, true);
233 void Selector_Algo::storeBaseArray(const TDF_LabelList& theRef, const TDF_Label& theLast)
235 Handle(TDataStd_ReferenceArray) anArray =
236 TDataStd_ReferenceArray::Set(myLab, kBASE_ARRAY, 0, theRef.Extent());
237 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
238 const TDF_Label aThisDocRoot = myLab.Root();
239 TDF_LabelList::Iterator aBIter(theRef);
240 for(int anIndex = 0; true; aBIter.Next(), anIndex++) {
241 const TDF_Label& aLab = aBIter.More() ? aBIter.Value() : theLast;
242 // check this is a label of this document
243 if (aLab.Root().IsEqual(aThisDocRoot)) {
244 anArray->SetValue(anIndex, aLab);
245 } else { // store reference to external document as an entry-string
246 if (anEntries.IsNull()) {
247 anEntries = TDataStd_ExtStringList::Set(myLab, kBASE_LIST);
249 TCollection_AsciiString anEntry;
250 TDF_Tool::Entry(aLab, anEntry);
251 anEntries->Append(anEntry);
252 anArray->SetValue(anIndex, aThisDocRoot); // stored root means it is external reference
259 bool Selector_Algo::restoreBaseArray(TDF_LabelList& theRef, TDF_Label& theLast)
261 const TDF_Label aThisDocRoot = myLab.Root();
262 Handle(TDataStd_ExtStringList) anEntries; // entries of references to external document
263 TDataStd_ListOfExtendedString::Iterator anIter;
264 Handle(TDataStd_ReferenceArray) anArray;
265 if (myLab.FindAttribute(kBASE_ARRAY, anArray)) {
266 int anUpper = anArray->Upper();
267 for(int anIndex = anArray->Lower(); anIndex <= anUpper; anIndex++) {
268 TDF_Label aLab = anArray->Value(anIndex);
269 if (aLab.IsEqual(aThisDocRoot)) { // external document reference
270 if (myBaseDocumentLab.IsNull())
272 if (anEntries.IsNull()) {
273 if (!myLab.FindAttribute(kBASE_LIST, anEntries))
275 anIter.Initialize(anEntries->List());
279 TDF_Tool::Label(myBaseDocumentLab.Data(), anIter.Value(), aLab);
282 if (anIndex == anUpper) {
293 void Selector_Algo::store(const TopoDS_Shape theShape)
295 TNaming_Builder aBuilder(myLab);
296 aBuilder.Select(theShape, theShape);
299 bool Selector_Algo::sameGeometry(const TopoDS_Shape theShape1, const TopoDS_Shape theShape2) {
300 if (!theShape1.IsNull() && !theShape2.IsNull() && theShape1.ShapeType() == theShape2.ShapeType())
302 if (theShape1.ShapeType() == TopAbs_FACE) { // check surfaces
303 TopLoc_Location aLoc1, aLoc2;
304 TopoDS_Face aFace1 = TopoDS::Face(theShape1);
305 Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1, aLoc1);
306 TopoDS_Face aFace2 = TopoDS::Face(theShape2);
307 Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2, aLoc2);
308 return aSurf1 == aSurf2 && aLoc1.IsEqual(aLoc2);
309 } else if (theShape1.ShapeType() == TopAbs_EDGE) { // check curves
310 TopLoc_Location aLoc1, aLoc2;
311 Standard_Real aFirst, aLast;
312 TopoDS_Edge anEdge1 = TopoDS::Edge(theShape1);
313 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aLoc1, aFirst, aLast);
314 TopoDS_Edge anEdge2 = TopoDS::Edge(theShape2);
315 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aLoc2, aFirst, aLast);
316 return aCurve1 == aCurve2 && aLoc1.IsEqual(aLoc2);
322 TopoDS_Shape Selector_Algo::value()
324 Handle(TNaming_NamedShape) aNS;
325 if (myLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
327 return TopoDS_Shape(); // empty, error shape
330 Selector_Algo* Selector_Algo::restoreByLab(TDF_Label theLab, TDF_Label theBaseDocLab)
332 Handle(TDataStd_Integer) aTypeAttr;
333 if (!theLab.FindAttribute(kSEL_TYPE, aTypeAttr))
335 Selector_Type aType = Selector_Type(aTypeAttr->Get());
336 Selector_Algo* aResult = NULL;
338 case SELTYPE_CONTAINER: {
339 aResult = new Selector_Container;
342 case SELTYPE_INTERSECT: {
343 aResult = new Selector_Intersect;
346 case SELTYPE_MODIFICATION: {
347 aResult = new Selector_Modify;
350 case SELTYPE_PRIMITIVE: {
351 aResult = new Selector_Primitive;
354 case SELTYPE_FILTER_BY_NEIGHBOR: {
355 aResult = new Selector_FilterByNeighbors;
358 case SELTYPE_WEAK_NAMING: {
359 aResult = new Selector_WeakName;
362 default: { // unknown case
366 aResult->myLab = theLab;
367 aResult->myBaseDocumentLab = theBaseDocLab;
368 aResult->myGeometricalNaming = theLab.IsAttribute(kGEOMETRICAL_NAMING);
369 if (!aResult->restore()) {
377 Selector_Algo* Selector_Algo::restoreByName(TDF_Label theLab, TDF_Label theBaseDocLab,
378 std::string theName, const TopAbs_ShapeEnum theShapeType,
379 Selector_NameGenerator* theNameGenerator, TDF_Label& theContextLab)
381 Selector_Algo* aResult = NULL;
382 if (theName[0] == '[') { // intersection or container
383 switch(theShapeType) {
384 case TopAbs_COMPOUND:
385 case TopAbs_COMPSOLID:
388 aResult = new Selector_Container;
393 aResult = new Selector_Intersect;
397 } else if (theName[0] == '(') { // filter by neighbors
398 aResult = new Selector_FilterByNeighbors;
399 } else if (theName.find(pureWeakNameID()) == 0) { // weak naming identifier
400 aResult = new Selector_WeakName;
401 } else if (theName.find('&') != std::string::npos) { // modification
402 aResult = new Selector_Modify;
403 } else { // primitive
404 aResult = new Selector_Primitive;
407 aResult->myLab = theLab;
408 aResult->myBaseDocumentLab = theBaseDocLab;
409 theContextLab = aResult->restoreByName(theName, theShapeType, theNameGenerator);
410 if (theContextLab.IsNull()) {
418 void Selector_Algo::storeType(const Selector_Type theType)
420 TDataStd_Integer::Set(myLab, kSEL_TYPE, (int)(theType));
421 if (myGeometricalNaming)
422 TDataStd_UAttribute::Set(myLab, kGEOMETRICAL_NAMING);