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