Salome HOME
51d0b8fc1e587bbd9e0cd01ae914252fee93d3da
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_Validators.cpp
4 // Created:     01 Aug 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "SketchPlugin_Validators.h"
8
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_Circle.h"
11 #include "SketchPlugin_ConstraintCoincidence.h"
12 #include "SketchPlugin_ConstraintDistance.h"
13 #include "SketchPlugin_ConstraintFillet.h"
14 #include "SketchPlugin_ConstraintRigid.h"
15 #include "SketchPlugin_ConstraintTangent.h"
16 #include "SketchPlugin_Line.h"
17 #include "SketchPlugin_Point.h"
18 #include "SketchPlugin_Sketch.h"
19 #include "SketchPlugin_Tools.h"
20
21 #include "SketcherPrs_Tools.h"
22
23 #include <Events_InfoMessage.h>
24
25 #include <ModelAPI_Data.h>
26 #include <ModelAPI_Validator.h>
27 #include <ModelAPI_AttributeDouble.h>
28 #include <ModelAPI_AttributeRefAttr.h>
29
30 #include <ModelAPI_AttributeRefAttrList.h>
31 #include <ModelAPI_AttributeRefList.h>
32 #include <ModelAPI_AttributeSelectionList.h>
33 #include <ModelAPI_AttributeString.h>
34 #include <ModelAPI_Session.h>
35 #include <ModelAPI_Tools.h>
36 #include <ModelAPI_ResultConstruction.h>
37
38 #include <ModelGeomAlgo_Point2D.h>
39
40 #include <GeomAPI_Circ.h>
41 #include <GeomAPI_Lin.h>
42 #include <GeomAPI_Edge.h>
43 #include <GeomAPI_Vertex.h>
44 #include <GeomDataAPI_Point2D.h>
45
46 #include <algorithm>
47 #include <cmath>
48
49 const double tolerance = 1.e-7;
50
51 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
52                                                  const std::list<std::string>& theArguments,
53                                                  Events_InfoMessage& theError) const
54 {
55   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
56     theError = "The attribute with the %1 type is not processed";
57     theError.arg(theAttribute->attributeType());
58     return false;
59   }
60
61   // there is a check whether the feature contains a point and a linear edge or two point values
62   std::string aParamA = theArguments.front();
63   SessionPtr aMgr = ModelAPI_Session::get();
64   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
65
66   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
67   bool isObject = aRefAttr->isObject();
68   if (!isObject) {
69     // an attribute is a point. A point value is valid always for the distance
70     return true;
71   } else {
72     // 1. check whether the references object is a linear
73     ObjectPtr anObject = aRefAttr->object();
74
75     const ModelAPI_AttributeValidator* aShapeValidator =
76       dynamic_cast<const ModelAPI_AttributeValidator*>(
77       aFactory->validator("GeomValidators_ShapeType"));
78     std::list<std::string> anArguments;
79     anArguments.push_back("circle");
80     Events_InfoMessage aCircleError;
81     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
82     // the circle line is not a valid case
83     if (aShapeValid) {
84       theError = "Circle can not be used in distance constraint";
85       return false;
86     }
87
88     anArguments.clear();
89     anArguments.push_back("line");
90     Events_InfoMessage aLineError;
91     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
92     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
93     if (aShapeValid) {
94       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
95       // If it is a line then we have to check that first attribute id not a line
96       std::shared_ptr<SketchPlugin_Feature> aSFeature =
97         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
98       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
99       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
100       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
101         aFeature->data(), aParamA, aPlane);
102       if (!aPoint.get()) {
103         theError = "One of parameters of distance constraint should be a point";
104         return false;
105       }
106     }
107   }
108   return true;
109 }
110
111 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
112                                                 const std::list<std::string>& theArguments,
113                                                 Events_InfoMessage& theError) const
114 {
115   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
116     theError = "The attribute with the %1 type is not processed";
117     theError.arg(theAttribute->attributeType());
118     return false;
119   }
120
121   // there is a check whether the feature contains a point and a linear edge or two point values
122   std::string aParamA = theArguments.front();
123   SessionPtr aMgr = ModelAPI_Session::get();
124   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
125
126   FeaturePtr anAttributeFeature =
127     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
128   AttributeRefAttrPtr aRefAttr =
129     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
130
131   bool isObject = aRefAttr->isObject();
132   ObjectPtr anObject = aRefAttr->object();
133   if (isObject && anObject.get()) {
134     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
135
136     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
137     ObjectPtr aOtherObject = aOtherAttr->object();
138     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
139     if (!aOtherFea)
140       return true;
141
142     if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
143       if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
144           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
145         theError = "It refers to a %1, but %2 is neither an %3 nor %4";
146         theError.arg(SketchPlugin_Line::ID()).arg(aParamA)
147             .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
148         return false;
149       }
150     }
151     else if (aRefFea->getKind() == SketchPlugin_Arc::ID() ||
152              aRefFea->getKind() == SketchPlugin_Circle::ID()) {
153       if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
154           aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
155           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
156         theError = "It refers to an %1, but %2 is not a %3 or an %4 or a %5";
157         theError.arg(SketchPlugin_Arc::ID()).arg(aParamA)
158             .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID())
159             .arg(SketchPlugin_Circle::ID());
160         return false;
161       }
162     }
163     else {
164       theError = "It refers to %1, but should refer to %2 or %3 or %4";
165       theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID())
166           .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
167       return false;
168     }
169     return true;
170   }
171   else {
172     theError = "It uses an empty object";
173     return false;
174   }
175
176   return true;
177 }
178
179 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
180                                              const std::list<std::string>& theArguments,
181                                              Events_InfoMessage& theError) const
182 {
183   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
184     theError = "The attribute with the %1 type is not processed";
185     theError.arg(theAttribute->attributeType());
186     return false;
187   }
188
189   std::shared_ptr<SketchPlugin_Feature> aFeature =
190       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
191   if (!aFeature)
192     return true;
193
194   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
195
196   SketchPlugin_Sketch* aSketch = aFeature->sketch();
197   int aNbFeatures = aSketch->numberOfSubs();
198   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
199     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
200     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
201       continue;
202     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
203         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
204     if (aRefAttr->isObject()) {
205       if (aRefAttr->object() == aRAttr->object()) {
206         ObjectPtr anObject = aRefAttr->object();
207         std::string aName = anObject.get() ? anObject->data()->name() : "";
208         theError = "The object %1 has been already fixed.";
209         theError.arg(aName);
210         return false;
211       }
212     }
213     else if (aRefAttr->attr() == aRAttr->attr()) {
214       AttributePtr anAttribute = aRefAttr->attr();
215       std::string aName = anAttribute.get() ? anAttribute->id() : "";
216       theError = "The attribute %1 has been already fixed.";
217       theError.arg(aName);
218       return false;
219     }
220   }
221   return true;
222 }
223
224 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
225                                               const std::list<std::string>& theArguments,
226                                               Events_InfoMessage& theError) const
227 {
228   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
229     theError = "The attribute with the %1 type is not processed";
230     theError.arg(theAttribute->attributeType());
231     return false;
232   }
233
234   std::string aParamA = theArguments.front();
235   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
236   AttributeRefAttrPtr aRefAttr[2];
237   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
238   aRefAttr[1] = aFeature->data()->refattr(aParamA);
239
240   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
241     theError = "Attributes can not be used in equal constraint";
242     return false;
243   }
244
245   std::string aType[2];
246   std::list<std::string> anArguments;
247   for (int i = 0; i < 2; i++) {
248     ObjectPtr anObject = aRefAttr[i]->object();
249     if (!anObject.get()) {
250       theError = "An empty object is used.";
251       return false;
252     }
253
254     aFeature = ModelAPI_Feature::feature(anObject);
255     if (!aFeature.get()) {
256       theError = "An empty feature is used.";
257       return false;
258     }
259
260     aType[i] = aFeature->getKind();
261     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
262         aFeature->getKind() != SketchPlugin_Circle::ID() &&
263         aFeature->getKind() != SketchPlugin_Arc::ID()) {
264       theError = "The %1 feature kind of attribute is wrong. It should be %2 or %3 or %4";
265       theError.arg(aFeature->getKind()).arg(SketchPlugin_Line::ID())
266           .arg(SketchPlugin_Circle::ID()).arg(SketchPlugin_Arc::ID());
267       // wrong type of attribute
268       return false;
269     }
270   }
271
272   if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) &&
273       aType[0] != aType[1]) {
274     theError = "Feature with kinds %1 and %2 can not be equal.";
275     theError.arg(aType[0]).arg(aType[1]);
276     return false;
277   }
278   return true;
279 }
280
281 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
282                                                const std::list<std::string>& theArguments,
283                                                Events_InfoMessage& theError) const
284 {
285   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
286     theError = "The attribute with the %1 type is not processed";
287     theError.arg(theAttribute->attributeType());
288     return false;
289   }
290
291   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
292   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
293
294   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
295       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
296   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
297
298   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
299     ObjectPtr aSelObject = aSelAttr->object(anInd);
300     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
301     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
302     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
303       if (aSelObject == *aMirIter) {
304         theError = "The object %1 is a result of mirror";
305         theError.arg(aName);
306         return false;
307       }
308   }
309   return true;
310 }
311
312 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
313                                                     const std::list<std::string>& theArguments,
314                                                     Events_InfoMessage& theError) const
315 {
316   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
317     theError = "The attribute with the %1 type is not processed";
318     theError.arg(theAttribute->attributeType());
319     return false;
320   }
321
322   // there is a check whether the feature contains a point and a linear edge or two point values
323   std::string aParamA = theArguments.front();
324   SessionPtr aMgr = ModelAPI_Session::get();
325   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
326
327   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
328   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
329   if (!aRefAttrA) {
330     theError = "The %1 attribute should be %2";
331     theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
332     return false;
333   }
334
335   AttributeRefAttrPtr aRefAttrB =
336     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
337
338   // first attribute is a point, it may coincide with any object
339   if (!aRefAttrA->isObject())
340     return true;
341   else {
342     ObjectPtr anObject = aRefAttrA->object();
343     if (!anObject.get()) {
344       theError = "%1 attribute has an empty object";
345       theError.arg(aParamA);
346       return false;
347     }
348     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
349     if (!aFeature.get()) {
350       theError = "%1 attribute has an empty feature";
351       theError.arg(aParamA);
352       return false;
353     }
354
355     if (aFeature->getKind() == SketchPlugin_Point::ID())
356       return true;
357   }
358
359   // second attribute is a point, it may coincide with any object
360   if (!aRefAttrB->isObject())
361     return true;
362   else {
363     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
364     if (!aFeature) {
365       theError = "%1 attribute has an empty object";
366       theError.arg(theAttribute->id());
367       return false;
368     }
369     if (aFeature->getKind() == SketchPlugin_Point::ID())
370       return true;
371   }
372   theError = "There is no an attribute filled by a point";
373   return false;
374 }
375
376
377 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
378                                          const std::list<std::string>& theArguments,
379                                          Events_InfoMessage& theError) const
380 {
381   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
382     theError = "The attribute with the %1 type is not processed";
383     theError.arg(theAttribute->attributeType());
384     return false;
385   }
386
387   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
388   AttributeRefListPtr aSelAttr =
389     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
390
391   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
392       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
393   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
394       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
395   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
396   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
397
398   std::list<ObjectPtr>::iterator anObjIter;
399   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
400     ObjectPtr aSelObject = aSelAttr->object(anInd);
401     anObjIter = anInitialObjects.begin();
402     for (; anObjIter != anInitialObjects.end(); anObjIter++)
403       if (aSelObject == *anObjIter)
404         break;
405     if (anObjIter != anInitialObjects.end())
406       continue;
407     anObjIter = aCopiedObjects.begin();
408     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
409       if (aSelObject == *anObjIter) {
410         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
411         theError = "The object %1 is a result of copy";
412         theError.arg(aName);
413         return false;
414       }
415   }
416   return true;
417 }
418
419 bool SketchPlugin_SolverErrorValidator::isValid(
420   const std::shared_ptr<ModelAPI_Feature>& theFeature,
421   const std::list<std::string>& theArguments,
422   Events_InfoMessage& theError) const
423 {
424   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
425
426   if (!aAttributeString->value().empty()) {
427     theError = aAttributeString->value();
428     return false;
429   }
430
431   return true;
432 }
433
434 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
435                                                         std::string theAttribute)
436 {
437   return true;
438 }
439
440 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
441                                   const FeaturePtr theFeature)
442 {
443   for(std::set<AttributePtr>::const_iterator
444       anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
445     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
446     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
447     if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
448       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
449         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
450       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
451         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
452       if(anAttrRefA.get()) {
453         ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
454         if(aResA.get()) {
455           DocumentPtr aDoc = aResA->document();
456           if(aDoc.get()) {
457             FeaturePtr aFeatureA = aDoc->feature(aResA);
458             if(aFeatureA.get() && aFeatureA == theFeature) {
459               return true;
460             }
461           }
462         }
463       }
464       if(anAttrRefB.get()) {
465         ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
466         if(aResB.get()) {
467           DocumentPtr aDoc = aResB->document();
468           if(aDoc.get()) {
469             FeaturePtr aFeatureB = aDoc->feature(aResB);
470             if(aFeatureB.get() && aFeatureB == theFeature) {
471               return true;
472             }
473           }
474         }
475       }
476     }
477   }
478   return false;
479 }
480
481 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
482                                                  const std::list<std::string>& theArguments,
483                                                  Events_InfoMessage& theError) const
484 {
485   std::shared_ptr<SketchPlugin_ConstraintFillet> aFilletFeature =
486     std::dynamic_pointer_cast<SketchPlugin_ConstraintFillet>(theAttribute->owner());
487   AttributeRefAttrListPtr aPointsRefList =
488     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
489   if(aPointsRefList->size() == 0) {
490     theError = "Error: List of points is empty.";
491     return false;
492   }
493
494   std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures> aPointsFeaturesMap =
495     aFilletFeature->pointsFeaturesMap();
496   std::set<AttributePtr> aSetOfPointsOnResultEdges;
497   for(std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures>::iterator
498       aPointsIter = aPointsFeaturesMap.begin();
499       aPointsIter != aPointsFeaturesMap.end();
500       ++aPointsIter) {
501     const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second;
502     const std::list<FeaturePtr>& aResultEdges = aFeatures.resultEdges;
503     for(std::list<FeaturePtr>::const_iterator aResultIter = aResultEdges.cbegin();
504         aResultIter != aResultEdges.cend();
505         ++aResultIter) {
506       FeaturePtr aResultFeature = *aResultIter;
507       if(aResultFeature->getKind() == SketchPlugin_Line::ID()) {
508         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID()));
509         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID()));
510       } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) {
511         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID()));
512         aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID()));
513       }
514     }
515   }
516
517   std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
518   for(std::list<std::pair<ObjectPtr, AttributePtr>>::const_iterator
519       aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) {
520     ObjectPtr anObject = (*aPointsIt).first;
521     AttributePtr aPointAttribute = (*aPointsIt).second;
522     if (!aPointAttribute.get())
523         return false;
524     std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
525       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
526
527     // If we alredy have some result then:
528     // - if it is the same point all ok, just skip it
529     // - if it is point on the fillet result edge then it is not valid
530     if(!aPointsFeaturesMap.empty()) {
531       if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) {
532         continue;
533       }
534
535       // Check that selected point not on the one of the fillet result edge.
536       if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) {
537         return false;
538       }
539     }
540
541     // Obtain constraint coincidence for the fillet point.
542     const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
543     FeaturePtr aConstraintCoincidence;
544     for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
545         anIt != aRefsList.cend(); ++anIt) {
546       std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
547       FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
548       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
549         AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
550           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
551         AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
552           aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
553         if(anAttrRefA.get() && !anAttrRefA->isObject()) {
554           AttributePtr anAttrA = anAttrRefA->attr();
555           if(aPointAttribute == anAttrA) {
556             aConstraintCoincidence = aConstrFeature;
557             break;
558           }
559         }
560         if(anAttrRefB.get() && !anAttrRefB->isObject()) {
561           AttributePtr anAttrB = anAttrRefB->attr();
562           if(aPointAttribute == anAttrB) {
563             aConstraintCoincidence = aConstrFeature;
564             break;
565           }
566         }
567       }
568     }
569
570     if(!aConstraintCoincidence.get()) {
571       theError = "Error: one of the selected point does not have coicidence.";
572       return false;
573     }
574
575     // Get coincides from constraint.
576     std::set<FeaturePtr> aCoinsides;
577     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
578                                          SketchPlugin_ConstraintCoincidence::ENTITY_A(),
579                                          aCoinsides);
580     SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
581                                          SketchPlugin_ConstraintCoincidence::ENTITY_B(),
582                                          aCoinsides);
583
584     // Remove points from set of coincides.
585     std::set<FeaturePtr> aNewSetOfCoincides;
586     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
587         anIt != aCoinsides.end(); ++anIt) {
588       if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
589          (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
590            continue;
591       }
592       if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
593         AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
594         std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
595           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
596         double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
597         if(aDistSelectedArcCenter < tolerance) {
598           continue;
599         }
600       }
601       aNewSetOfCoincides.insert(*anIt);
602     }
603     aCoinsides = aNewSetOfCoincides;
604
605     // If we still have more than two coincides remove auxilary entities from set of coincides.
606     if(aCoinsides.size() > 2) {
607       aNewSetOfCoincides.clear();
608       for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
609           anIt != aCoinsides.end(); ++anIt) {
610         if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
611           aNewSetOfCoincides.insert(*anIt);
612         }
613       }
614       aCoinsides = aNewSetOfCoincides;
615     }
616
617     if(aCoinsides.size() != 2) {
618       theError = "Error: One of the selected points does not have two suitable edges for fillet.";
619       return false;
620     }
621
622     // Check that selected edges don't have tangent constraint.
623     std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
624     FeaturePtr aFirstFeature = *anIt++;
625     FeaturePtr aSecondFeature = *anIt;
626     const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
627     if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
628       theError = "Error: Edges in selected point has tangent constraint.";
629       return false;
630     }
631
632     std::list<ResultPtr> aFirstResults = aFirstFeature->results();
633     for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
634         aResIt != aFirstResults.end(); ++aResIt) {
635       ResultPtr aRes = *aResIt;
636       const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
637       if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
638         theError = "Error: Edges in selected point has tangent constraint.";
639         return false;
640       }
641     }
642
643     // Check that lines not collinear
644     if(aFirstFeature->getKind() == SketchPlugin_Line::ID() &&
645         aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
646       std::string aStartAttr = SketchPlugin_Line::START_ID();
647       std::string anEndAttr = SketchPlugin_Line::END_ID();
648       std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
649       aFirstStartPnt =
650         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
651         aFirstFeature->attribute(aStartAttr))->pnt();
652       aFirstEndPnt =
653         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
654       aSecondStartPnt =
655         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
656         aSecondFeature->attribute(aStartAttr))->pnt();
657       aSecondEndPnt =
658         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
659         aSecondFeature->attribute(anEndAttr))->pnt();
660       double aCheck1 =
661         fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
662         (aSecondStartPnt->y() - aFirstStartPnt->y()) -
663         (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
664       double aCheck2 =
665         fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
666         (aSecondEndPnt->y() - aFirstStartPnt->y()) -
667         (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
668       if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
669         return false;
670       }
671     }
672   }
673
674   return true;
675 }
676
677 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
678                                                     const std::list<std::string>& theArguments,
679                                                     Events_InfoMessage& theError) const
680 {
681   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
682     theError = "The attribute with the %1 type is not processed";
683     theError.arg(theAttribute->attributeType());
684     return false;
685   }
686
687   // there is a check whether the feature contains a point and a linear edge or two point values
688   std::string aParamA = theArguments.front();
689   SessionPtr aMgr = ModelAPI_Session::get();
690   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
691
692   FeaturePtr anAttributeFeature =
693     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
694   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
695   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
696
697   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
698   int aNbPoints = 0;
699   int aNbLines = 0;
700   for (int i = 0; i < 2; ++i) {
701     if (!aRefAttrs[i]->isObject())
702       ++aNbPoints;
703     else {
704       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
705       if (!aFeature) {
706         if (aNbPoints + aNbLines != 0)
707           return true;
708         else continue;
709       }
710
711       if (aFeature->getKind() == SketchPlugin_Point::ID())
712         ++aNbPoints;
713       else if (aFeature->getKind() == SketchPlugin_Line::ID())
714         ++aNbLines;
715     }
716   }
717
718   if (aNbPoints != 1 || aNbLines != 1) {
719     theError = "Middle point constraint allows points and lines only";
720     return false;
721   }
722   return true;
723 }
724
725 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
726                                                     const std::list<std::string>& /*theArguments*/,
727                                                     Events_InfoMessage& theError) const
728 {
729   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
730     theError = "The attribute with the %1 type is not processed";
731     theError.arg(theAttribute->attributeType());
732     return false;
733   }
734   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
735   AttributePtr anAttr = aRefAttr->attr();
736   if (!anAttr) {
737     theError = "The attribute %1 should be a point";
738     theError.arg(theAttribute->id());
739     return false;
740   }
741
742   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
743   const std::string& aFeatureType = anAttrFeature->getKind();
744   if (aFeatureType == SketchPlugin_Arc::ID()) {
745     // selected point should not be a center of arc
746     const std::string& aPntId = anAttr->id();
747     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
748       theError = "The attribute %1 is not supported";
749       theError.arg(aPntId);
750       return false;
751     }
752   }
753   else if (aFeatureType == SketchPlugin_Line::ID()) {
754     // selected point should be bound point of line
755     const std::string& aPntId = anAttr->id();
756     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
757       theError = "The attribute %1 is not supported";
758       theError.arg(aPntId);
759       return false;
760     }
761   }
762   else {
763     theError = "Unable to build tangent arc on %1";
764     theError.arg(anAttrFeature->getKind());
765     return false;
766   }
767
768   // Check the tangent point is equal to arc end
769   FeaturePtr anArc = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->owner());
770   std::shared_ptr<GeomDataAPI_Point2D> anEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
771       anArc->attribute(SketchPlugin_Arc::END_ID()));
772   if (anEndPoint->isInitialized()) {
773     std::shared_ptr<GeomDataAPI_Point2D> aTangPt =
774         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
775     if (aTangPt->pnt()->distance(anEndPoint->pnt()) < tolerance) {
776       theError = "Unable to build arc on same points";
777       return false;
778     }
779   }
780
781   return true;
782 }
783
784 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
785                                                  const std::list<std::string>& theArguments,
786                                                  Events_InfoMessage& theError) const
787 {
788   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
789     theError = "The attribute with the %1 type is not processed";
790     theError.arg(theAttribute->attributeType());
791     return false;
792   }
793   AttributeSelectionPtr aLineAttr =
794                        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
795   std::shared_ptr<GeomAPI_Edge> anEdge;
796   if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
797     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
798   } else if(aLineAttr->context() &&
799             aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) {
800     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
801   }
802
803   if (!anEdge || !anEdge->isLine()) {
804     theError = "The attribute %1 should be a line";
805     theError.arg(theAttribute->id());
806     return false;
807   }
808
809   std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
810
811   // find a sketch
812   std::shared_ptr<SketchPlugin_Sketch> aSketch;
813   std::set<AttributePtr> aRefs = aLineAttr->owner()->data()->refsToMe();
814   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
815   for (; anIt != aRefs.end(); ++anIt) {
816     CompositeFeaturePtr aComp =
817         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
818     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
819       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
820       break;
821     }
822   }
823   if (!aSketch) {
824     theError = "There is no sketch referring to the current feature";
825     return false;
826   }
827
828   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
829   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
830   return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
831 }
832
833 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
834                                           const std::list<std::string>& theArguments,
835                                           Events_InfoMessage& theError) const
836 {
837   bool aValid = false;
838
839   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
840     theError = "The attribute with the %1 type is not processed";
841     theError.arg(theAttribute->attributeType());
842     return aValid;
843   }
844   AttributeReferencePtr aFeatureAttr =
845             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
846
847   ObjectPtr anAttrObject = aFeatureAttr->value();
848   FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
849   if (!anAttrFeature)
850     return aValid;
851
852   std::string aKind = anAttrFeature->getKind();
853   if (aKind == SketchPlugin_Line::ID() ||
854       aKind == SketchPlugin_Arc::ID() ||
855       aKind == SketchPlugin_Circle::ID()) {
856
857     std::set<GeomShapePtr> anEdgeShapes;
858     ModelAPI_Tools::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
859     if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
860       return aValid;
861
862     // coincidences to the feature
863     std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
864     ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
865                         SketchPlugin_ConstraintCoincidence::ID(),
866                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
867
868     GeomShapePtr anAttrShape = *anEdgeShapes.begin();
869     std::shared_ptr<SketchPlugin_Feature> aSFeature =
870                                  std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
871     SketchPlugin_Sketch* aSketch = aSFeature->sketch();
872
873     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
874     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
875         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
876     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
877         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
878     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
879         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
880     std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
881
882     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
883     std::map<std::shared_ptr<GeomDataAPI_Point2D>, std::shared_ptr<GeomAPI_Pnt> >
884       aPointToAttributes;
885     ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
886                                                 aX->dir(), aDirY, aPoints, aPointToAttributes);
887
888     int aCoincidentToFeature = (int)aPoints.size();
889     if (aKind == SketchPlugin_Circle::ID())
890       aValid = aCoincidentToFeature >= 2;
891     else
892       aValid = aCoincidentToFeature >= 1;
893   }
894
895   return aValid;
896 }
897
898 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
899                                                const std::list<std::string>& theArguments,
900                                                Events_InfoMessage& theError) const
901 {
902   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
903     theError = "The attribute with the %1 type is not processed";
904     theError.arg(theAttribute->attributeType());
905     return false;
906   }
907
908   AttributeSelectionPtr aFeatureAttr =
909       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
910   std::shared_ptr<GeomAPI_Edge> anEdge;
911   if (aFeatureAttr.get()) {
912     GeomShapePtr aVal = aFeatureAttr->value();
913     ResultPtr aRes = aFeatureAttr->context();
914     if(aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) {
915       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
916     } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() &&
917               aFeatureAttr->context()->shape()->isEdge()) {
918       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
919     }
920   }
921   if (!anEdge) {
922     theError = "The attribute %1 should be an edge";
923     theError.arg(theAttribute->id());
924     return false;
925   }
926
927   // find a sketch
928   std::shared_ptr<SketchPlugin_Sketch> aSketch;
929   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
930   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
931   for (; anIt != aRefs.end(); ++anIt) {
932     CompositeFeaturePtr aComp =
933         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
934     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
935       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
936       break;
937     }
938   }
939   if (!aSketch) {
940     theError = "There is no sketch referring to the current feature";
941     return false;
942   }
943
944   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
945   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
946   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
947
948   if (anEdge->isLine()) {
949     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
950     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
951     std::shared_ptr<GeomAPI_Pnt> aLineLoc = aLine->location();
952     double aDot = aNormal->dot(aLineDir);
953     double aDist = aLineLoc->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
954     bool aValid = (fabs(aDot) >= tolerance && fabs(aDot) < 1.0 - tolerance) ||
955            (fabs(aDot) < tolerance && fabs(aDist) > tolerance);
956     if (!aValid)
957       theError = "Error: Edge is already in the sketch plane.";
958     return aValid;
959   }
960   else if (anEdge->isCircle() || anEdge->isArc()) {
961     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
962     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
963     std::shared_ptr<GeomAPI_Pnt> aCircCenter = aCircle->center();
964     double aDot = fabs(aNormal->dot(aCircNormal));
965     double aDist = aCircCenter->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
966     bool aValid = fabs(aDot - 1.0) < tolerance * tolerance && fabs(aDist) > tolerance;
967     if (!aValid)
968       theError.arg(anEdge->isCircle() ? "Error: Cirlce is already in the sketch plane."
969                                       : "Error: Arc is already in the sketch plane.");
970     return aValid;
971   }
972
973   theError = "Error: Selected object is not line, circle or arc.";
974   return false;
975 }