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