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