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>
28 #include <SketchPlugin_Sketch.h>
29 #include <SketchPlugin_ConstraintCoincidence.h>
30 #include <SketchPlugin_Arc.h>
31 #include <GeomAPI_Edge.h>
38 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
40 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
42 foreach (ModuleBase_ViewerPrs aPrs, aList) {
43 const TopoDS_Shape& aShape = aPrs.shape();
44 if (!aShape.IsNull()) {
45 if (aShape.ShapeType() == TopAbs_VERTEX)
52 int shapesNbLines(const ModuleBase_ISelection* theSelection)
54 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
56 foreach(ModuleBase_ViewerPrs aPrs, aList) {
57 const TopoDS_Shape& aShape = aPrs.shape();
58 if (!aShape.IsNull()) {
59 if (aShape.ShapeType() == TopAbs_EDGE) {
60 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
61 Standard_Real aStart, aEnd;
62 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
63 GeomAdaptor_Curve aAdaptor(aCurve);
64 if (aAdaptor.GetType() == GeomAbs_Line)
72 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection) const
74 int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
75 return (aCount > 0) && (aCount < 3);
78 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection) const
80 int aCount = shapesNbLines(theSelection);
84 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection) const
86 int aCount = shapesNbLines(theSelection);
87 return (aCount > 0) && (aCount < 3);
90 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection) const
92 int aCount = shapesNbLines(theSelection);
93 return (aCount > 0) && (aCount < 3);
96 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection) const
98 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
99 ModuleBase_ViewerPrs aPrs;
101 foreach (ModuleBase_ViewerPrs aPrs, aList) {
102 const TopoDS_Shape& aShape = aPrs.shape();
103 if (!aShape.IsNull()) {
104 if (aShape.ShapeType() == TopAbs_EDGE) {
105 TopoDS_Edge aEdge = TopoDS::Edge(aShape);
106 Standard_Real aStart, aEnd;
107 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
108 GeomAdaptor_Curve aAdaptor(aCurve);
109 if (aAdaptor.GetType() == GeomAbs_Circle)
114 return (aCount == 1);
117 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection) const
119 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
120 return (aList.count() == 1);
124 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection) const
126 // Coincident can be applied to points and to lines
127 int aCount = shapesNbPoints(theSelection);
128 aCount += shapesNbLines(theSelection);
129 return (aCount > 0) && (aCount < 3);
132 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection) const
134 int aCount = shapesNbLines(theSelection);
135 return (aCount == 1);
138 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection) const
140 int aCount = shapesNbLines(theSelection);
141 return (aCount > 0) && (aCount < 3);
144 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection) const
146 QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
147 if ((aList.size() == 0) || (aList.size() > 2))
150 ModuleBase_ViewerPrs aPrs = aList.first();
151 const TopoDS_Shape& aShape = aPrs.shape();
155 if (aShape.ShapeType() != TopAbs_EDGE)
158 std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
159 aShapePtr->setImpl(new TopoDS_Shape(aShape));
160 GeomAPI_Edge aEdge1(aShapePtr);
162 if (aEdge1.isLine() || aEdge1.isArc()) {
163 if (aList.size() == 2) {
164 // Check second selection
166 const TopoDS_Shape& aShape2 = aPrs.shape();
167 if (aShape2.IsNull())
170 if (aShape2.ShapeType() != TopAbs_EDGE)
173 std::shared_ptr<GeomAPI_Shape> aShapePtr2(new GeomAPI_Shape);
174 aShapePtr2->setImpl(new TopoDS_Shape(aShape2));
175 GeomAPI_Edge aEdge2(aShapePtr2);
176 if (aEdge1.isLine() && aEdge2.isArc())
178 else if (aEdge1.isArc() && aEdge2.isLine())
188 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection) const
190 int aCount = shapesNbLines(theSelection);
191 return (aCount > 0) && (aCount < 3);
195 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
196 const std::list<std::string>& theArguments,
197 std::string& theError) const
199 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
201 // the type of validated attributes should be equal, attributes with different types are not validated
202 // Check RefAttr attributes
203 std::string anAttrType = theAttribute->attributeType();
204 std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
206 if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
207 AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
208 bool isObject = anAttr->isObject();
209 ObjectPtr anObject = anAttr->object();
210 AttributePtr anAttributeAttr = anAttr->attr();
212 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
213 if (anAttrs.size() > 0) {
214 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
215 for(; anAttr != anAttrs.end(); anAttr++) {
216 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
217 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
218 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
219 if (aRef->isObject() != isObject)
222 if (aRef->object() == anObject)
225 else { // the attribute reference
226 if (aRef->attr() == anAttributeAttr)
233 else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
234 AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
235 ResultPtr aContext = anAttr->context();
236 GeomShapePtr aShape = anAttr->value();
238 // Check selection attributes
239 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
240 if (anAttrs.size() > 0) {
241 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
242 for(; anAttr != anAttrs.end(); anAttr++) {
243 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
244 std::shared_ptr<ModelAPI_AttributeSelection> aRef =
245 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
246 // check the object is already presented
247 if (aRef->context() == aContext) {
248 bool aHasShape = aShape.get() != NULL;
249 if (!aHasShape || aRef->value()->isEqual(aShape))
256 else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
257 AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
258 ObjectPtr anObject = anAttr->value();
259 // Check selection attributes
260 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
261 if (anAttrs.size() > 0) {
262 std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
263 for(; anAttr != anAttrs.end(); anAttr++) {
264 if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
265 std::shared_ptr<ModelAPI_AttributeReference> aRef =
266 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
267 // check the object is already presented
268 if (aRef->value() == anObject)
275 else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
276 std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
277 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
278 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
279 if(anAttrs.size() > 0) {
280 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
281 for(; anAttrItr != anAttrs.end(); anAttrItr++){
282 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
283 std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
284 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
285 for(int i = 0; i < aCurSelList->size(); i++) {
286 std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
287 for(int j = 0; j < aRefSelList->size(); j++) {
288 std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
289 if(aCurSel->context() == aRefSel->context()) {
290 if(aCurSel->value().get() == NULL || aRefSel->value().get() == NULL
291 || aCurSel->value()->isEqual(aRefSel->value())) {
301 else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
302 std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
303 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
304 anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
305 if (anAttrs.size() > 0) {
306 std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
307 for (; anAttrItr != anAttrs.end(); anAttrItr++){
308 if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
309 std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
310 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
311 for (int i = 0; i < aCurSelList->size(); i++) {
312 ObjectPtr aCurSelObject = aCurSelList->object(i);
313 for (int j = 0; j < aRefSelList->size(); j++) {
314 if (aCurSelObject == aRefSelList->object(j)) {
326 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
327 const std::list<std::string>& theArguments,
328 std::string& theError) const
330 bool isSketchEntities = true;
331 std::set<std::string> anEntityKinds;
332 std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
333 for (; anIt != aLast; anIt++) {
334 anEntityKinds.insert(*anIt);
337 std::string anAttributeType = theAttribute->attributeType();
338 if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
339 AttributeSelectionListPtr aSelectionListAttr =
340 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
341 // all context objects should be sketch entities
342 for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize && isSketchEntities; i++) {
343 AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
344 ObjectPtr anObject = aSelectAttr->context();
345 // a context of the selection attribute is a feature result. It can be a case when the result
346 // of the feature is null, e.g. the feature is modified and has not been executed yet.
347 // The validator returns an invalid result here. The case is an extrusion built on a sketch
348 // feature. A new sketch element creation leads to an empty result.
350 isSketchEntities = false;
352 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
353 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
357 if (anAttributeType == ModelAPI_AttributeRefList::typeId()) {
358 AttributeRefListPtr aRefListAttr =
359 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
360 // all context objects should be sketch entities
361 for (int i = 0, aSize = aRefListAttr->size(); i < aSize && isSketchEntities; i++) {
362 ObjectPtr anObject = aRefListAttr->object(i);
363 // a context of the selection attribute is a feature result. It can be a case when the result
364 // of the feature is null, e.g. the feature is modified and has not been executed yet.
365 // The validator returns an invalid result here. The case is an extrusion built on a sketch
366 // feature. A new sketch element creation leads to an empty result.
368 isSketchEntities = false;
370 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
371 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
375 if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
376 std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
377 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
378 isSketchEntities = false;
379 if (aRef->isObject()) {
380 ObjectPtr anObject = aRef->object();
381 if (anObject.get() != NULL) {
382 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
383 if (aFeature.get() != NULL)
384 isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
389 return isSketchEntities;
394 bool PartSet_SameTypeAttrValidator::isValid(const AttributePtr& theAttribute,
395 const std::list<std::string>& theArguments,
396 std::string& theError ) const
398 // there is a check whether the feature contains a point and a linear edge or two point values
399 std::string aParamA = theArguments.front();
400 SessionPtr aMgr = ModelAPI_Session::get();
401 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
403 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
404 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
408 bool isObject = aRefAttr->isObject();
409 ObjectPtr anObject = aRefAttr->object();
410 if (isObject && anObject) {
411 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
413 AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
414 ObjectPtr aOtherObject = aOtherAttr->object();
415 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
416 return aRefFea->getKind() == aOtherFea->getKind();
421 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
422 const std::list<std::string>& theArguments,
423 std::string& theError) const
425 // there is a check whether the feature contains a point and a linear edge or two point values
426 std::string aParamA = theArguments.front();
427 SessionPtr aMgr = ModelAPI_Session::get();
428 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
430 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
431 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
435 QList<FeaturePtr> aCoinsideLines;
437 bool isObject = aRefAttr->isObject();
438 ObjectPtr anObject = aRefAttr->object();
439 if (isObject && anObject) {
440 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
441 AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
442 ObjectPtr aOtherObject = aOtherAttr->object();
443 // if the other attribute is not filled still, the result is true
444 if (!aOtherObject.get())
446 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
448 // check that both have coincidence
449 FeaturePtr aConstrFeature;
450 std::set<FeaturePtr> aCoinList;
451 const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
452 std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
453 for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
454 std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
455 aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
456 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
457 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
458 AttributePtr aAR = aRAttr->attr();
459 if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
460 aCoinList.insert(aConstrFeature);
461 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
462 SketchPlugin_ConstraintCoincidence::ENTITY_A());
463 PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
464 SketchPlugin_ConstraintCoincidence::ENTITY_B());
467 // if there is no coincidence then it is not valid
468 if (aCoinList.size() == 0)
471 QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
473 for (; anIt != aLast && !aValid; anIt++) {
474 aValid = *anIt == aOtherFea;