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"
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>
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>
29 #include <SketchPlugin_Sketch.h>
30 #include <SketchPlugin_ConstraintCoincidence.h>
31 #include <SketchPlugin_Arc.h>
32 #include <GeomAPI_Edge.h>
39 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
41 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
42 ModuleBase_ISelection::filterPreselectionOnEqualPoints(aList);
45 foreach (ModuleBase_ViewerPrs aPrs, aList) {
46 const TopoDS_Shape& aShape = aPrs.shape();
47 if (!aShape.IsNull()) {
48 if (aShape.ShapeType() == TopAbs_VERTEX)
55 int shapesNbLines(const ModuleBase_ISelection* theSelection)
57 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
59 foreach(ModuleBase_ViewerPrs aPrs, aList) {
60 const TopoDS_Shape& aShape = aPrs.shape();
61 if (!aShape.IsNull()) {
62 if (aShape.ShapeType() == TopAbs_EDGE) {
63 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
64 Standard_Real aStart, aEnd;
65 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
66 GeomAdaptor_Curve aAdaptor(aCurve);
67 if (aAdaptor.GetType() == GeomAbs_Line)
75 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection) const
77 int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
78 return (aCount > 0) && (aCount < 3);
81 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection) const
83 int aCount = shapesNbLines(theSelection);
87 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection) const
89 int aCount = shapesNbLines(theSelection);
90 return (aCount > 0) && (aCount < 3);
93 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection) const
95 int aCount = shapesNbLines(theSelection);
96 return (aCount > 0) && (aCount < 3);
99 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection) const
101 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
102 ModuleBase_ViewerPrs aPrs;
104 foreach (ModuleBase_ViewerPrs aPrs, aList) {
105 const TopoDS_Shape& aShape = aPrs.shape();
106 if (!aShape.IsNull()) {
107 if (aShape.ShapeType() == TopAbs_EDGE) {
108 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
109 Standard_Real aStart, aEnd;
110 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
111 GeomAdaptor_Curve aAdaptor(aCurve);
112 if (aAdaptor.GetType() == GeomAbs_Circle)
117 return (aCount == 1);
120 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection) const
122 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
123 return (aList.count() == 1);
127 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection) const
129 // Coincident can be applied to points and to lines
130 int aCount = shapesNbPoints(theSelection);
131 aCount += shapesNbLines(theSelection);
132 return (aCount > 0) && (aCount < 3);
135 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection) const
137 int aCount = shapesNbLines(theSelection);
138 return (aCount == 1);
141 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection) const
143 int aCount = shapesNbLines(theSelection);
144 return (aCount > 0) && (aCount < 3);
147 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection) const
149 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
150 if ((aList.size() == 0) || (aList.size() > 2))
153 ModuleBase_ViewerPrs aPrs = aList.first();
154 const TopoDS_Shape& aShape = aPrs.shape();
158 if (aShape.ShapeType() != TopAbs_EDGE)
161 std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
162 aShapePtr->setImpl(new TopoDS_Shape(aShape));
163 GeomAPI_Edge aEdge1(aShapePtr);
165 if (aEdge1.isLine() || aEdge1.isArc()) {
166 if (aList.size() == 2) {
167 // Check second selection
169 const TopoDS_Shape& aShape2 = aPrs.shape();
170 if (aShape2.IsNull())
173 if (aShape2.ShapeType() != TopAbs_EDGE)
176 std::shared_ptr<GeomAPI_Shape> aShapePtr2(new GeomAPI_Shape);
177 aShapePtr2->setImpl(new TopoDS_Shape(aShape2));
178 GeomAPI_Edge aEdge2(aShapePtr2);
179 if (aEdge1.isLine() && aEdge2.isArc())
181 else if (aEdge1.isArc() && aEdge2.isLine())
191 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection) const
193 int aCount = shapesNbLines(theSelection);
194 return (aCount > 0) && (aCount < 3);
197 std::string PartSet_DifferentObjectsValidator::errorMessage(
198 const PartSet_DifferentObjectsValidator::ErrorType& theType,
199 const std::string& thEqualObject, const std::string& theFirstAttribute,
200 const std::string& theSecondAttribute) const
205 anError = "The feature uses one " + thEqualObject + " object in " +
206 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
208 case EqualAttributes:
209 anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
210 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
213 anError = "The feature uses one shape in " +
214 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
217 anError = "The feature uses empty shapes in " +
218 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
227 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
228 const std::list<std::string>& theArguments,
229 std::string& theError) const
231 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
233 // the type of validated attributes should be equal, attributes with different types are not validated
234 // Check RefAttr attributes
235 std::string anAttrType = theAttribute->attributeType();
236 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
238 if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
239 AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
240 bool isObject = anAttr->isObject();
241 ObjectPtr anObject = anAttr->object();
242 AttributePtr anAttributeAttr = anAttr->attr();
244 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
245 if (anAttrs.size() > 0) {
246 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
247 for(; anAttr != anAttrs.end(); anAttr++) {
248 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
249 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
250 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
251 if (aRef->isObject() != isObject)
254 if (aRef->object() == anObject) {
255 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
256 theAttribute->id(), aRef->id());
260 else { // the attribute reference
261 if (aRef->attr() == anAttributeAttr) {
262 theError = errorMessage(EqualAttributes,
263 anAttributeAttr.get() ? anAttributeAttr->id() : "",
264 theAttribute->id(), aRef->id());
272 else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
273 AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
274 ResultPtr aContext = anAttr->context();
275 GeomShapePtr aShape = anAttr->value();
277 // Check selection attributes
278 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
279 if (anAttrs.size() > 0) {
280 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
281 for(; anAttr != anAttrs.end(); anAttr++) {
282 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
283 std::shared_ptr<ModelAPI_AttributeSelection> aRef =
284 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
285 // check the object is already presented
286 if (aRef->context() == aContext) {
287 bool aHasShape = aShape.get() != NULL;
288 if (!aHasShape || aRef->value()->isEqual(aShape)) {
289 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
297 else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
298 AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
299 ObjectPtr anObject = anAttr->value();
300 // Check selection attributes
301 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
302 if (anAttrs.size() > 0) {
303 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
304 for(; anAttr != anAttrs.end(); anAttr++) {
305 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
306 std::shared_ptr<ModelAPI_AttributeReference> aRef =
307 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
308 // check the object is already presented
309 if (aRef->value() == anObject) {
310 theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
311 theAttribute->id(), aRef->id());
319 else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
320 std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
321 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
322 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
323 if(anAttrs.size() > 0) {
324 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
325 for(; anAttrItr != anAttrs.end(); anAttrItr++){
326 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
327 std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
328 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
329 for(int i = 0; i < aCurSelList->size(); i++) {
330 std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
331 ResultPtr aCurSelContext = aCurSel->context();
332 ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
333 std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
334 if(aCurSelCompSolidPtr.get()) {
335 aCurSelCompSolid = aCurSelCompSolidPtr->shape();
337 for(int j = 0; j < aRefSelList->size(); j++) {
338 std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
339 ResultPtr aRefSelContext = aRefSel->context();
340 ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
341 std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
342 if(aRefSelCompSolidPtr.get()) {
343 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
345 if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
346 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
347 theError = errorMessage(EqualShapes, "", theAttribute->id(),
351 if(aCurSelContext == aRefSelContext) {
352 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
353 theError = errorMessage(EmptyShapes, "", theAttribute->id(),
357 if (aCurSel->value()->isEqual(aRefSel->value())) {
358 theError = errorMessage(EqualShapes, "", theAttribute->id(),
369 else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
370 std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
371 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
372 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
373 if (anAttrs.size() > 0) {
374 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
375 for (; anAttrItr != anAttrs.end(); anAttrItr++){
376 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
377 std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
378 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
379 for (int i = 0; i < aCurSelList->size(); i++) {
380 ObjectPtr aCurSelObject = aCurSelList->object(i);
381 for (int j = 0; j < aRefSelList->size(); j++) {
382 if (aCurSelObject == aRefSelList->object(j)) {
383 theError = errorMessage(EqualObjects,
384 aCurSelObject.get() ? aCurSelObject->data()->name() : "",
385 theAttribute->id(), aCurSelList->id());
397 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
398 const std::list<std::string>& theArguments,
399 std::string& theError) const
401 bool isSketchEntities = true;
402 std::set<std::string> anEntityKinds;
403 std::string anEntityKindsStr;
404 std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
405 for (; anIt != aLast; anIt++) {
406 anEntityKinds.insert(*anIt);
407 if (!anEntityKindsStr.empty())
408 anEntityKindsStr += ", ";
409 anEntityKindsStr += *anIt;
412 std::string anAttributeType = theAttribute->attributeType();
413 if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
414 AttributeSelectionListPtr aSelectionListAttr =
415 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
416 // all context objects should be sketch entities
417 for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize && isSketchEntities; i++) {
418 AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
419 ObjectPtr anObject = aSelectAttr->context();
420 // a context of the selection attribute is a feature result. It can be a case when the result
421 // of the feature is null, e.g. the feature is modified and has not been executed yet.
422 // The validator returns an invalid result here. The case is an extrusion built on a sketch
423 // feature. A new sketch element creation leads to an empty result.
425 isSketchEntities = false;
427 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
428 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
432 if (anAttributeType == ModelAPI_AttributeRefList::typeId()) {
433 AttributeRefListPtr aRefListAttr =
434 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
435 // all context objects should be sketch entities
436 for (int i = 0, aSize = aRefListAttr->size(); i < aSize && isSketchEntities; i++) {
437 ObjectPtr anObject = aRefListAttr->object(i);
438 // a context of the selection attribute is a feature result. It can be a case when the result
439 // of the feature is null, e.g. the feature is modified and has not been executed yet.
440 // The validator returns an invalid result here. The case is an extrusion built on a sketch
441 // feature. A new sketch element creation leads to an empty result.
443 isSketchEntities = false;
445 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
446 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
450 if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
451 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
452 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
453 isSketchEntities = false;
454 if (aRef->isObject()) {
455 ObjectPtr anObject = aRef->object();
456 if (anObject.get() != NULL) {
457 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
458 if (aFeature.get() != NULL)
459 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
463 if (!isSketchEntities) {
464 theError = "It refers to feature, which kind is not in the list: " + anEntityKindsStr;
467 return isSketchEntities;
470 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
471 const std::list<std::string>& theArguments,
472 std::string& theError) const
474 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
475 theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
479 // there is a check whether the feature contains a point and a linear edge or two point values
480 std::string aParamA = theArguments.front();
481 SessionPtr aMgr = ModelAPI_Session::get();
482 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
484 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
485 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
486 QList<FeaturePtr> aCoinsideLines;
488 bool isObject = aRefAttr->isObject();
489 ObjectPtr anObject = aRefAttr->object();
490 if (isObject && anObject) {
491 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
492 AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
493 ObjectPtr aOtherObject = aOtherAttr->object();
494 // if the other attribute is not filled still, the result is true
495 if (!aOtherObject.get())
497 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
499 // check that both have coincidence
500 FeaturePtr aConstrFeature;
501 std::set<FeaturePtr> aCoinList;
502 const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
503 std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
504 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
505 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
506 aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
507 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
508 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
509 AttributePtr aAR = aRAttr->attr();
510 if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
511 aCoinList.insert(aConstrFeature);
512 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
513 SketchPlugin_ConstraintCoincidence::ENTITY_A());
514 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
515 SketchPlugin_ConstraintCoincidence::ENTITY_B());
518 // if there is no coincidence then it is not valid
519 if (aCoinList.size() > 0) {
520 QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
522 for (; anIt != aLast && !aValid; anIt++) {
523 aValid = *anIt == aOtherFea;
529 theError = "There is no a common coincident point.";