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>
20 #include <ModuleBase_ViewerPrs.h>
22 #include <Events_InfoMessage.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25 #include <ModelAPI_AttributeSelection.h>
26 #include <ModelAPI_AttributeReference.h>
27 #include <ModelAPI_AttributeSelectionList.h>
28 #include <ModelAPI_AttributeRefList.h>
29 #include <ModelAPI_Object.h>
30 #include <ModelAPI_Session.h>
31 #include <ModelAPI_Tools.h>
33 #include <SketchPlugin_Sketch.h>
34 #include <SketchPlugin_ConstraintCoincidence.h>
35 #include <SketchPlugin_Arc.h>
36 #include <GeomAPI_Edge.h>
43 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
45 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
46 ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
49 foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
50 const GeomShapePtr& aShape = aPrs->shape();
51 if (aShape.get() && !aShape->isNull()) {
52 if (aShape->shapeType() == GeomAPI_Shape::VERTEX)
59 int shapesNbLines(const ModuleBase_ISelection* theSelection)
61 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
63 foreach(ModuleBase_ViewerPrsPtr aPrs, aList) {
64 const GeomShapePtr& aShape = aPrs->shape();
65 if (aShape.get() && !aShape->isNull()) {
66 if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
67 const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
68 TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
69 Standard_Real aStart, aEnd;
70 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
71 GeomAdaptor_Curve aAdaptor(aCurve);
72 if (aAdaptor.GetType() == GeomAbs_Line)
81 std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
83 std::shared_ptr<GeomAPI_Pln> aEmptyPln;
85 ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
87 CompositeFeaturePtr aFeature =
88 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureOp->feature());
89 if (aFeature && (aFeature->getKind() == SketchPlugin_Sketch::ID()))
90 return PartSet_Tools::sketchPlane(aFeature);
97 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
99 ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
100 // during the create operation empty selection is always valid
101 if (!aFeatureOp->isEditOperation()) {
105 if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
106 std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
112 else// in edit operation an empty selection is always valid, performed for re-entrant operrations
117 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
119 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
120 return isEmptySelectionValid(theOperation);
122 int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
123 return (aCount > 0) && (aCount < 3);
127 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
129 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
130 return isEmptySelectionValid(theOperation);
132 int aCount = shapesNbLines(theSelection);
133 return (aCount == 1);
137 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
139 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
140 return isEmptySelectionValid(theOperation);
142 int aCount = shapesNbLines(theSelection);
143 return (aCount > 0) && (aCount < 3);
147 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
149 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
150 return isEmptySelectionValid(theOperation);
152 int aCount = shapesNbLines(theSelection);
153 return (aCount > 0) && (aCount < 3);
157 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
159 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
160 return isEmptySelectionValid(theOperation);
162 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
164 foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
165 const GeomShapePtr& aShape = aPrs->shape();
166 if (aShape.get() && !aShape->isNull()) {
167 if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
168 const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
169 TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
170 Standard_Real aStart, aEnd;
171 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
172 GeomAdaptor_Curve aAdaptor(aCurve);
173 if (aAdaptor.GetType() == GeomAbs_Circle)
178 return (aCount == 1);
182 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
184 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
185 return isEmptySelectionValid(theOperation);
187 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
188 return (aList.count() == 1);
193 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
195 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
196 return isEmptySelectionValid(theOperation);
198 // Coincident can be applied to points and to lines
199 int aCount = shapesNbPoints(theSelection);
200 aCount += shapesNbLines(theSelection);
201 return (aCount > 0) && (aCount < 3);
205 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
207 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
208 return isEmptySelectionValid(theOperation);
210 int aCount = shapesNbLines(theSelection);
211 return (aCount == 1);
215 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
217 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
218 return isEmptySelectionValid(theOperation);
220 int aCount = shapesNbPoints(theSelection);
225 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
227 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
228 return isEmptySelectionValid(theOperation);
230 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
231 if ((aList.size() == 0) || (aList.size() > 2))
234 ModuleBase_ViewerPrsPtr aPrs = aList.first();
235 const GeomShapePtr& aShape = aPrs->shape();
236 if (!aShape.get() || aShape->isNull() || aShape->shapeType() != GeomAPI_Shape::EDGE)
238 GeomAPI_Edge aEdge1(aShape);
240 if (aEdge1.isLine() || aEdge1.isArc()) {
241 if (aList.size() == 2) {
242 // Check second selection
244 const GeomShapePtr& aShape2 = aPrs->shape();
245 if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
247 GeomAPI_Edge aEdge2(aShape2);
249 if (aEdge1.isLine() && aEdge2.isArc())
251 else if (aEdge1.isArc() && aEdge2.isLine())
262 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
264 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
265 return isEmptySelectionValid(theOperation);
267 int aCount = shapesNbLines(theSelection);
268 return (aCount > 0) && (aCount < 3);
272 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
274 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
275 return isEmptySelectionValid(theOperation);
277 QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
280 foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
281 GeomShapePtr aShape = aPrs->shape();
282 if (aShape.get() && aShape->isEdge()) {
284 GeomAPI_Edge aEdge(aShape);
285 if (aEdge.isLine()) {
290 } else if (aEdge.isCircle()) {
295 } else if (aEdge.isArc()) {
304 return (aCount > 0) && (aCount < 3);
308 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
310 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
311 return isEmptySelectionValid(theOperation);
313 int aCount = shapesNbLines(theSelection);
314 return (aCount > 0) && (aCount < 3);
318 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
320 if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
321 return isEmptySelectionValid(theOperation);
323 return shapesNbLines(theSelection) == 1 && shapesNbPoints(theSelection) == 1;
327 std::string PartSet_DifferentObjectsValidator::errorMessage(
328 const PartSet_DifferentObjectsValidator::ErrorType& theType,
329 const std::string& thEqualObject, const std::string& theFirstAttribute,
330 const std::string& theSecondAttribute) const
335 anError = "The feature uses one " + thEqualObject + " object in " +
336 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
338 case EqualAttributes:
339 anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
340 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
343 anError = "The feature uses one shape in " +
344 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
347 anError = "The feature uses empty shapes in " +
348 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
357 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
358 const std::list<std::string>& theArguments,
359 Events_InfoMessage& theError) const
361 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
363 // the type of validated attributes should be equal, attributes with different types are not validated
364 // Check RefAttr attributes
365 std::string anAttrType = theAttribute->attributeType();
366 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
368 if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
369 AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
370 bool isObject = anAttr->isObject();
371 ObjectPtr anObject = anAttr->object();
373 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
374 if (anAttrs.size() > 0) {
375 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
376 for(; anAttrIter != anAttrs.end(); anAttrIter++) {
377 if ((*anAttrIter).get() && (*anAttrIter)->id() != theAttribute->id()) {
378 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
379 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
380 if (aRef->isObject() != isObject)
383 if (aRef->object() == anObject) {
384 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
385 theAttribute->id(), aRef->id());
389 else { // the attribute reference
390 AttributePtr anAttributeAttr = anAttr->attr();
391 if (aRef->attr() == anAttributeAttr) {
392 theError = errorMessage(EqualAttributes,
393 anAttributeAttr.get() ? anAttributeAttr->id() : "",
394 theAttribute->id(), aRef->id());
402 else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
403 AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
404 ResultPtr aContext = anAttr->context();
405 GeomShapePtr aShape = anAttr->value();
407 // Check selection attributes
408 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
409 if (anAttrs.size() > 0) {
410 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
411 for(; anAttr != anAttrs.end(); anAttr++) {
412 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
413 std::shared_ptr<ModelAPI_AttributeSelection> aRef =
414 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
415 // check the object is already presented
416 if (aRef->context() == aContext) {
417 bool aHasShape = aShape.get() != NULL;
418 if (!aHasShape || aRef->value()->isEqual(aShape)) {
419 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
427 else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
428 AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
429 ObjectPtr anObject = anAttr->value();
430 // Check selection attributes
431 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
432 if (anAttrs.size() > 0) {
433 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
434 for(; anAttr != anAttrs.end(); anAttr++) {
435 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
436 std::shared_ptr<ModelAPI_AttributeReference> aRef =
437 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
438 // check the object is already presented
439 if (aRef->value() == anObject) {
440 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
441 theAttribute->id(), aRef->id());
449 else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
450 std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
451 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
452 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
453 if(anAttrs.size() > 0) {
454 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
455 for(; anAttrItr != anAttrs.end(); anAttrItr++){
456 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
457 std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
458 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
459 for(int i = 0; i < aCurSelList->size(); i++) {
460 std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
461 ResultPtr aCurSelContext = aCurSel->context();
462 ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
463 std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
464 if(aCurSelCompSolidPtr.get()) {
465 aCurSelCompSolid = aCurSelCompSolidPtr->shape();
467 for(int j = 0; j < aRefSelList->size(); j++) {
468 std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
469 ResultPtr aRefSelContext = aRefSel->context();
470 ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
471 std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
472 if(aRefSelCompSolidPtr.get()) {
473 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
475 if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
476 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
477 theError = errorMessage(EqualShapes, "", theAttribute->id(),
481 if(aCurSelContext == aRefSelContext) {
482 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
483 theError = errorMessage(EmptyShapes, "", theAttribute->id(),
487 if (aCurSel->value()->isEqual(aRefSel->value())) {
488 theError = errorMessage(EqualShapes, "", theAttribute->id(),
499 else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
500 std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
501 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
502 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
503 if (anAttrs.size() > 0) {
504 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
505 for (; anAttrItr != anAttrs.end(); anAttrItr++){
506 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
507 std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
508 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
509 for (int i = 0; i < aCurSelList->size(); i++) {
510 ObjectPtr aCurSelObject = aCurSelList->object(i);
511 for (int j = 0; j < aRefSelList->size(); j++) {
512 if (aCurSelObject == aRefSelList->object(j)) {
513 theError = errorMessage(EqualObjects,
514 aCurSelObject.get() ? aCurSelObject->data()->name() : "",
515 theAttribute->id(), aCurSelList->id());
527 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
528 const std::list<std::string>& theArguments,
529 Events_InfoMessage& theError) const
531 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
532 theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
536 // there is a check whether the feature contains a point and a linear edge or two point values
537 std::string aParamA = theArguments.front();
538 SessionPtr aMgr = ModelAPI_Session::get();
539 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
541 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
542 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
543 QList<FeaturePtr> aCoinsideLines;
544 QList<FeaturePtr> aCoins;
546 bool isObject = aRefAttr->isObject();
547 ObjectPtr anObject = aRefAttr->object();
548 if (isObject && anObject) {
549 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
550 AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
551 ObjectPtr aOtherObject = aOtherAttr->object();
552 // if the other attribute is not filled still, the result is true
553 if (!aOtherObject.get())
555 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
557 // check that both have coincidence
558 FeaturePtr aConstrFeature;
559 std::set<FeaturePtr> aCoinList;
560 const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
561 std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
562 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
563 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
564 aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
565 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
566 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
567 AttributePtr aAR = aRAttr->attr();
568 if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
569 aCoinList.insert(aConstrFeature);
570 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
571 SketchPlugin_ConstraintCoincidence::ENTITY_A());
572 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
573 SketchPlugin_ConstraintCoincidence::ENTITY_B());
576 // if there is no coincidence then it is not valid
577 if (aCoinList.size() > 0) {
578 QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
580 for (; anIt != aLast && !aValid; anIt++) {
581 aValid = *anIt == aOtherFea;
587 theError = "There is no a common coincident point.";