Salome HOME
Correct processing of the fixed arc in PlaneGCS (issue #1280)
[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   int aType[2] = {0, 0}; // types of attributes: 0 - incorrect, 1 - line, 2 - circle, 3 - arc
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     if (aFeature->getKind() == SketchPlugin_Line::ID()) {
288       aType[i] = 1;
289       continue;
290     }
291     if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
292       aType[i] = 2;
293       continue;
294     }
295     if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
296       aType[i] = 3;
297       continue;
298     }
299     theError = "The " + aFeature->getKind() + " feature kind of attribute is wrong. It should be " +
300                SketchPlugin_Line::ID() + " or " + SketchPlugin_Circle::ID() + " or " + 
301                SketchPlugin_Arc::ID();
302     // wrong type of attribute
303     return false;
304   }
305
306   if ((aType[0] == 1 && aType[1] == 2) ||
307       (aType[0] == 2 && aType[1] == 1)) {
308     theError = "Feature with kinds " + SketchPlugin_Line::ID() + " and " +
309                SketchPlugin_Circle::ID() + "can not be equal.";
310     return false;
311   }
312   return true;
313 }
314
315 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, 
316                                                const std::list<std::string>& theArguments,
317                                                std::string& theError) const
318 {
319   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
320     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
321     return false;
322   }
323
324   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
325   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
326
327   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
328       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
329   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
330
331   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
332     ObjectPtr aSelObject = aSelAttr->object(anInd);
333     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
334     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
335     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
336       if (aSelObject == *aMirIter) {
337         theError = "The object " + aName + " is a result of mirror";
338         return false;
339       }
340   }
341   return true;
342 }
343
344 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, 
345                                                     const std::list<std::string>& theArguments,
346                                                     std::string& theError) const
347 {
348   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
349     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
350     return false;
351   }
352
353   // there is a check whether the feature contains a point and a linear edge or two point values
354   std::string aParamA = theArguments.front();
355   SessionPtr aMgr = ModelAPI_Session::get();
356   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
357
358   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
359   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
360   if (!aRefAttrA) {
361     theError = "The " + aParamA + " attribute " + " should be " + ModelAPI_AttributeRefAttr::typeId();
362     return false;
363   }
364
365   AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
366
367   // first attribute is a point, it may coincide with any object
368   if (!aRefAttrA->isObject())
369     return true;
370   else {
371     ObjectPtr anObject = aRefAttrA->object();
372     if (!anObject.get()) {
373       theError = aParamA + " attribute has an empty object";
374       return false;
375     }
376     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
377     if (!aFeature.get()) {
378       theError = aParamA + " attribute has an empty feature";
379       return false;
380     }
381
382     if (aFeature->getKind() == SketchPlugin_Point::ID())
383       return true;
384   }
385
386   // second attribute is a point, it may coincide with any object
387   if (!aRefAttrB->isObject())
388     return true;
389   else {
390     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
391     if (!aFeature) {
392       theError = theAttribute->id() + " attribute has an empty object";
393       return false;
394     }
395     if (aFeature->getKind() == SketchPlugin_Point::ID())
396       return true;
397   }
398   theError = "There is no an attribute filled by a point";
399   return false;
400 }
401
402
403 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, 
404                                          const std::list<std::string>& theArguments,
405                                          std::string& theError) const
406 {
407   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
408     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
409     return false;
410   }
411
412   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
413   AttributeRefListPtr aSelAttr = 
414     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
415
416   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
417       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
418   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
419       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
420   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
421   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
422
423   std::list<ObjectPtr>::iterator anObjIter;
424   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
425     ObjectPtr aSelObject = aSelAttr->object(anInd);
426     anObjIter = anInitialObjects.begin();
427     for (; anObjIter != anInitialObjects.end(); anObjIter++)
428       if (aSelObject == *anObjIter)
429         break;
430     if (anObjIter != anInitialObjects.end())
431       continue;
432     anObjIter = aCopiedObjects.begin();
433     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
434       if (aSelObject == *anObjIter) {
435         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
436         theError = "The object " + aName + " is a result of copy";
437         return false;
438       }
439   }
440   return true;
441 }
442
443 bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
444                                                 const std::list<std::string>& theArguments,
445                                                 std::string& theError) const
446 {
447   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
448
449   if (!aAttributeString->value().empty()) {
450     theError = aAttributeString->value();
451     return false;
452   }
453
454   return true;
455 }
456
457 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature, std::string theAttribute)
458 {
459   return true;
460 }
461
462 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
463                                                  const std::list<std::string>& theArguments,
464                                                  std::string& theError) const
465 {
466   if(!theAttribute.get() || !theAttribute->isInitialized()) {
467     theError = "Error: List of points is not initialized.";
468     return false;
469   }
470
471   FeaturePtr aFilletFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
472   AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
473   if(aPointsRefList->size() == 0) {
474     theError = "Error: List of points is empty.";
475     return false;
476   }
477
478   AttributeRefAttrListPtr aBasePointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(
479     aFilletFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
480   AttributeRefListPtr aResultEdgesRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
481     aFilletFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
482
483   std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
484   for(std::list<std::pair<ObjectPtr, AttributePtr>>::const_iterator anIt = aPointsList.cbegin(); anIt != aPointsList.cend(); anIt++) {
485     ObjectPtr anObject = (*anIt).first;
486     AttributePtr aPointAttribute = (*anIt).second;
487
488     // If we alredy have some result then:
489     // - if it is the same point all ok, just skip it
490     // - if it is point on the fillet arc then it is not valid
491     if(aBasePointsRefList->size() > 0) {
492       if(aBasePointsRefList->isInList(aPointAttribute)) {
493         continue;
494       }
495
496       // Check that selected point not on the one of the result fillet arc.
497       for(int anIndex = 0; anIndex < aBasePointsRefList->size(); anIndex++) {
498         if(aResultEdgesRefList->size() > 0) {
499           FeaturePtr aResultArc;
500           aResultArc = ModelAPI_Feature::feature(aResultEdgesRefList->object(anIndex * 3 + 2));
501           AttributePtr anArcStart = aResultArc->attribute(SketchPlugin_Arc::START_ID());
502           AttributePtr anArcEnd = aResultArc->attribute(SketchPlugin_Arc::END_ID());
503           std::shared_ptr<GeomAPI_Pnt2d> anArcStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcStart)->pnt();
504           std::shared_ptr<GeomAPI_Pnt2d> anArcEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcEnd)->pnt();
505           std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
506           double aDistSelectedArcStart = aSelectedPnt->distance(anArcStartPnt);
507           double aDistSelectedArcEnd = aSelectedPnt->distance(anArcEndPnt);
508           if(aDistSelectedArcStart < tolerance || aDistSelectedArcEnd < tolerance) {
509             return false;
510           }
511         }
512       }
513     }
514
515     // Obtain constraint coincidence for the fillet point.
516     const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
517     FeaturePtr aConstraintCoincidence;
518     for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
519       std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
520       FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
521       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
522         AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
523           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
524         AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
525           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
526         if(anAttrRefA.get() && !anAttrRefA->isObject()) {
527           AttributePtr anAttrA = anAttrRefA->attr();
528           if(aPointAttribute == anAttrA) {
529             aConstraintCoincidence = aConstrFeature;
530             break;
531           }
532         }
533         if(anAttrRefB.get() && !anAttrRefB->isObject()) {
534           AttributePtr anAttrB = anAttrRefB->attr();
535           if(aPointAttribute == anAttrB) {
536             aConstraintCoincidence = aConstrFeature;
537             break;
538           }
539         }
540       }
541     }
542
543     if(!aConstraintCoincidence.get()) {
544       theError = "Error: one of the selected point does not have coicidence.";
545       return false;
546     }
547
548     // Get coincides from constraint.
549     std::set<FeaturePtr> aCoinsides;
550     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
551                                          SketchPlugin_ConstraintCoincidence::ENTITY_A(),
552                                          aCoinsides);
553     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
554                                          SketchPlugin_ConstraintCoincidence::ENTITY_B(),
555                                          aCoinsides);
556
557     // Remove points from set of coincides.
558     std::set<FeaturePtr> aNewSetOfCoincides;
559     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
560       if((*anIt)->getKind() == SketchPlugin_Line::ID() ||
561          (*anIt)->getKind() == SketchPlugin_Arc::ID()) {
562         aNewSetOfCoincides.insert(*anIt);
563       }
564     }
565     aCoinsides = aNewSetOfCoincides;
566
567     // If we still have more than two coincides remove auxilary entities from set of coincides.
568     if(aCoinsides.size() > 2) {
569       aNewSetOfCoincides.clear();
570       for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
571         if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
572           aNewSetOfCoincides.insert(*anIt);
573         }
574       }
575       aCoinsides = aNewSetOfCoincides;
576     }
577
578     if(aCoinsides.size() != 2) {
579       theError = ("Error: One of the selected points does not have two suitable edges for fillet.");
580       return false;
581     }
582
583     // Check that lines not collinear
584     std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
585     FeaturePtr aFirstFeature = *anIt++;
586     FeaturePtr aSecondFeature = *anIt;
587     if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
588       std::string aStartAttr = SketchPlugin_Line::START_ID();
589       std::string anEndAttr = SketchPlugin_Line::END_ID();
590       std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
591       aFirstStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(aStartAttr))->pnt();
592       aFirstEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
593       aSecondStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(aStartAttr))->pnt();
594       aSecondEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(anEndAttr))->pnt();
595       double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) -
596         (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
597       double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) -
598         (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
599       if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
600         return false;
601       }
602     }
603   }
604
605   return true;
606 }
607
608 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, 
609                                                     const std::list<std::string>& theArguments,
610                                                     std::string& theError) const
611 {
612   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
613     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
614     return false;
615   }
616
617   // there is a check whether the feature contains a point and a linear edge or two point values
618   std::string aParamA = theArguments.front();
619   SessionPtr aMgr = ModelAPI_Session::get();
620   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
621
622   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
623   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
624   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
625
626   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
627   int aNbPoints = 0;
628   int aNbLines = 0;
629   for (int i = 0; i < 2; ++i) {
630     if (!aRefAttrs[i]->isObject())
631       ++aNbPoints;
632     else {
633       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
634       if (!aFeature) {
635         if (aNbPoints + aNbLines != 0)
636           return true;
637         else continue;
638       }
639
640       if (aFeature->getKind() == SketchPlugin_Point::ID())
641         ++aNbPoints;
642       else if (aFeature->getKind() == SketchPlugin_Line::ID())
643         ++aNbLines;
644     }
645   }
646
647   if (aNbPoints != 1 || aNbLines != 1) {
648     theError = "Middle point constraint allows points and lines only";
649     return false;
650   }
651   return true;
652 }
653
654 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
655                                                     const std::list<std::string>& /*theArguments*/,
656                                                     std::string& theError) const
657 {
658   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
659     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
660     return false;
661   }
662   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
663   AttributePtr anAttr = aRefAttr->attr();
664   if (!anAttr) {
665     theError = "The attribute " + theAttribute->id() + " should be a point";
666     return false;
667   }
668
669   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
670   const std::string& aFeatureType = anAttrFeature->getKind();
671   if (aFeatureType == SketchPlugin_Arc::ID()) {
672     // selected point should not be a center of arc
673     const std::string& aPntId = anAttr->id();
674     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
675       theError = "The attribute " + aPntId + " is not supported";
676       return false;
677     }
678   }
679   else if (aFeatureType == SketchPlugin_Line::ID()) {
680     // selected point should be bound point of line
681     const std::string& aPntId = anAttr->id();
682     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
683       theError = "The attribute " + aPntId + " is not supported";
684       return false;
685     }
686   }
687   else {
688     theError = "Unable to build tangent arc on " + anAttrFeature->getKind();
689     return false;
690   }
691
692   return true;
693 }