Salome HOME
8c5bd25ed41fb12eb6624a0f0f88d937431ea46a
[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_AttributeRefList.h>
25 #include <ModelAPI_Object.h>
26 #include <ModelAPI_Session.h>
27
28 #include <SketchPlugin_Sketch.h>
29 #include <SketchPlugin_ConstraintCoincidence.h>
30 #include <SketchPlugin_Arc.h>
31 #include <GeomAPI_Edge.h>
32
33 #include <list>
34 #ifdef _DEBUG
35 #include <iostream>
36 #endif
37
38 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
39 {
40   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
41   int aCount = 0;
42   foreach (ModuleBase_ViewerPrs aPrs, aList) {
43     const TopoDS_Shape& aShape = aPrs.shape();
44     if (!aShape.IsNull()) {
45       if (aShape.ShapeType() == TopAbs_VERTEX)
46         aCount++;
47     }
48   }
49   return aCount;
50 }
51
52 int shapesNbLines(const ModuleBase_ISelection* theSelection)
53 {
54   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
55   int aCount = 0;
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)
65           aCount++;
66       }
67     }
68   }
69   return aCount;
70 }
71
72 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection) const
73 {
74   int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
75   return (aCount > 0) && (aCount < 3);
76 }
77
78 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection) const
79 {
80   int aCount = shapesNbLines(theSelection);
81   return (aCount == 1);
82 }
83
84 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection) const
85 {
86   int aCount = shapesNbLines(theSelection);
87   return (aCount > 0) && (aCount < 3);
88 }
89
90 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection) const
91 {
92   int aCount = shapesNbLines(theSelection);
93   return (aCount > 0) && (aCount < 3);
94 }
95
96 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection) const
97 {
98   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
99   ModuleBase_ViewerPrs aPrs;
100   int aCount = 0;
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)
110           aCount++;
111       }
112     }
113   }
114   return (aCount == 1);
115 }
116
117 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection) const
118 {
119   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
120   return (aList.count() == 1);
121 }
122
123
124 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection) const
125 {
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);
130 }
131
132 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection) const
133 {
134   int aCount = shapesNbLines(theSelection);
135   return (aCount == 1);
136 }
137
138 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection) const
139 {
140   int aCount = shapesNbLines(theSelection);
141   return (aCount > 0) && (aCount < 3);
142 }
143
144 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection) const
145 {
146   QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
147   if ((aList.size() == 0) || (aList.size() > 2))
148     return false;
149
150   ModuleBase_ViewerPrs aPrs = aList.first();
151   const TopoDS_Shape& aShape = aPrs.shape();
152   if (aShape.IsNull())
153     return false;
154
155   if (aShape.ShapeType() != TopAbs_EDGE)
156     return false;
157
158   std::shared_ptr<GeomAPI_Shape> aShapePtr(new GeomAPI_Shape);
159   aShapePtr->setImpl(new TopoDS_Shape(aShape));
160   GeomAPI_Edge aEdge1(aShapePtr);
161
162   if (aEdge1.isLine() || aEdge1.isArc()) {
163     if (aList.size() == 2) {
164       // Check second selection
165       aPrs = aList.last();
166       const TopoDS_Shape& aShape2 = aPrs.shape();
167       if (aShape2.IsNull())
168         return false;
169
170       if (aShape2.ShapeType() != TopAbs_EDGE)
171         return false;
172
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())
177         return true;
178       else if (aEdge1.isArc() && aEdge2.isLine())
179         return true;
180       else
181         return false;
182     } else
183       return true;
184   }
185   return false;
186 }
187
188 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection) const
189 {
190   int aCount = shapesNbLines(theSelection);
191   return (aCount > 0) && (aCount < 3);
192 }
193
194
195 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
196                                                 const std::list<std::string>& theArguments,
197                                                 std::string& theError) const
198 {
199   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
200
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;
205
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();
211
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)
220             continue;
221           if (isObject) {
222             if (aRef->object() == anObject)
223               return false;
224           }
225           else { // the attribute reference
226             if (aRef->attr() == theAttribute)
227               return false;
228           }
229         }
230       }
231     }
232   }
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();
237
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))
250               return false;
251           }
252         }
253       }
254     }
255   }
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)
269             return false;
270         }
271         return true;
272       }
273     }
274   }
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())) {
292                     return false;
293                 }
294               }
295             }
296           }
297         }
298       }
299     }
300   }
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)) {
315                 return false;
316               }
317             }
318           }
319         }
320       }
321     }
322   }
323   return true;
324 }
325
326 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
327                                             const std::list<std::string>& theArguments,
328                                             std::string& theError) const
329 {
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);
335   }
336
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.
349       if (!anObject.get())
350         isSketchEntities = false;
351       else {
352         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
353         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
354       }
355     }
356   }
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.
367       if (!anObject.get())
368         isSketchEntities = false;
369       else {
370         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
371         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
372       }
373     }
374   }
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();
385       }
386     }
387   }
388
389   return isSketchEntities;
390 }
391
392
393
394 bool PartSet_SameTypeAttrValidator::isValid(const AttributePtr& theAttribute, 
395                                             const std::list<std::string>& theArguments,
396                                             std::string& theError ) const
397 {
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();
402
403   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
404   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
405   if (!aRefAttr)
406     return false;
407
408   bool isObject = aRefAttr->isObject();
409   ObjectPtr anObject = aRefAttr->object();
410   if (isObject && anObject) {
411     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
412
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();
417   }
418   return false;
419 }
420
421 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
422                                      const std::list<std::string>& theArguments,
423                                      std::string& theError) const
424 {
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();
429
430   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
431   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
432   if (!aRefAttr)
433     return false;
434
435   QList<FeaturePtr> aCoinsideLines;
436
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())
445       return true;
446     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
447
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());
465       }
466     }
467     // if there is no coincidence then it is not valid
468     if (aCoinList.size() == 0)
469       return false;
470
471     QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
472     bool aValid = false;
473     for (; anIt != aLast && !aValid; anIt++) {
474       aValid = *anIt == aOtherFea;
475     }
476     if (aValid)
477       return true;
478   }
479   return false;
480 }
481