Salome HOME
Fillet creation fixes
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_Validators.cpp
4 // Created:     01 Aug 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "SketchPlugin_Validators.h"
8
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_Circle.h"
11 #include "SketchPlugin_ConstraintCoincidence.h"
12 #include "SketchPlugin_ConstraintDistance.h"
13 #include "SketchPlugin_ConstraintRigid.h"
14 #include "SketchPlugin_Line.h"
15 #include "SketchPlugin_Point.h"
16 #include "SketchPlugin_Sketch.h"
17 #include "SketchPlugin_Tools.h"
18
19 #include "SketcherPrs_Tools.h"
20
21 #include <ModelAPI_Data.h>
22 #include <ModelAPI_Validator.h>
23 #include <ModelAPI_AttributeDouble.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_Session.h>
29
30 #include <GeomValidators_ShapeType.h>
31
32 #include <GeomDataAPI_Point2D.h>
33
34
35 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, 
36                                                  const std::list<std::string>& theArguments,
37                                                  std::string& theError) const
38 {
39   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
40     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
41     return false;
42   }
43
44   // there is a check whether the feature contains a point and a linear edge or two point values
45   std::string aParamA = theArguments.front();
46   SessionPtr aMgr = ModelAPI_Session::get();
47   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
48
49   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
50   bool isObject = aRefAttr->isObject();
51   if (!isObject) {
52     // an attribute is a point. A point value is valid always for the distance
53     return true;
54   } else {
55     // 1. check whether the references object is a linear
56     ObjectPtr anObject = aRefAttr->object();
57
58     const ModelAPI_AttributeValidator* aShapeValidator = 
59       dynamic_cast<const GeomValidators_ShapeType*>(aFactory->validator("GeomValidators_ShapeType"));
60     std::list<std::string> anArguments;
61     anArguments.push_back("circle");
62     std::string aCircleError;
63     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
64     // the circle line is not a valid case
65     if (aShapeValid) {
66       theError = "Circle can not be used in distance constraint";
67       return false;
68     }
69       
70     anArguments.clear();
71     anArguments.push_back("line");
72     std::string aLineError;
73     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
74     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
75     if (aShapeValid) {
76       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
77       // If it is a line then we have to check that first attribute id not a line
78       std::shared_ptr<SketchPlugin_Feature> aSFeature =
79         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
80       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
81       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
82       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
83         aFeature->data(), aParamA, aPlane);
84       if (!aPoint.get()) {
85         theError = "One of parameters of distance constraint should be a point";
86         return false;
87       }
88     }
89   }
90   return true;
91 }
92
93 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, 
94                                                 const std::list<std::string>& theArguments,
95                                                 std::string& theError) const
96 {
97   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
98     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
99     return false;
100   }
101
102   // there is a check whether the feature contains a point and a linear edge or two point values
103   std::string aParamA = theArguments.front();
104   SessionPtr aMgr = ModelAPI_Session::get();
105   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
106
107   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
108   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
109
110   bool isObject = aRefAttr->isObject();
111   ObjectPtr anObject = aRefAttr->object();
112   if (isObject && anObject.get()) {
113     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
114
115     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
116     ObjectPtr aOtherObject = aOtherAttr->object();
117     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
118
119     if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
120       if (aOtherFea->getKind() != SketchPlugin_Arc::ID()) {
121         theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is not an "
122           + SketchPlugin_Arc::ID();
123         return false;
124       }
125     }
126     else if (aRefFea->getKind() == SketchPlugin_Arc::ID()) {
127       if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
128         aOtherFea->getKind() != SketchPlugin_Arc::ID()) {
129         theError = "It refers to an " + SketchPlugin_Arc::ID() + ", but " + aParamA + " is not a "
130           + SketchPlugin_Line::ID() + " or an " + SketchPlugin_Arc::ID();
131         return false;
132       }
133     }
134     else {
135       theError = "It refers to " + aRefFea->getKind() + "but should refer to " + SketchPlugin_Line::ID()
136         + " or " + SketchPlugin_Arc::ID();
137       return false;
138     }
139     return true;
140   }
141   else {
142     theError = "It uses an empty object";
143     return false;
144   }
145
146   return true;
147 }
148
149 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute, 
150                                              const std::list<std::string>& theArguments,
151                                              std::string& theError) const
152 {
153   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
154     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
155     return false;
156   }
157
158   std::shared_ptr<SketchPlugin_Feature> aFeature =
159       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
160   if (!aFeature)
161     return true;
162
163   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
164
165   SketchPlugin_Sketch* aSketch = aFeature->sketch();
166   int aNbFeatures = aSketch->numberOfSubs();
167   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
168     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
169     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
170       continue;
171     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
172         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
173     if (aRefAttr->isObject()) {
174       if (aRefAttr->object() == aRAttr->object()) {
175         ObjectPtr anObject = aRefAttr->object();
176         std::string aName = anObject.get() ? anObject->data()->name() : "";
177         theError = "The object " + aName + " has been already fixed.";
178         return false;
179       }
180     }
181     else if (aRefAttr->attr() == aRAttr->attr()) {
182       AttributePtr anAttribute = aRefAttr->attr();
183       std::string aName = anAttribute.get() ? anAttribute->id() : "";
184       theError = "The attribute " + aName + " has been already fixed.";
185       return false;
186     }
187   }
188   return true;
189 }
190
191 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, 
192                                               const std::list<std::string>& theArguments,
193                                               std::string& theError) const
194 {
195   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
196     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
197     return false;
198   }
199
200   std::string aParamA = theArguments.front();
201   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
202   AttributeRefAttrPtr aRefAttr[2];
203   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
204   aRefAttr[1] = aFeature->data()->refattr(aParamA);
205
206   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
207     theError = "Attributes can not be used in equal constraint";
208     return false;
209   }
210
211   int aType[2] = {0, 0}; // types of attributes: 0 - incorrect, 1 - line, 2 - circle, 3 - arc
212   std::list<std::string> anArguments;
213   for (int i = 0; i < 2; i++) {
214     ObjectPtr anObject = aRefAttr[i]->object();
215     if (!anObject.get()) {
216       theError = "An empty object is used.";
217       return false;
218     }
219
220     aFeature = ModelAPI_Feature::feature(anObject);
221     if (!aFeature.get()) {
222       theError = "An empty feature is used.";
223       return false;
224     }
225
226     if (aFeature->getKind() == SketchPlugin_Line::ID()) {
227       aType[i] = 1;
228       continue;
229     }
230     if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
231       aType[i] = 2;
232       continue;
233     }
234     if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
235       aType[i] = 3;
236       continue;
237     }
238     theError = "The " + aFeature->getKind() + " feature kind of attribute is wrong. It should be " +
239                SketchPlugin_Line::ID() + " or " + SketchPlugin_Circle::ID() + " or " + 
240                SketchPlugin_Arc::ID();
241     // wrong type of attribute
242     return false;
243   }
244
245   if ((aType[0] == 1 && aType[1] == 2) ||
246       (aType[0] == 2 && aType[1] == 1)) {
247     theError = "Feature with kinds " + SketchPlugin_Line::ID() + " and " +
248                SketchPlugin_Circle::ID() + "can not be equal.";
249     return false;
250   }
251   return true;
252 }
253
254 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, 
255                                                const std::list<std::string>& theArguments,
256                                                std::string& theError) const
257 {
258   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
259     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
260     return false;
261   }
262
263   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
264   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
265
266   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
267       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
268   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
269
270   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
271     ObjectPtr aSelObject = aSelAttr->object(anInd);
272     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
273     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
274     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
275       if (aSelObject == *aMirIter) {
276         theError = "The object " + aName + " is a result of mirror";
277         return false;
278       }
279   }
280   return true;
281 }
282
283
284 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, 
285                                                     const std::list<std::string>& theArguments,
286                                                     std::string& theError) const
287 {
288   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
289     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
290     return false;
291   }
292
293   // there is a check whether the feature contains a point and a linear edge or two point values
294   std::string aParamA = theArguments.front();
295   SessionPtr aMgr = ModelAPI_Session::get();
296   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
297
298   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
299   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
300   if (!aRefAttrA) {
301     theError = "The " + aParamA + " attribute " + " should be " + ModelAPI_AttributeRefAttr::typeId();
302     return false;
303   }
304
305   AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
306
307   // first attribute is a point, it may coincide with any object
308   if (!aRefAttrA->isObject())
309     return true;
310   else {
311     ObjectPtr anObject = aRefAttrA->object();
312     if (!anObject.get()) {
313       theError = aParamA + " attribute has an empty object";
314       return false;
315     }
316     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
317     if (!aFeature.get()) {
318       theError = aParamA + " attribute has an empty feature";
319       return false;
320     }
321
322     if (aFeature->getKind() == SketchPlugin_Point::ID())
323       return true;
324   }
325
326   // second attribute is a point, it may coincide with any object
327   if (!aRefAttrB->isObject())
328     return true;
329   else {
330     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
331     if (!aFeature) {
332       theError = theAttribute->id() + " attribute has an empty object";
333       return false;
334     }
335     if (aFeature->getKind() == SketchPlugin_Point::ID())
336       return true;
337   }
338   theError = "There is no an attribute filled by a point";
339   return false;
340 }
341
342
343 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, 
344                                          const std::list<std::string>& theArguments,
345                                          std::string& theError) const
346 {
347   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
348     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
349     return false;
350   }
351
352   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
353   AttributeRefListPtr aSelAttr = 
354     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
355
356   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
357       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
358   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
359       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
360   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
361   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
362
363   std::list<ObjectPtr>::iterator anObjIter;
364   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
365     ObjectPtr aSelObject = aSelAttr->object(anInd);
366     anObjIter = anInitialObjects.begin();
367     for (; anObjIter != anInitialObjects.end(); anObjIter++)
368       if (aSelObject == *anObjIter)
369         break;
370     if (anObjIter != anInitialObjects.end())
371       continue;
372     anObjIter = aCopiedObjects.begin();
373     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
374       if (aSelObject == *anObjIter) {
375         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
376         theError = "The object " + aName + " is a result of copy";
377         return false;
378       }
379   }
380   return true;
381 }
382
383 bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
384                                                 const std::list<std::string>& theArguments,
385                                                 std::string& theError) const
386 {
387   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
388
389   if (!aAttributeString->value().empty()) {
390     theError = aAttributeString->value();
391     return false;
392   }
393
394   return true;
395 }
396
397 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature, std::string theAttribute)
398 {
399   return true;
400 }
401
402 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
403                                                  const std::list<std::string>& theArguments,
404                                                  std::string& theError) const
405 {
406   if(!theAttribute.get()) {
407     return false;
408   }
409
410   AttributeRefAttrPtr aBase = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
411   if(aBase->isObject()) {
412     return false;
413   }
414
415   // If we alredy have some result then all ok
416   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
417   AttributePtr aBaseLinesAttribute = aFeature->attribute(SketchPlugin_Constraint::ENTITY_C());
418   AttributeRefListPtr aRefListOfBaseLines = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aBaseLinesAttribute);
419   if(aRefListOfBaseLines->list().size() == 2) {
420     return true;
421   }
422
423   AttributePtr anAttrBase = aBase->attr();
424   const std::set<AttributePtr>& aRefsList = anAttrBase->owner()->data()->refsToMe();
425   std::set<AttributePtr>::const_iterator aIt;
426   FeaturePtr aCoincident;
427   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
428     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
429     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
430     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
431       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
432         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
433       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
434         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
435       if(anAttrRefA.get() && !anAttrRefA->isObject()) {
436         AttributePtr anAttrA = anAttrRefA->attr();
437         if(anAttrBase == anAttrA) {
438           aCoincident = aConstrFeature;
439           break;
440         }
441       }
442       if(anAttrRefA.get() && !anAttrRefB->isObject()) {
443         AttributePtr anAttrB = anAttrRefB->attr();
444         if(anAttrBase == anAttrB) {
445           aCoincident = aConstrFeature;
446           break;
447         }
448       }
449     }
450   }
451
452   if(!aCoincident.get()) {
453     return false;
454   }
455
456   std::set<FeaturePtr> aCoinsideLines;
457   SketchPlugin_Tools::findCoincidences(aCoincident,
458                                        SketchPlugin_ConstraintCoincidence::ENTITY_A(),
459                                        aCoinsideLines);
460   SketchPlugin_Tools::findCoincidences(aCoincident,
461                                        SketchPlugin_ConstraintCoincidence::ENTITY_B(),
462                                        aCoinsideLines);
463   if(aCoinsideLines.size() < 2) {
464     return false;
465   }
466
467   // Remove auxilary lines
468   if(aCoinsideLines.size() > 2) {
469     std::set<FeaturePtr> aNewLines;
470     for(std::set<FeaturePtr>::iterator anIt = aCoinsideLines.begin(); anIt != aCoinsideLines.end(); ++anIt) {
471       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
472         aNewLines.insert(*anIt);
473       }
474     }
475     aCoinsideLines = aNewLines;
476   }
477
478   if(aCoinsideLines.size() != 2) {
479     return false;
480   }
481
482   // Check that lines not collinear
483   std::set<FeaturePtr>::iterator anIt = aCoinsideLines.begin();
484   FeaturePtr aFirstFeature = *anIt++;
485   FeaturePtr aSecondFeature = *anIt;
486   if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
487     std::string aStartAttr = SketchPlugin_Line::START_ID();
488     std::string anEndAttr = SketchPlugin_Line::END_ID();
489     std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
490     aFirstStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(aStartAttr))->pnt();
491     aFirstEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
492     aSecondStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(aStartAttr))->pnt();
493     aSecondEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(anEndAttr))->pnt();
494     double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) -
495       (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
496     double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) -
497       (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
498     if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
499       return false;
500     }
501   }
502
503   return true;
504 }