1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: PartSet_Validators.cpp
4 // Created: 09 July 2014
5 // Author: Vitaly SMETANNIKOV
7 #include "PartSet_Validators.h"
9 #include "PartSet_Tools.h"
10 #include "PartSet_SketcherMgr.h"
13 #include <TopoDS_Edge.hxx>
14 #include <BRep_Tool.hxx>
15 #include <GeomAdaptor_Curve.hxx>
16 #include <GeomAbs_CurveType.hxx>
17 #include <ModuleBase_ISelection.h>
18 #include <ModuleBase_WidgetShapeSelector.h>
19 #include <ModuleBase_OperationFeature.h>
21 #include <ModelAPI_AttributeRefAttr.h>
22 #include <ModelAPI_AttributeSelection.h>
23 #include <ModelAPI_AttributeReference.h>
24 #include <ModelAPI_AttributeSelectionList.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_Object.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_Tools.h>
30 #include <SketchPlugin_Sketch.h>
31 #include <SketchPlugin_ConstraintCoincidence.h>
32 #include <SketchPlugin_Arc.h>
33 #include <GeomAPI_Edge.h>
40 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
42 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
43 ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
46 foreach (ModuleBase_ViewerPrs aPrs, aList) {
47 const TopoDS_Shape& aShape = aPrs.shape();
48 if (!aShape.IsNull()) {
49 if (aShape.ShapeType() == TopAbs_VERTEX)
56 int shapesNbLines(const ModuleBase_ISelection* theSelection)
58 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
60 foreach(ModuleBase_ViewerPrs aPrs, aList) {
61 const TopoDS_Shape& aShape = aPrs.shape();
62 if (!aShape.IsNull()) {
63 if (aShape.ShapeType() == TopAbs_EDGE) {
64 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
65 Standard_Real aStart, aEnd;
66 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
67 GeomAdaptor_Curve aAdaptor(aCurve);
68 if (aAdaptor.GetType() == GeomAbs_Line)
77 std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
79 std::shared_ptr<GeomAPI_Pln> aEmptyPln;
81 ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
83 CompositeFeaturePtr aFeature =
84 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureOp->feature());
85 if (aFeature && (aFeature->getKind() == SketchPlugin_Sketch::ID()))
86 return PartSet_Tools::sketchPlane(aFeature);
93 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
95 ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
96 // during the create operation empty selection is always valid
97 if (!aFeatureOp->isEditOperation()) {
101 if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
102 std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
108 else// in edit operation an empty selection is always valid, performed for re-entrant operrations
113 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
115 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
116 return isEmptySelectionValid(theOperation);
118 int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
119 return (aCount > 0) && (aCount < 3);
123 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
125 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
126 return isEmptySelectionValid(theOperation);
128 int aCount = shapesNbLines(theSelection);
129 return (aCount == 1);
133 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
135 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
136 return isEmptySelectionValid(theOperation);
138 int aCount = shapesNbLines(theSelection);
139 return (aCount > 0) && (aCount < 3);
143 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
145 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
146 return isEmptySelectionValid(theOperation);
148 int aCount = shapesNbLines(theSelection);
149 return (aCount > 0) && (aCount < 3);
153 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
155 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
156 return isEmptySelectionValid(theOperation);
158 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
159 ModuleBase_ViewerPrs aPrs;
161 foreach (ModuleBase_ViewerPrs aPrs, aList) {
162 const TopoDS_Shape& aShape = aPrs.shape();
163 if (!aShape.IsNull()) {
164 if (aShape.ShapeType() == TopAbs_EDGE) {
165 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
166 Standard_Real aStart, aEnd;
167 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
168 GeomAdaptor_Curve aAdaptor(aCurve);
169 if (aAdaptor.GetType() == GeomAbs_Circle)
174 return (aCount == 1);
178 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
180 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
181 return isEmptySelectionValid(theOperation);
183 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
184 return (aList.count() == 1);
189 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
191 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
192 return isEmptySelectionValid(theOperation);
194 // Coincident can be applied to points and to lines
195 int aCount = shapesNbPoints(theSelection);
196 aCount += shapesNbLines(theSelection);
197 return (aCount > 0) && (aCount < 3);
201 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
203 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
204 return isEmptySelectionValid(theOperation);
206 int aCount = shapesNbLines(theSelection);
207 return (aCount == 1);
211 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
213 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
214 return isEmptySelectionValid(theOperation);
216 int aCount = shapesNbPoints(theSelection);
221 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
223 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
224 return isEmptySelectionValid(theOperation);
226 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
227 if ((aList.size() == 0) || (aList.size() > 2))
230 ModuleBase_ViewerPrs aPrs = aList.first();
231 const TopoDS_Shape& aShape = aPrs.shape();
235 if (aShape.ShapeType() != TopAbs_EDGE)
238 std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
239 aShapePtr->setImpl(new TopoDS_Shape(aShape));
240 GeomAPI_Edge aEdge1(aShapePtr);
242 if (aEdge1.isLine() || aEdge1.isArc()) {
243 if (aList.size() == 2) {
244 // Check second selection
246 const TopoDS_Shape& aShape2 = aPrs.shape();
247 if (aShape2.IsNull())
250 if (aShape2.ShapeType() != TopAbs_EDGE)
253 std::shared_ptr<GeomAPI_Shape> aShapePtr2(new GeomAPI_Shape);
254 aShapePtr2->setImpl(new TopoDS_Shape(aShape2));
255 GeomAPI_Edge aEdge2(aShapePtr2);
256 if (aEdge1.isLine() && aEdge2.isArc())
258 else if (aEdge1.isArc() && aEdge2.isLine())
269 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
271 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
272 return isEmptySelectionValid(theOperation);
274 int aCount = shapesNbLines(theSelection);
275 return (aCount > 0) && (aCount < 3);
279 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
281 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
282 return isEmptySelectionValid(theOperation);
284 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
285 ModuleBase_ViewerPrs aPrs;
288 foreach (ModuleBase_ViewerPrs aPrs, aList) {
289 std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
290 aShape->setImpl(new TopoDS_Shape(aPrs.shape()));
291 if (aShape->isEdge()) {
293 GeomAPI_Edge aEdge(aShape);
294 if (aEdge.isLine()) {
299 } else if (aEdge.isCircle()) {
304 } else if (aEdge.isArc()) {
313 return (aCount > 0) && (aCount < 3);
318 std::string PartSet_DifferentObjectsValidator::errorMessage(
319 const PartSet_DifferentObjectsValidator::ErrorType& theType,
320 const std::string& thEqualObject, const std::string& theFirstAttribute,
321 const std::string& theSecondAttribute) const
326 anError = "The feature uses one " + thEqualObject + " object in " +
327 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
329 case EqualAttributes:
330 anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
331 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
334 anError = "The feature uses one shape in " +
335 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
338 anError = "The feature uses empty shapes in " +
339 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
348 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
349 const std::list<std::string>& theArguments,
350 std::string& theError) const
352 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
354 // the type of validated attributes should be equal, attributes with different types are not validated
355 // Check RefAttr attributes
356 std::string anAttrType = theAttribute->attributeType();
357 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
359 if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
360 AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
361 bool isObject = anAttr->isObject();
362 ObjectPtr anObject = anAttr->object();
363 AttributePtr anAttributeAttr = anAttr->attr();
365 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
366 if (anAttrs.size() > 0) {
367 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
368 for(; anAttr != anAttrs.end(); anAttr++) {
369 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
370 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
371 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
372 if (aRef->isObject() != isObject)
375 if (aRef->object() == anObject) {
376 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
377 theAttribute->id(), aRef->id());
381 else { // the attribute reference
382 if (aRef->attr() == anAttributeAttr) {
383 theError = errorMessage(EqualAttributes,
384 anAttributeAttr.get() ? anAttributeAttr->id() : "",
385 theAttribute->id(), aRef->id());
393 else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
394 AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
395 ResultPtr aContext = anAttr->context();
396 GeomShapePtr aShape = anAttr->value();
398 // Check selection attributes
399 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
400 if (anAttrs.size() > 0) {
401 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
402 for(; anAttr != anAttrs.end(); anAttr++) {
403 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
404 std::shared_ptr<ModelAPI_AttributeSelection> aRef =
405 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
406 // check the object is already presented
407 if (aRef->context() == aContext) {
408 bool aHasShape = aShape.get() != NULL;
409 if (!aHasShape || aRef->value()->isEqual(aShape)) {
410 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
418 else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
419 AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
420 ObjectPtr anObject = anAttr->value();
421 // Check selection attributes
422 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
423 if (anAttrs.size() > 0) {
424 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
425 for(; anAttr != anAttrs.end(); anAttr++) {
426 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
427 std::shared_ptr<ModelAPI_AttributeReference> aRef =
428 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
429 // check the object is already presented
430 if (aRef->value() == anObject) {
431 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
432 theAttribute->id(), aRef->id());
440 else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
441 std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
442 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
443 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
444 if(anAttrs.size() > 0) {
445 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
446 for(; anAttrItr != anAttrs.end(); anAttrItr++){
447 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
448 std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
449 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
450 for(int i = 0; i < aCurSelList->size(); i++) {
451 std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
452 ResultPtr aCurSelContext = aCurSel->context();
453 ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
454 std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
455 if(aCurSelCompSolidPtr.get()) {
456 aCurSelCompSolid = aCurSelCompSolidPtr->shape();
458 for(int j = 0; j < aRefSelList->size(); j++) {
459 std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
460 ResultPtr aRefSelContext = aRefSel->context();
461 ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
462 std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
463 if(aRefSelCompSolidPtr.get()) {
464 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
466 if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
467 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
468 theError = errorMessage(EqualShapes, "", theAttribute->id(),
472 if(aCurSelContext == aRefSelContext) {
473 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
474 theError = errorMessage(EmptyShapes, "", theAttribute->id(),
478 if (aCurSel->value()->isEqual(aRefSel->value())) {
479 theError = errorMessage(EqualShapes, "", theAttribute->id(),
490 else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
491 std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
492 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
493 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
494 if (anAttrs.size() > 0) {
495 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
496 for (; anAttrItr != anAttrs.end(); anAttrItr++){
497 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
498 std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
499 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
500 for (int i = 0; i < aCurSelList->size(); i++) {
501 ObjectPtr aCurSelObject = aCurSelList->object(i);
502 for (int j = 0; j < aRefSelList->size(); j++) {
503 if (aCurSelObject == aRefSelList->object(j)) {
504 theError = errorMessage(EqualObjects,
505 aCurSelObject.get() ? aCurSelObject->data()->name() : "",
506 theAttribute->id(), aCurSelList->id());
518 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
519 const std::list<std::string>& theArguments,
520 std::string& theError) const
522 bool isSketchEntities = true;
523 std::set<std::string> anEntityKinds;
524 std::string anEntityKindsStr;
525 std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
526 for (; anIt != aLast; anIt++) {
527 anEntityKinds.insert(*anIt);
528 if (!anEntityKindsStr.empty())
529 anEntityKindsStr += ", ";
530 anEntityKindsStr += *anIt;
533 std::string anAttributeType = theAttribute->attributeType();
534 if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
535 AttributeSelectionListPtr aSelectionListAttr =
536 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
537 // all context objects should be sketch entities
538 for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize && isSketchEntities; i++) {
539 AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
540 ObjectPtr anObject = aSelectAttr->context();
541 // a context of the selection attribute is a feature result. It can be a case when the result
542 // of the feature is null, e.g. the feature is modified and has not been executed yet.
543 // The validator returns an invalid result here. The case is an extrusion built on a sketch
544 // feature. A new sketch element creation leads to an empty result.
546 isSketchEntities = false;
548 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
549 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
553 if (anAttributeType == ModelAPI_AttributeSelection::typeId()) {
554 AttributeSelectionPtr aSelectAttr =
555 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
556 ObjectPtr anObject = aSelectAttr->context();
557 // a context of the selection attribute is a feature result. It can be a case when the result
558 // of the feature is null, e.g. the feature is modified and has not been executed yet.
559 // The validator returns an invalid result here. The case is an extrusion built on a sketch
560 // feature. A new sketch element creation leads to an empty result.
562 isSketchEntities = false;
564 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
565 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
568 if (anAttributeType == ModelAPI_AttributeRefList::typeId()) {
569 AttributeRefListPtr aRefListAttr =
570 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
571 // all context objects should be sketch entities
572 for (int i = 0, aSize = aRefListAttr->size(); i < aSize && isSketchEntities; i++) {
573 ObjectPtr anObject = aRefListAttr->object(i);
574 // a context of the selection attribute is a feature result. It can be a case when the result
575 // of the feature is null, e.g. the feature is modified and has not been executed yet.
576 // The validator returns an invalid result here. The case is an extrusion built on a sketch
577 // feature. A new sketch element creation leads to an empty result.
579 isSketchEntities = false;
581 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
582 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
586 if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
587 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
588 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
589 isSketchEntities = false;
590 if (aRef->isObject()) {
591 ObjectPtr anObject = aRef->object();
592 if (anObject.get() != NULL) {
593 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
594 if (aFeature.get() != NULL)
595 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
599 if (!isSketchEntities) {
600 theError = "It refers to feature, which kind is not in the list: " + anEntityKindsStr;
603 return isSketchEntities;
606 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
607 const std::list<std::string>& theArguments,
608 std::string& theError) const
610 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
611 theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
615 // there is a check whether the feature contains a point and a linear edge or two point values
616 std::string aParamA = theArguments.front();
617 SessionPtr aMgr = ModelAPI_Session::get();
618 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
620 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
621 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
622 QList<FeaturePtr> aCoinsideLines;
624 bool isObject = aRefAttr->isObject();
625 ObjectPtr anObject = aRefAttr->object();
626 if (isObject && anObject) {
627 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
628 AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
629 ObjectPtr aOtherObject = aOtherAttr->object();
630 // if the other attribute is not filled still, the result is true
631 if (!aOtherObject.get())
633 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
635 // check that both have coincidence
636 FeaturePtr aConstrFeature;
637 std::set<FeaturePtr> aCoinList;
638 const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
639 std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
640 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
641 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
642 aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
643 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
644 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
645 AttributePtr aAR = aRAttr->attr();
646 if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
647 aCoinList.insert(aConstrFeature);
648 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
649 SketchPlugin_ConstraintCoincidence::ENTITY_A());
650 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
651 SketchPlugin_ConstraintCoincidence::ENTITY_B());
654 // if there is no coincidence then it is not valid
655 if (aCoinList.size() > 0) {
656 QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
658 for (; anIt != aLast && !aValid; anIt++) {
659 aValid = *anIt == aOtherFea;
665 theError = "There is no a common coincident point.";