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