Salome HOME
Error management -- Attribute validator returns an error.
[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_Object.h>
25 #include <ModelAPI_Session.h>
26
27 #include <SketchPlugin_Sketch.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_Arc.h>
30 #include <GeomAPI_Edge.h>
31
32 #include <list>
33 #ifdef _DEBUG
34 #include <iostream>
35 #endif
36
37 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
38 {
39   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
40   int aCount = 0;
41   foreach (ModuleBase_ViewerPrs aPrs, aList) {
42     const TopoDS_Shape& aShape = aPrs.shape();
43     if (!aShape.IsNull()) {
44       if (aShape.ShapeType() == TopAbs_VERTEX)
45         aCount++;
46     }
47   }
48   return aCount;
49 }
50
51 int shapesNbLines(const ModuleBase_ISelection* theSelection)
52 {
53   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
54   int aCount = 0;
55   foreach(ModuleBase_ViewerPrs aPrs, aList) {
56     const TopoDS_Shape& aShape = aPrs.shape();
57     if (!aShape.IsNull()) {
58       if (aShape.ShapeType() == TopAbs_EDGE) {
59         TopoDS_Edge aEdge = TopoDS::Edge(aShape);
60         Standard_Real aStart, aEnd;
61         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
62         GeomAdaptor_Curve aAdaptor(aCurve);
63         if (aAdaptor.GetType() == GeomAbs_Line)
64           aCount++;
65       }
66     }
67   }
68   return aCount;
69 }
70
71 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection) const
72 {
73   int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
74   return (aCount > 0) && (aCount < 3);
75 }
76
77 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection) const
78 {
79   int aCount = shapesNbLines(theSelection);
80   return (aCount == 1);
81 }
82
83 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection) const
84 {
85   int aCount = shapesNbLines(theSelection);
86   return (aCount > 0) && (aCount < 3);
87 }
88
89 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection) const
90 {
91   int aCount = shapesNbLines(theSelection);
92   return (aCount > 0) && (aCount < 3);
93 }
94
95 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection) const
96 {
97   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
98   ModuleBase_ViewerPrs aPrs;
99   int aCount = 0;
100   foreach (ModuleBase_ViewerPrs aPrs, aList) {
101     const TopoDS_Shape& aShape = aPrs.shape();
102     if (!aShape.IsNull()) {
103       if (aShape.ShapeType() == TopAbs_EDGE) {
104         TopoDS_Edge aEdge = TopoDS::Edge(aShape);
105         Standard_Real aStart, aEnd;
106         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
107         GeomAdaptor_Curve aAdaptor(aCurve);
108         if (aAdaptor.GetType() == GeomAbs_Circle)
109           aCount++;
110       }
111     }
112   }
113   return (aCount == 1);
114 }
115
116 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection) const
117 {
118   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
119   return (aList.count() == 1);
120 }
121
122
123 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection) const
124 {
125   int aCount = shapesNbPoints(theSelection);
126   return (aCount > 0) && (aCount < 3);
127 }
128
129 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection) const
130 {
131   int aCount = shapesNbLines(theSelection);
132   return (aCount == 1);
133 }
134
135 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection) const
136 {
137   int aCount = shapesNbLines(theSelection);
138   return (aCount > 0) && (aCount < 3);
139 }
140
141 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection) const
142 {
143   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
144   if ((aList.size() == 0) || (aList.size() > 2))
145     return false;
146
147   ModuleBase_ViewerPrs aPrs = aList.first();
148   const TopoDS_Shape& aShape = aPrs.shape();
149   if (aShape.IsNull())
150     return false;
151
152   if (aShape.ShapeType() != TopAbs_EDGE)
153     return false;
154
155   std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
156   aShapePtr->setImpl(new TopoDS_Shape(aShape));
157   GeomAPI_Edge aEdge1(aShapePtr);
158
159   if (aEdge1.isLine() || aEdge1.isArc()) {
160     if (aList.size() == 2) {
161       // Check second selection
162       aPrs = aList.last();
163       const TopoDS_Shape& aShape2 = aPrs.shape();
164       if (aShape2.IsNull())
165         return false;
166
167       if (aShape2.ShapeType() != TopAbs_EDGE)
168         return false;
169
170       std::shared_ptr<GeomAPI_Shape> aShapePtr2(new GeomAPI_Shape);
171       aShapePtr2->setImpl(new TopoDS_Shape(aShape2));
172       GeomAPI_Edge aEdge2(aShapePtr2);
173       if (aEdge1.isLine() && aEdge2.isArc())
174         return true;
175       else if (aEdge1.isArc() && aEdge2.isLine())
176         return true;
177       else
178         return false;
179     } else
180       return true;
181   }
182   return false;
183 }
184
185
186 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
187                                                 const std::list<std::string>& theArguments,
188                                                 std::string& theError) const
189 {
190   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
191
192   // the type of validated attributes should be equal, attributes with different types are not validated
193   // Check RefAttr attributes
194   std::string anAttrType = theAttribute->attributeType();
195   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
196
197   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
198     AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
199     bool isObject = anAttr->isObject();
200     ObjectPtr anObject = anAttr->object();
201     AttributePtr anAttributeAttr = anAttr->attr();
202
203     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
204     if (anAttrs.size() > 0) {
205       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
206       for(; anAttr != anAttrs.end(); anAttr++) {
207       if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
208           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
209                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
210           if (aRef->isObject() != isObject)
211             continue;
212           if (isObject) {
213             if (aRef->object() == anObject)
214               return false;
215           }
216           else { // the attribute reference
217             if (aRef->attr() == theAttribute)
218               return false;
219           }
220         }
221       }
222     }
223   }
224   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
225     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
226     ResultPtr aContext = anAttr->context();
227     GeomShapePtr aShape = anAttr->value();
228
229     // Check selection attributes
230     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
231     if (anAttrs.size() > 0) {
232       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
233       for(; anAttr != anAttrs.end(); anAttr++) {
234         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
235           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
236                                         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
237           // check the object is already presented
238           if (aRef->context() == aContext) {
239             bool aHasShape = aShape.get() != NULL;
240             if (!aHasShape || aRef->value()->isEqual(aShape))
241               return false;
242           }
243         }
244       }
245     }
246   }
247   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
248     AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
249     ObjectPtr anObject = anAttr->value();
250     // Check selection attributes
251     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
252     if (anAttrs.size() > 0) {
253       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
254       for(; anAttr != anAttrs.end(); anAttr++) {
255         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
256           std::shared_ptr<ModelAPI_AttributeReference> aRef =
257             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
258           // check the object is already presented
259           if (aRef->value() == anObject)
260             return false;
261         }
262         return true;
263       }
264     }
265   }
266   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
267     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList = 
268             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
269     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
270     if(anAttrs.size() > 0) {
271       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
272       for(; anAttrItr != anAttrs.end(); anAttrItr++){
273         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
274           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList = 
275             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
276           for(int i = 0; i < aCurSelList->size(); i++) {
277             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
278             for(int j = 0; j < aRefSelList->size(); j++) {
279               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
280               if(aCurSel->context() == aRefSel->context()) {
281                 if(aCurSel->value().get() == NULL || aRefSel->value().get() == NULL
282                   || aCurSel->value()->isEqual(aRefSel->value())) {
283                     return false;
284                 }
285               }
286             }
287           }
288         }
289       }
290     }
291   }
292   return !featureHasReferences(theAttribute);
293 }
294
295 bool PartSet_DifferentObjectsValidator::featureHasReferences(const AttributePtr& theAttribute) const
296 {
297   std::list<std::pair<std::string, std::list<ObjectPtr> > > allRefs;
298   if (theAttribute->owner().get() && theAttribute->owner()->data()->isValid())
299     theAttribute->owner()->data()->referencesToObjects(allRefs);
300   // collect object referenced by theAttribute
301   std::list<ObjectPtr>* anAttrObjs = 0;
302   std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefIter = allRefs.begin();
303   for(; aRefIter != allRefs.end(); aRefIter++) {
304     if (theAttribute->id() == aRefIter->first)
305       anAttrObjs = &(aRefIter->second);
306   }
307   if (!anAttrObjs || anAttrObjs->empty())
308     return false; // theAttribute does not references to anything
309   // check with all others
310   for(aRefIter = allRefs.begin(); aRefIter != allRefs.end(); aRefIter++) {
311     if (theAttribute->id() == aRefIter->first)
312       continue; // do not check with myself
313     std::list<ObjectPtr>::iterator aReferenced = aRefIter->second.begin();
314     for(; aReferenced != aRefIter->second.end(); aReferenced++) {
315       std::list<ObjectPtr>::iterator aReferencedByMe = anAttrObjs->begin();
316       for(; aReferencedByMe != anAttrObjs->end(); aReferencedByMe++) {
317         if (*aReferenced == *aReferencedByMe) // found same objects!
318           return true;
319       }
320     }
321   }
322   return false;
323 }
324
325 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
326                                             const std::list<std::string>& theArguments,
327                                             std::string& theError) const
328 {
329   bool isSketchEntities = true;
330   std::set<std::string> anEntityKinds;
331   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
332   for (; anIt != aLast; anIt++) {
333     anEntityKinds.insert(*anIt);
334   }
335
336   std::string anAttributeType = theAttribute->attributeType();
337   if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
338     AttributeSelectionListPtr aSelectionListAttr = 
339                       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
340     // it filters only selection list attributes
341     std::string aType = aSelectionListAttr->selectionType().c_str();
342     // all context objects should be sketch entities
343     int aSize = aSelectionListAttr->size();
344     for (int i = 0; i < aSelectionListAttr->size() && isSketchEntities; i++) {
345       AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
346       ObjectPtr anObject = aSelectAttr->context();
347       // a context of the selection attribute is a feature result. It can be a case when the result
348       // of the feature is null, e.g. the feature is modified and has not been executed yet.
349       // The validator returns an invalid result here. The case is an extrusion built on a sketch
350       // feature. A new sketch element creation leads to an empty result.
351       if (!anObject.get())
352         isSketchEntities = false;
353       else {
354         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
355         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
356       }
357     }
358   }
359   if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
360     std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = 
361                      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
362     isSketchEntities = false;
363     if (aRef->isObject()) {
364       ObjectPtr anObject = aRef->object();
365       if (anObject.get() != NULL) {
366         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
367         if (aFeature.get() != NULL)
368           isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
369       }
370     }
371   }
372
373   return isSketchEntities;
374 }
375
376
377
378 bool PartSet_SameTypeAttrValidator::isValid(const AttributePtr& theAttribute, 
379                                             const std::list<std::string>& theArguments,
380                                             std::string& theError ) const
381 {
382   // there is a check whether the feature contains a point and a linear edge or two point values
383   std::string aParamA = theArguments.front();
384   SessionPtr aMgr = ModelAPI_Session::get();
385   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
386
387   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
388   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
389   if (!aRefAttr)
390     return false;
391
392   bool isObject = aRefAttr->isObject();
393   ObjectPtr anObject = aRefAttr->object();
394   if (isObject && anObject) {
395     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
396
397     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
398     ObjectPtr aOtherObject = aOtherAttr->object();
399     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
400     return aRefFea->getKind() == aOtherFea->getKind();
401   }
402   return false;
403 }
404
405 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
406                                      const std::list<std::string>& theArguments,
407                                      std::string& theError) const
408 {
409   // there is a check whether the feature contains a point and a linear edge or two point values
410   std::string aParamA = theArguments.front();
411   SessionPtr aMgr = ModelAPI_Session::get();
412   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
413
414   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
415   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
416   if (!aRefAttr)
417     return false;
418
419   QList<FeaturePtr> aCoinsideLines;
420
421   bool isObject = aRefAttr->isObject();
422   ObjectPtr anObject = aRefAttr->object();
423   if (isObject && anObject) {
424     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
425     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
426     ObjectPtr aOtherObject = aOtherAttr->object();
427     // if the other attribute is not filled still, the result is true
428     if (!aOtherObject.get())
429       return true;
430     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
431
432     // check that both have coincidence
433     FeaturePtr aConstrFeature;
434     std::set<FeaturePtr> aCoinList;
435     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
436     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
437     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
438       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
439       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
440       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
441         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
442         AttributePtr aAR = aRAttr->attr();
443         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
444           aCoinList.insert(aConstrFeature);
445           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
446                                           SketchPlugin_ConstraintCoincidence::ENTITY_A());
447           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
448                                           SketchPlugin_ConstraintCoincidence::ENTITY_B());
449       }
450     }
451     // if there is no coincidence then it is not valid
452     if (aCoinList.size() == 0)
453       return false;
454
455     QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
456     bool aValid = false;
457     for (; anIt != aLast && !aValid; anIt++) {
458       aValid = *anIt == aOtherFea;
459     }
460     if (aValid)
461       return true;
462   }
463   return false;
464 }
465