Salome HOME
Minor fix: checked on edition of extrusion-cut sketch: extrusion cut result should...
[modules/shaper.git] / src / PartSet / PartSet_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_Validators.cpp
4 // Created:     09 July 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_Validators.h"
8
9 #include "PartSet_Tools.h"
10
11 #include <TopoDS.hxx>
12 #include <TopoDS_Edge.hxx>
13 #include <BRep_Tool.hxx>
14 #include <GeomAdaptor_Curve.hxx>
15 #include <GeomAbs_CurveType.hxx>
16 #include <GeomValidators_Tools.h>
17 #include <ModuleBase_ISelection.h>
18 #include <ModuleBase_WidgetShapeSelector.h>
19
20 #include <ModelAPI_AttributeRefAttr.h>
21 #include <ModelAPI_AttributeSelection.h>
22 #include <ModelAPI_AttributeReference.h>
23 #include <ModelAPI_AttributeSelectionList.h>
24 #include <ModelAPI_AttributeRefList.h>
25 #include <ModelAPI_Object.h>
26 #include <ModelAPI_Session.h>
27 #include <ModelAPI_Tools.h>
28
29 #include <SketchPlugin_Sketch.h>
30 #include <SketchPlugin_ConstraintCoincidence.h>
31 #include <SketchPlugin_Arc.h>
32 #include <GeomAPI_Edge.h>
33
34 #include <list>
35 #ifdef _DEBUG
36 #include <iostream>
37 #endif
38
39 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
40 {
41   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
42   int aCount = 0;
43   foreach (ModuleBase_ViewerPrs aPrs, aList) {
44     const TopoDS_Shape& aShape = aPrs.shape();
45     if (!aShape.IsNull()) {
46       if (aShape.ShapeType() == TopAbs_VERTEX)
47         aCount++;
48     }
49   }
50   return aCount;
51 }
52
53 int shapesNbLines(const ModuleBase_ISelection* theSelection)
54 {
55   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
56   int aCount = 0;
57   foreach(ModuleBase_ViewerPrs aPrs, aList) {
58     const TopoDS_Shape& aShape = aPrs.shape();
59     if (!aShape.IsNull()) {
60       if (aShape.ShapeType() == TopAbs_EDGE) {
61         TopoDS_Edge aEdge = TopoDS::Edge(aShape);
62         Standard_Real aStart, aEnd;
63         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
64         GeomAdaptor_Curve aAdaptor(aCurve);
65         if (aAdaptor.GetType() == GeomAbs_Line)
66           aCount++;
67       }
68     }
69   }
70   return aCount;
71 }
72
73 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection) const
74 {
75   int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
76   return (aCount > 0) && (aCount < 3);
77 }
78
79 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection) const
80 {
81   int aCount = shapesNbLines(theSelection);
82   return (aCount == 1);
83 }
84
85 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection) const
86 {
87   int aCount = shapesNbLines(theSelection);
88   return (aCount > 0) && (aCount < 3);
89 }
90
91 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection) const
92 {
93   int aCount = shapesNbLines(theSelection);
94   return (aCount > 0) && (aCount < 3);
95 }
96
97 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection) const
98 {
99   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
100   ModuleBase_ViewerPrs aPrs;
101   int aCount = 0;
102   foreach (ModuleBase_ViewerPrs aPrs, aList) {
103     const TopoDS_Shape& aShape = aPrs.shape();
104     if (!aShape.IsNull()) {
105       if (aShape.ShapeType() == TopAbs_EDGE) {
106         TopoDS_Edge aEdge = TopoDS::Edge(aShape);
107         Standard_Real aStart, aEnd;
108         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
109         GeomAdaptor_Curve aAdaptor(aCurve);
110         if (aAdaptor.GetType() == GeomAbs_Circle)
111           aCount++;
112       }
113     }
114   }
115   return (aCount == 1);
116 }
117
118 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection) const
119 {
120   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
121   return (aList.count() == 1);
122 }
123
124
125 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection) const
126 {
127   // Coincident can be applied to points and to lines
128   int aCount = shapesNbPoints(theSelection);
129   aCount += shapesNbLines(theSelection);
130   return (aCount > 0) && (aCount < 3);
131 }
132
133 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection) const
134 {
135   int aCount = shapesNbLines(theSelection);
136   return (aCount == 1);
137 }
138
139 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection) const
140 {
141   int aCount = shapesNbLines(theSelection);
142   return (aCount > 0) && (aCount < 3);
143 }
144
145 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection) const
146 {
147   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
148   if ((aList.size() == 0) || (aList.size() > 2))
149     return false;
150
151   ModuleBase_ViewerPrs aPrs = aList.first();
152   const TopoDS_Shape& aShape = aPrs.shape();
153   if (aShape.IsNull())
154     return false;
155
156   if (aShape.ShapeType() != TopAbs_EDGE)
157     return false;
158
159   std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
160   aShapePtr->setImpl(new TopoDS_Shape(aShape));
161   GeomAPI_Edge aEdge1(aShapePtr);
162
163   if (aEdge1.isLine() || aEdge1.isArc()) {
164     if (aList.size() == 2) {
165       // Check second selection
166       aPrs = aList.last();
167       const TopoDS_Shape& aShape2 = aPrs.shape();
168       if (aShape2.IsNull())
169         return false;
170
171       if (aShape2.ShapeType() != TopAbs_EDGE)
172         return false;
173
174       std::shared_ptr<GeomAPI_Shape> aShapePtr2(new GeomAPI_Shape);
175       aShapePtr2->setImpl(new TopoDS_Shape(aShape2));
176       GeomAPI_Edge aEdge2(aShapePtr2);
177       if (aEdge1.isLine() && aEdge2.isArc())
178         return true;
179       else if (aEdge1.isArc() && aEdge2.isLine())
180         return true;
181       else
182         return false;
183     } else
184       return true;
185   }
186   return false;
187 }
188
189 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection) const
190 {
191   int aCount = shapesNbLines(theSelection);
192   return (aCount > 0) && (aCount < 3);
193 }
194
195 std::string PartSet_DifferentObjectsValidator::errorMessage(
196                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
197                          const std::string& thEqualObject, const std::string& theFirstAttribute,
198                          const std::string& theSecondAttribute) const
199 {
200   std::string anError;
201   switch (theType) {
202     case EqualObjects:
203       anError = "The feature uses one " + thEqualObject + " object in " +
204                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
205       break;
206     case EqualAttributes:
207       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
208                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
209       break;
210     case EqualShapes:
211       anError = "The feature uses one shape in " +
212                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
213       break;
214     case EmptyShapes:
215       anError = "The feature uses empty shapes in " +
216                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
217       break;
218       break;
219     default:
220       break;
221   }
222   return anError;
223 }
224
225 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
226                                                 const std::list<std::string>& theArguments,
227                                                 std::string& theError) const
228 {
229   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
230
231   // the type of validated attributes should be equal, attributes with different types are not validated
232   // Check RefAttr attributes
233   std::string anAttrType = theAttribute->attributeType();
234   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
235
236   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
237     AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
238     bool isObject = anAttr->isObject();
239     ObjectPtr anObject = anAttr->object();
240     AttributePtr anAttributeAttr = anAttr->attr();
241
242     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
243     if (anAttrs.size() > 0) {
244       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
245       for(; anAttr != anAttrs.end(); anAttr++) {
246       if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
247           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
248                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
249           if (aRef->isObject() != isObject)
250             continue;
251           if (isObject) {
252             if (aRef->object() == anObject) {
253               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
254                                       theAttribute->id(), aRef->id());
255               return false;
256             }
257           }
258           else { // the attribute reference
259             if (aRef->attr() == anAttributeAttr) {
260               theError = errorMessage(EqualAttributes,
261                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
262                                       theAttribute->id(), aRef->id());
263               return false;
264             }
265           }
266         }
267       }
268     }
269   }
270   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
271     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
272     ResultPtr aContext = anAttr->context();
273     GeomShapePtr aShape = anAttr->value();
274
275     // Check selection attributes
276     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
277     if (anAttrs.size() > 0) {
278       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
279       for(; anAttr != anAttrs.end(); anAttr++) {
280         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
281           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
282                                         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
283           // check the object is already presented
284           if (aRef->context() == aContext) {
285             bool aHasShape = aShape.get() != NULL;
286             if (!aHasShape || aRef->value()->isEqual(aShape)) {
287               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
288               return false;
289             }
290           }
291         }
292       }
293     }
294   }
295   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
296     AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
297     ObjectPtr anObject = anAttr->value();
298     // Check selection attributes
299     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
300     if (anAttrs.size() > 0) {
301       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
302       for(; anAttr != anAttrs.end(); anAttr++) {
303         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
304           std::shared_ptr<ModelAPI_AttributeReference> aRef =
305             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
306           // check the object is already presented
307           if (aRef->value() == anObject) {
308             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
309                                     theAttribute->id(), aRef->id());
310             return false;
311           }
312         }
313         return true;
314       }
315     }
316   }
317   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
318     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList = 
319             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
320     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
321     if(anAttrs.size() > 0) {
322       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
323       for(; anAttrItr != anAttrs.end(); anAttrItr++){
324         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
325           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList = 
326             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
327           for(int i = 0; i < aCurSelList->size(); i++) {
328             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
329             ResultPtr aCurSelContext = aCurSel->context();
330             ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
331             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
332             if(aCurSelCompSolidPtr.get()) {
333               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
334             }
335             for(int j = 0; j < aRefSelList->size(); j++) {
336               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
337               ResultPtr aRefSelContext = aRefSel->context();
338               ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
339               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
340               if(aRefSelCompSolidPtr.get()) {
341                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
342               }
343               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
344                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
345                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
346                                           aRefSel->id());
347                   return false;
348               }
349               if(aCurSelContext == aRefSelContext) {
350                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
351                   theError = errorMessage(EmptyShapes, "", theAttribute->id(),
352                                           aRefSel->id());
353                   return false;
354                 }
355                 if (aCurSel->value()->isEqual(aRefSel->value())) {
356                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
357                                           aRefSel->id());
358                   return false;
359                 }
360               }
361             }
362           }
363         }
364       }
365     }
366   }
367   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
368     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
369       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
370     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
371     if (anAttrs.size() > 0) {
372       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
373       for (; anAttrItr != anAttrs.end(); anAttrItr++){
374         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
375           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
376             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
377           for (int i = 0; i < aCurSelList->size(); i++) {
378             ObjectPtr aCurSelObject = aCurSelList->object(i);
379             for (int j = 0; j < aRefSelList->size(); j++) {
380               if (aCurSelObject == aRefSelList->object(j)) {
381                 theError = errorMessage(EqualObjects,
382                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
383                               theAttribute->id(), aCurSelList->id());
384                 return false;
385               }
386             }
387           }
388         }
389       }
390     }
391   }
392   return true;
393 }
394
395 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
396                                             const std::list<std::string>& theArguments,
397                                             std::string& theError) const
398 {
399   bool isSketchEntities = true;
400   std::set<std::string> anEntityKinds;
401   std::string anEntityKindsStr;
402   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
403   for (; anIt != aLast; anIt++) {
404     anEntityKinds.insert(*anIt);
405     if (!anEntityKindsStr.empty())
406       anEntityKindsStr += ", ";
407     anEntityKindsStr += *anIt;
408   }
409
410   std::string anAttributeType = theAttribute->attributeType();
411   if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
412     AttributeSelectionListPtr aSelectionListAttr = 
413                       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
414     // all context objects should be sketch entities
415     for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize && isSketchEntities; i++) {
416       AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
417       ObjectPtr anObject = aSelectAttr->context();
418       // a context of the selection attribute is a feature result. It can be a case when the result
419       // of the feature is null, e.g. the feature is modified and has not been executed yet.
420       // The validator returns an invalid result here. The case is an extrusion built on a sketch
421       // feature. A new sketch element creation leads to an empty result.
422       if (!anObject.get())
423         isSketchEntities = false;
424       else {
425         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
426         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
427       }
428     }
429   }
430   if (anAttributeType == ModelAPI_AttributeRefList::typeId()) {
431     AttributeRefListPtr aRefListAttr =
432       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
433     // all context objects should be sketch entities
434     for (int i = 0, aSize = aRefListAttr->size(); i < aSize && isSketchEntities; i++) {
435       ObjectPtr anObject = aRefListAttr->object(i);
436       // a context of the selection attribute is a feature result. It can be a case when the result
437       // of the feature is null, e.g. the feature is modified and has not been executed yet.
438       // The validator returns an invalid result here. The case is an extrusion built on a sketch
439       // feature. A new sketch element creation leads to an empty result.
440       if (!anObject.get())
441         isSketchEntities = false;
442       else {
443         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
444         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
445       }
446     }
447   }
448   if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
449     std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = 
450                      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
451     isSketchEntities = false;
452     if (aRef->isObject()) {
453       ObjectPtr anObject = aRef->object();
454       if (anObject.get() != NULL) {
455         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
456         if (aFeature.get() != NULL)
457           isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
458       }
459     }
460   }
461   if (!isSketchEntities) {
462     theError = "It refers to feature, which kind is not in the list: " + anEntityKindsStr;
463   }
464
465   return isSketchEntities;
466 }
467
468 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
469                                      const std::list<std::string>& theArguments,
470                                      std::string& theError) const
471 {
472   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
473     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
474     return false;
475   }
476
477   // there is a check whether the feature contains a point and a linear edge or two point values
478   std::string aParamA = theArguments.front();
479   SessionPtr aMgr = ModelAPI_Session::get();
480   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
481
482   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
483   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
484   QList<FeaturePtr> aCoinsideLines;
485
486   bool isObject = aRefAttr->isObject();
487   ObjectPtr anObject = aRefAttr->object();
488   if (isObject && anObject) {
489     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
490     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
491     ObjectPtr aOtherObject = aOtherAttr->object();
492     // if the other attribute is not filled still, the result is true
493     if (!aOtherObject.get())
494       return true;
495     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
496
497     // check that both have coincidence
498     FeaturePtr aConstrFeature;
499     std::set<FeaturePtr> aCoinList;
500     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
501     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
502     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
503       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
504       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
505       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
506         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
507         AttributePtr aAR = aRAttr->attr();
508         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
509           aCoinList.insert(aConstrFeature);
510           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
511                                           SketchPlugin_ConstraintCoincidence::ENTITY_A());
512           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
513                                           SketchPlugin_ConstraintCoincidence::ENTITY_B());
514       }
515     }
516     // if there is no coincidence then it is not valid
517     if (aCoinList.size() > 0) {
518       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
519       bool aValid = false;
520       for (; anIt != aLast && !aValid; anIt++) {
521         aValid = *anIt == aOtherFea;
522       }
523       if (aValid)
524         return true;
525     }
526   }
527   theError = "There is no a common coincident point.";
528   return false;
529 }
530