Salome HOME
431cc0347c0c88618acda48017462a26eb90f91d
[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_ConstraintFillet.h"
14 #include "SketchPlugin_ConstraintRigid.h"
15 #include "SketchPlugin_Line.h"
16 #include "SketchPlugin_Point.h"
17 #include "SketchPlugin_Sketch.h"
18 #include "SketchPlugin_Tools.h"
19
20 #include "SketcherPrs_Tools.h"
21
22 #include <ModelAPI_Data.h>
23 #include <ModelAPI_Validator.h>
24 #include <ModelAPI_AttributeDouble.h>
25 #include <ModelAPI_AttributeRefAttr.h>
26
27 #include <ModelAPI_AttributeRefAttrList.h>
28 #include <ModelAPI_AttributeRefList.h>
29 #include <ModelAPI_AttributeSelectionList.h>
30 #include <ModelAPI_AttributeString.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_ResultConstruction.h>
33
34 #include <GeomAPI_Lin.h>
35 #include <GeomAPI_Edge.h>
36 #include <GeomAPI_Vertex.h>
37 #include <GeomDataAPI_Point2D.h>
38
39 #include <algorithm>
40 #include <cmath>
41
42 const double tolerance = 1.e-7;
43
44 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, 
45                                                  const std::list<std::string>& theArguments,
46                                                  std::string& theError) const
47 {
48   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
49     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
50     return false;
51   }
52
53   // there is a check whether the feature contains a point and a linear edge or two point values
54   std::string aParamA = theArguments.front();
55   SessionPtr aMgr = ModelAPI_Session::get();
56   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
57
58   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
59   bool isObject = aRefAttr->isObject();
60   if (!isObject) {
61     // an attribute is a point. A point value is valid always for the distance
62     return true;
63   } else {
64     // 1. check whether the references object is a linear
65     ObjectPtr anObject = aRefAttr->object();
66
67     const ModelAPI_AttributeValidator* aShapeValidator = 
68       dynamic_cast<const ModelAPI_AttributeValidator*>(aFactory->validator("GeomValidators_ShapeType"));
69     std::list<std::string> anArguments;
70     anArguments.push_back("circle");
71     std::string aCircleError;
72     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
73     // the circle line is not a valid case
74     if (aShapeValid) {
75       theError = "Circle can not be used in distance constraint";
76       return false;
77     }
78       
79     anArguments.clear();
80     anArguments.push_back("line");
81     std::string aLineError;
82     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
83     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
84     if (aShapeValid) {
85       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
86       // If it is a line then we have to check that first attribute id not a line
87       std::shared_ptr<SketchPlugin_Feature> aSFeature =
88         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
89       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
90       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
91       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
92         aFeature->data(), aParamA, aPlane);
93       if (!aPoint.get()) {
94         theError = "One of parameters of distance constraint should be a point";
95         return false;
96       }
97     }
98   }
99   return true;
100 }
101
102
103 static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2)
104 {
105   FeaturePtr aConstrFeature;
106   std::list<AttributePtr> anAttrList;
107   if (theFeature1->getKind() == SketchPlugin_Circle::ID() ||
108       theFeature2->getKind() == SketchPlugin_Circle::ID())
109     return false;
110   if (theFeature2->getKind() == SketchPlugin_Line::ID()) {
111     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID()));
112     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID()));
113   } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) {
114     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID()));
115     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID()));
116   }
117
118   const std::set<AttributePtr>& aRefsList = theFeature1->data()->refsToMe();
119   std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
120   for (; aRefIt != aRefsList.end(); ++aRefIt) {
121     aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
122     if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
123       continue;
124     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
125     AttributePtr anAttr = aRefAttr->attr();
126     if (anAttr->id() == SketchPlugin_Arc::CENTER_ID())
127       continue;
128
129     anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
130     if (anAttr == *aRefIt)
131       anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
132
133     aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
134     if (!aRefAttr)
135       continue;
136     anAttr = aRefAttr->attr();
137     for (std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
138          anIt != anAttrList.end(); ++anIt)
139       if (*anIt == anAttr)
140         return true;
141   }
142   return false;
143 }
144
145 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, 
146                                                 const std::list<std::string>& theArguments,
147                                                 std::string& theError) const
148 {
149   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
150     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
151     return false;
152   }
153
154   // there is a check whether the feature contains a point and a linear edge or two point values
155   std::string aParamA = theArguments.front();
156   SessionPtr aMgr = ModelAPI_Session::get();
157   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
158
159   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
160   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
161
162   bool isObject = aRefAttr->isObject();
163   ObjectPtr anObject = aRefAttr->object();
164   if (isObject && anObject.get()) {
165     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
166
167     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
168     ObjectPtr aOtherObject = aOtherAttr->object();
169     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
170     if (!aOtherFea)
171       return true;
172
173     if ((aRefFea->getKind() == SketchPlugin_Arc::ID() ||
174         aOtherFea->getKind() == SketchPlugin_Arc::ID()) &&
175         !hasCoincidentPoint(aRefFea, aOtherFea))
176       return false;
177
178     if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
179       if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
180           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
181         theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is neither an "
182           + SketchPlugin_Arc::ID() + " nor " + SketchPlugin_Circle::ID();
183         return false;
184       }
185     }
186     else if (aRefFea->getKind() == SketchPlugin_Arc::ID()) {
187       if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
188         aOtherFea->getKind() != SketchPlugin_Arc::ID()) {
189         theError = "It refers to an " + SketchPlugin_Arc::ID() + ", but " + aParamA + " is not a "
190           + SketchPlugin_Line::ID() + " or an " + SketchPlugin_Arc::ID();
191         return false;
192       }
193     }
194     else if (aRefFea->getKind() == SketchPlugin_Circle::ID()) {
195       if (aOtherFea->getKind() != SketchPlugin_Line::ID()) {
196         theError = "It refers to an " + SketchPlugin_Circle::ID() + ", but " + aParamA + " is not a "
197           + SketchPlugin_Line::ID();
198         return false;
199       }
200     }
201     else {
202       theError = "It refers to " + aRefFea->getKind() + ", but should refer to " + SketchPlugin_Line::ID()
203         + " or " + SketchPlugin_Arc::ID() + " or " + SketchPlugin_Circle::ID();
204       return false;
205     }
206     return true;
207   }
208   else {
209     theError = "It uses an empty object";
210     return false;
211   }
212
213   return true;
214 }
215
216 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
217                                              const std::list<std::string>& theArguments,
218                                              std::string& theError) const
219 {
220   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
221     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
222     return false;
223   }
224
225   std::shared_ptr<SketchPlugin_Feature> aFeature =
226       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
227   if (!aFeature)
228     return true;
229
230   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
231
232   SketchPlugin_Sketch* aSketch = aFeature->sketch();
233   int aNbFeatures = aSketch->numberOfSubs();
234   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
235     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
236     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
237       continue;
238     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
239         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
240     if (aRefAttr->isObject()) {
241       if (aRefAttr->object() == aRAttr->object()) {
242         ObjectPtr anObject = aRefAttr->object();
243         std::string aName = anObject.get() ? anObject->data()->name() : "";
244         theError = "The object " + aName + " has been already fixed.";
245         return false;
246       }
247     }
248     else if (aRefAttr->attr() == aRAttr->attr()) {
249       AttributePtr anAttribute = aRefAttr->attr();
250       std::string aName = anAttribute.get() ? anAttribute->id() : "";
251       theError = "The attribute " + aName + " has been already fixed.";
252       return false;
253     }
254   }
255   return true;
256 }
257
258 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, 
259                                               const std::list<std::string>& theArguments,
260                                               std::string& theError) const
261 {
262   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
263     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
264     return false;
265   }
266
267   std::string aParamA = theArguments.front();
268   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
269   AttributeRefAttrPtr aRefAttr[2];
270   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
271   aRefAttr[1] = aFeature->data()->refattr(aParamA);
272
273   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
274     theError = "Attributes can not be used in equal constraint";
275     return false;
276   }
277
278   std::string aType[2];
279   std::list<std::string> anArguments;
280   for (int i = 0; i < 2; i++) {
281     ObjectPtr anObject = aRefAttr[i]->object();
282     if (!anObject.get()) {
283       theError = "An empty object is used.";
284       return false;
285     }
286
287     aFeature = ModelAPI_Feature::feature(anObject);
288     if (!aFeature.get()) {
289       theError = "An empty feature is used.";
290       return false;
291     }
292
293     aType[i] = aFeature->getKind();
294     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
295         aFeature->getKind() != SketchPlugin_Circle::ID() &&
296         aFeature->getKind() != SketchPlugin_Arc::ID()) {
297       theError = "The " + aFeature->getKind() + " feature kind of attribute is wrong. It should be " +
298                  SketchPlugin_Line::ID() + " or " + SketchPlugin_Circle::ID() + " or " + 
299                  SketchPlugin_Arc::ID();
300       // wrong type of attribute
301       return false;
302     }
303   }
304
305   if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) &&
306       aType[0] != aType[1]) {
307     theError = "Feature with kinds " + aType[0] + " and " + aType[1] + "can not be equal.";
308     return false;
309   }
310   return true;
311 }
312
313 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, 
314                                                const std::list<std::string>& theArguments,
315                                                std::string& theError) const
316 {
317   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
318     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
319     return false;
320   }
321
322   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
323   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
324
325   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
326       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
327   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
328
329   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
330     ObjectPtr aSelObject = aSelAttr->object(anInd);
331     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
332     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
333     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
334       if (aSelObject == *aMirIter) {
335         theError = "The object " + aName + " is a result of mirror";
336         return false;
337       }
338   }
339   return true;
340 }
341
342 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, 
343                                                     const std::list<std::string>& theArguments,
344                                                     std::string& theError) const
345 {
346   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
347     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
348     return false;
349   }
350
351   // there is a check whether the feature contains a point and a linear edge or two point values
352   std::string aParamA = theArguments.front();
353   SessionPtr aMgr = ModelAPI_Session::get();
354   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
355
356   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
357   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
358   if (!aRefAttrA) {
359     theError = "The " + aParamA + " attribute " + " should be " + ModelAPI_AttributeRefAttr::typeId();
360     return false;
361   }
362
363   AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
364
365   // first attribute is a point, it may coincide with any object
366   if (!aRefAttrA->isObject())
367     return true;
368   else {
369     ObjectPtr anObject = aRefAttrA->object();
370     if (!anObject.get()) {
371       theError = aParamA + " attribute has an empty object";
372       return false;
373     }
374     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
375     if (!aFeature.get()) {
376       theError = aParamA + " attribute has an empty feature";
377       return false;
378     }
379
380     if (aFeature->getKind() == SketchPlugin_Point::ID())
381       return true;
382   }
383
384   // second attribute is a point, it may coincide with any object
385   if (!aRefAttrB->isObject())
386     return true;
387   else {
388     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
389     if (!aFeature) {
390       theError = theAttribute->id() + " attribute has an empty object";
391       return false;
392     }
393     if (aFeature->getKind() == SketchPlugin_Point::ID())
394       return true;
395   }
396   theError = "There is no an attribute filled by a point";
397   return false;
398 }
399
400
401 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, 
402                                          const std::list<std::string>& theArguments,
403                                          std::string& theError) const
404 {
405   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
406     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
407     return false;
408   }
409
410   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
411   AttributeRefListPtr aSelAttr = 
412     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
413
414   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
415       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
416   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
417       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
418   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
419   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
420
421   std::list<ObjectPtr>::iterator anObjIter;
422   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
423     ObjectPtr aSelObject = aSelAttr->object(anInd);
424     anObjIter = anInitialObjects.begin();
425     for (; anObjIter != anInitialObjects.end(); anObjIter++)
426       if (aSelObject == *anObjIter)
427         break;
428     if (anObjIter != anInitialObjects.end())
429       continue;
430     anObjIter = aCopiedObjects.begin();
431     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
432       if (aSelObject == *anObjIter) {
433         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
434         theError = "The object " + aName + " is a result of copy";
435         return false;
436       }
437   }
438   return true;
439 }
440
441 bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
442                                                 const std::list<std::string>& theArguments,
443                                                 std::string& theError) const
444 {
445   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
446
447   if (!aAttributeString->value().empty()) {
448     theError = aAttributeString->value();
449     return false;
450   }
451
452   return true;
453 }
454
455 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature, std::string theAttribute)
456 {
457   return true;
458 }
459
460 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
461                                                  const std::list<std::string>& theArguments,
462                                                  std::string& theError) const
463 {
464   std::shared_ptr<SketchPlugin_ConstraintFillet> aFilletFeature = std::dynamic_pointer_cast<SketchPlugin_ConstraintFillet>(theAttribute->owner());
465   AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
466   if(aPointsRefList->size() == 0) {
467     theError = "Error: List of points is empty.";
468     return false;
469   }
470
471   std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures> aPointsFeaturesMap = aFilletFeature->pointsFeaturesMap();
472   std::set<AttributePtr> aSetOfPointsOnResultEdges;
473   for(std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures>::iterator aPointsIter = aPointsFeaturesMap.begin();
474       aPointsIter != aPointsFeaturesMap.end();
475       ++aPointsIter) {
476     const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second;
477     const std::list<FeaturePtr>& aResultEdges = aFeatures.resultEdges;
478     for(std::list<FeaturePtr>::const_iterator aResultIter = aResultEdges.cbegin();
479         aResultIter != aResultEdges.cend();
480         ++aResultIter) {
481       FeaturePtr aResultFeature = *aResultIter;
482       if(aResultFeature->getKind() == SketchPlugin_Line::ID()) {
483         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID()));
484         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID()));
485       } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) {
486         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID()));
487         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID()));
488       }
489     }
490   }
491
492   std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
493   for(std::list<std::pair<ObjectPtr, AttributePtr>>::const_iterator aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) {
494     ObjectPtr anObject = (*aPointsIt).first;
495     AttributePtr aPointAttribute = (*aPointsIt).second;
496     std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
497
498     // If we alredy have some result then:
499     // - if it is the same point all ok, just skip it
500     // - if it is point on the fillet result edge then it is not valid
501     if(!aPointsFeaturesMap.empty()) {
502       if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) {
503         continue;
504       }
505
506       // Check that selected point not on the one of the fillet result edge.
507       if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) {
508         return false;
509       }
510     }
511
512     // Obtain constraint coincidence for the fillet point.
513     const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
514     FeaturePtr aConstraintCoincidence;
515     for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
516       std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
517       FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
518       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
519         AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
520           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
521         AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
522           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
523         if(anAttrRefA.get() && !anAttrRefA->isObject()) {
524           AttributePtr anAttrA = anAttrRefA->attr();
525           if(aPointAttribute == anAttrA) {
526             aConstraintCoincidence = aConstrFeature;
527             break;
528           }
529         }
530         if(anAttrRefB.get() && !anAttrRefB->isObject()) {
531           AttributePtr anAttrB = anAttrRefB->attr();
532           if(aPointAttribute == anAttrB) {
533             aConstraintCoincidence = aConstrFeature;
534             break;
535           }
536         }
537       }
538     }
539
540     if(!aConstraintCoincidence.get()) {
541       theError = "Error: one of the selected point does not have coicidence.";
542       return false;
543     }
544
545     // Get coincides from constraint.
546     std::set<FeaturePtr> aCoinsides;
547     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
548                                          SketchPlugin_ConstraintCoincidence::ENTITY_A(),
549                                          aCoinsides);
550     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
551                                          SketchPlugin_ConstraintCoincidence::ENTITY_B(),
552                                          aCoinsides);
553
554     // Remove points from set of coincides.
555     std::set<FeaturePtr> aNewSetOfCoincides;
556     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
557       if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
558          (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
559            continue;
560       }
561       if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
562         AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
563         std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
564         double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
565         if(aDistSelectedArcCenter < tolerance) {
566           continue;
567         }
568       }
569       aNewSetOfCoincides.insert(*anIt);
570     }
571     aCoinsides = aNewSetOfCoincides;
572
573     // If we still have more than two coincides remove auxilary entities from set of coincides.
574     if(aCoinsides.size() > 2) {
575       aNewSetOfCoincides.clear();
576       for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
577         if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
578           aNewSetOfCoincides.insert(*anIt);
579         }
580       }
581       aCoinsides = aNewSetOfCoincides;
582     }
583
584     if(aCoinsides.size() != 2) {
585       theError = ("Error: One of the selected points does not have two suitable edges for fillet.");
586       return false;
587     }
588
589     // Check that lines not collinear
590     std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
591     FeaturePtr aFirstFeature = *anIt++;
592     FeaturePtr aSecondFeature = *anIt;
593     if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
594       std::string aStartAttr = SketchPlugin_Line::START_ID();
595       std::string anEndAttr = SketchPlugin_Line::END_ID();
596       std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
597       aFirstStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(aStartAttr))->pnt();
598       aFirstEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
599       aSecondStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(aStartAttr))->pnt();
600       aSecondEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(anEndAttr))->pnt();
601       double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) -
602         (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
603       double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) -
604         (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
605       if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
606         return false;
607       }
608     }
609   }
610
611   return true;
612 }
613
614 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, 
615                                                     const std::list<std::string>& theArguments,
616                                                     std::string& theError) const
617 {
618   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
619     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
620     return false;
621   }
622
623   // there is a check whether the feature contains a point and a linear edge or two point values
624   std::string aParamA = theArguments.front();
625   SessionPtr aMgr = ModelAPI_Session::get();
626   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
627
628   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
629   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
630   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
631
632   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
633   int aNbPoints = 0;
634   int aNbLines = 0;
635   for (int i = 0; i < 2; ++i) {
636     if (!aRefAttrs[i]->isObject())
637       ++aNbPoints;
638     else {
639       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
640       if (!aFeature) {
641         if (aNbPoints + aNbLines != 0)
642           return true;
643         else continue;
644       }
645
646       if (aFeature->getKind() == SketchPlugin_Point::ID())
647         ++aNbPoints;
648       else if (aFeature->getKind() == SketchPlugin_Line::ID())
649         ++aNbLines;
650     }
651   }
652
653   if (aNbPoints != 1 || aNbLines != 1) {
654     theError = "Middle point constraint allows points and lines only";
655     return false;
656   }
657   return true;
658 }
659
660 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
661                                                     const std::list<std::string>& /*theArguments*/,
662                                                     std::string& theError) const
663 {
664   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
665     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
666     return false;
667   }
668   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
669   AttributePtr anAttr = aRefAttr->attr();
670   if (!anAttr) {
671     theError = "The attribute " + theAttribute->id() + " should be a point";
672     return false;
673   }
674
675   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
676   const std::string& aFeatureType = anAttrFeature->getKind();
677   if (aFeatureType == SketchPlugin_Arc::ID()) {
678     // selected point should not be a center of arc
679     const std::string& aPntId = anAttr->id();
680     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
681       theError = "The attribute " + aPntId + " is not supported";
682       return false;
683     }
684   }
685   else if (aFeatureType == SketchPlugin_Line::ID()) {
686     // selected point should be bound point of line
687     const std::string& aPntId = anAttr->id();
688     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
689       theError = "The attribute " + aPntId + " is not supported";
690       return false;
691     }
692   }
693   else {
694     theError = "Unable to build tangent arc on " + anAttrFeature->getKind();
695     return false;
696   }
697
698   return true;
699 }
700
701 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
702                                                  const std::list<std::string>& theArguments,
703                                                  std::string& theError) const
704 {
705   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
706     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
707     return false;
708   }
709   AttributeSelectionPtr aLineAttr =
710                               std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
711   std::shared_ptr<GeomAPI_Edge> anEdge;
712   if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
713     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
714   } else if(aLineAttr->context() && aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) {
715     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
716   }
717
718   if (!anEdge || !anEdge->isLine()) {
719     theError = "The attribute " + theAttribute->id() + " should be a line";
720     return false;
721   }
722
723   std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
724
725   // find a sketch
726   std::shared_ptr<SketchPlugin_Sketch> aSketch;
727   std::set<AttributePtr> aRefs = aLineAttr->owner()->data()->refsToMe();
728   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
729   for (; anIt != aRefs.end(); ++anIt) {
730     CompositeFeaturePtr aComp =
731         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
732     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
733       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
734       break;
735     }
736   }
737   if (!aSketch) {
738     theError = "There is no sketch referring to the current feature";
739     return false;
740   }
741
742   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
743   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
744   return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
745 }