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