Salome HOME
Issue #17347: B-Splines in Sketcher
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SketchPlugin_Validators.h"
21
22 #include "SketchPlugin_Arc.h"
23 #include "SketchPlugin_Circle.h"
24 #include "SketchPlugin_ConstraintCoincidence.h"
25 #include "SketchPlugin_ConstraintDistance.h"
26 #include "SketchPlugin_ConstraintRigid.h"
27 #include "SketchPlugin_ConstraintTangent.h"
28 #include "SketchPlugin_Ellipse.h"
29 #include "SketchPlugin_EllipticArc.h"
30 #include "SketchPlugin_Fillet.h"
31 #include "SketchPlugin_Line.h"
32 #include "SketchPlugin_MacroArc.h"
33 #include "SketchPlugin_MacroCircle.h"
34 #include "SketchPlugin_MultiRotation.h"
35 #include "SketchPlugin_Point.h"
36 #include "SketchPlugin_Sketch.h"
37 #include "SketchPlugin_Trim.h"
38 #include "SketchPlugin_Tools.h"
39
40 #include "SketcherPrs_Tools.h"
41
42 #include <Events_InfoMessage.h>
43
44 #include <ModelAPI_Data.h>
45 #include <ModelAPI_Validator.h>
46 #include <ModelAPI_AttributeDouble.h>
47 #include <ModelAPI_AttributeInteger.h>
48 #include <ModelAPI_AttributeRefAttr.h>
49 #include <ModelAPI_AttributeRefList.h>
50 #include <ModelAPI_AttributeSelectionList.h>
51 #include <ModelAPI_AttributeString.h>
52 #include <ModelAPI_Session.h>
53 #include <ModelAPI_Tools.h>
54 #include <ModelAPI_ResultConstruction.h>
55
56 #include <ModelGeomAlgo_Point2D.h>
57 #include <ModelGeomAlgo_Shape.h>
58
59 #include <GeomAlgoAPI_EdgeBuilder.h>
60 #include <GeomAlgoAPI_ShapeTools.h>
61
62 #include <GeomAPI_Circ.h>
63 #include <GeomAPI_Dir2d.h>
64 #include <GeomAPI_Ellipse.h>
65 #include <GeomAPI_Lin.h>
66 #include <GeomAPI_Edge.h>
67 #include <GeomAPI_Vertex.h>
68
69 #include <GeomDataAPI_Point2D.h>
70 #include <GeomDataAPI_Point2DArray.h>
71
72 #include <algorithm>
73 #include <cmath>
74
75 const double tolerance = 1.e-7;
76
77 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
78                                                  const std::list<std::string>& theArguments,
79                                                  Events_InfoMessage& theError) const
80 {
81   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
82     theError = "The attribute with the %1 type is not processed";
83     theError.arg(theAttribute->attributeType());
84     return false;
85   }
86
87   // there is a check whether the feature contains a point and a linear edge or two point values
88   std::string aParamA = theArguments.front();
89   SessionPtr aMgr = ModelAPI_Session::get();
90   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
91
92   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
93                                                                       (theAttribute);
94   bool isObject = aRefAttr->isObject();
95   if (!isObject) {
96     // an attribute is a point. A point value is valid always for the distance
97     return true;
98   } else {
99     // 1. check whether the references object is a linear
100     ObjectPtr anObject = aRefAttr->object();
101
102     const ModelAPI_AttributeValidator* aShapeValidator =
103       dynamic_cast<const ModelAPI_AttributeValidator*>(
104       aFactory->validator("GeomValidators_ShapeType"));
105     std::list<std::string> anArguments;
106     anArguments.push_back("circle");
107     Events_InfoMessage aCircleError;
108     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
109     // the circle line is not a valid case
110     if (aShapeValid) {
111       theError = "Circle can not be used in distance constraint";
112       return false;
113     }
114
115     anArguments.clear();
116     anArguments.push_back("line");
117     Events_InfoMessage aLineError;
118     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
119     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
120     if (aShapeValid) {
121       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
122       // If it is a line then we have to check that first attribute id not a line
123       std::shared_ptr<SketchPlugin_Feature> aSFeature =
124         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
125       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
126       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
127       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
128         aFeature->data(), aParamA, aPlane);
129       if (!aPoint.get()) {
130         theError = "One of parameters of distance constraint should be a point";
131         return false;
132       }
133     }
134   }
135   return true;
136 }
137
138 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
139                                                 const std::list<std::string>& theArguments,
140                                                 Events_InfoMessage& theError) const
141 {
142   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
143     theError = "The attribute with the %1 type is not processed";
144     theError.arg(theAttribute->attributeType());
145     return false;
146   }
147
148   // there is a check whether the feature contains a point and a linear edge or two point values
149   std::string aParamA = theArguments.front();
150   SessionPtr aMgr = ModelAPI_Session::get();
151   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
152
153   FeaturePtr anAttributeFeature =
154     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
155   AttributeRefAttrPtr aRefAttr =
156     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
157
158   bool isObject = aRefAttr->isObject();
159   ObjectPtr anObject = aRefAttr->object();
160   if (isObject && anObject.get()) {
161     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
162
163     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
164     ObjectPtr aOtherObject = aOtherAttr->object();
165     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
166     if (!aOtherFea)
167       return true;
168
169     if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
170         aOtherFea->getKind() == SketchPlugin_Line::ID()) {
171       theError = "Two segments cannot be tangent";
172       return false;
173     }
174     return true;
175   }
176   else {
177     theError = "It uses an empty object";
178     return false;
179   }
180
181   return true;
182 }
183
184 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
185                                                       const std::list<std::string>& theArguments,
186                                                       Events_InfoMessage& theError) const
187 {
188   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
189     theError = "The attribute with the %1 type is not processed";
190     theError.arg(theAttribute->attributeType());
191     return false;
192   }
193
194   std::string aParamA = theArguments.front();
195   SessionPtr aMgr = ModelAPI_Session::get();
196   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
197
198   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
199   AttributeRefAttrPtr aRefAttr =
200       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
201
202   bool isObject = aRefAttr->isObject();
203   ObjectPtr anObject = aRefAttr->object();
204   if (isObject && anObject.get()) {
205     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
206
207     AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
208     ObjectPtr aOtherObject = aOtherAttr->object();
209     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
210     if (!aOtherFea)
211       return true;
212
213     // at least one feature should be a line
214     if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
215         aOtherFea->getKind() != SketchPlugin_Line::ID()) {
216       theError = "At least one feature should be a line";
217       return false;
218     }
219   }
220   else {
221     theError = "It uses an empty object";
222     return false;
223   }
224
225   return true;
226 }
227
228 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
229                                              const std::list<std::string>& theArguments,
230                                              Events_InfoMessage& theError) const
231 {
232   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
233     theError = "The attribute with the %1 type is not processed";
234     theError.arg(theAttribute->attributeType());
235     return false;
236   }
237
238   std::shared_ptr<SketchPlugin_Feature> aFeature =
239       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
240   if (!aFeature)
241     return true;
242
243   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
244
245   SketchPlugin_Sketch* aSketch = aFeature->sketch();
246   int aNbFeatures = aSketch->numberOfSubs();
247   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
248     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
249     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
250       continue;
251     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
252         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
253     if (aRefAttr->isObject()) {
254       if (aRefAttr->object() == aRAttr->object()) {
255         ObjectPtr anObject = aRefAttr->object();
256         std::string aName = anObject.get() ? anObject->data()->name() : "";
257         theError = "The object %1 has been already fixed.";
258         theError.arg(aName);
259         return false;
260       }
261     }
262     else if (aRefAttr->attr() == aRAttr->attr()) {
263       AttributePtr anAttribute = aRefAttr->attr();
264       std::string aName = anAttribute.get() ? anAttribute->id() : "";
265       theError = "The attribute %1 has been already fixed.";
266       theError.arg(aName);
267       return false;
268     }
269   }
270   return true;
271 }
272
273 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
274                                               const std::list<std::string>& theArguments,
275                                               Events_InfoMessage& theError) const
276 {
277   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
278     theError = "The attribute with the %1 type is not processed";
279     theError.arg(theAttribute->attributeType());
280     return false;
281   }
282
283   std::string aParamA = theArguments.front();
284   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
285   AttributeRefAttrPtr aRefAttr[2];
286   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
287   aRefAttr[1] = aFeature->data()->refattr(aParamA);
288
289   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
290     theError = "Attributes can not be used in equal constraint";
291     return false;
292   }
293
294   std::string aType[2];
295   std::list<std::string> anArguments;
296   for (int i = 0; i < 2; i++) {
297     ObjectPtr anObject = aRefAttr[i]->object();
298     if (!anObject.get()) {
299       theError = "An empty object is used.";
300       return false;
301     }
302
303     aFeature = ModelAPI_Feature::feature(anObject);
304     if (!aFeature.get()) {
305       theError = "An empty feature is used.";
306       return false;
307     }
308
309     aType[i] = aFeature->getKind();
310     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
311         aFeature->getKind() != SketchPlugin_Circle::ID() &&
312         aFeature->getKind() != SketchPlugin_Arc::ID() &&
313         aFeature->getKind() != SketchPlugin_Ellipse::ID() &&
314         aFeature->getKind() != SketchPlugin_EllipticArc::ID()) {
315       theError = "The %1 feature is not supported by the Equal constraint.";
316       theError.arg(aFeature->getKind());
317       // wrong type of attribute
318       return false;
319     }
320   }
321
322   bool isOk = aType[0] == aType[1];
323   if (!isOk) {
324     // circle and arc may be equal
325     isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
326         || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
327   }
328   if (!isOk) {
329     // ellipse and elliptic arc may be equal
330     isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID())
331         || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID());
332   }
333   if (!isOk) {
334     theError = "Features with kinds %1 and %2 can not be equal.";
335     theError.arg(aType[0]).arg(aType[1]);
336     return false;
337   }
338   return true;
339 }
340
341 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
342                                                const std::list<std::string>& theArguments,
343                                                Events_InfoMessage& theError) const
344 {
345   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
346     theError = "The attribute with the %1 type is not processed";
347     theError.arg(theAttribute->attributeType());
348     return false;
349   }
350
351   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
352   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
353
354   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
355       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
356   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
357
358   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
359     ObjectPtr aSelObject = aSelAttr->object(anInd);
360     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
361     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
362     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
363       if (aSelObject == *aMirIter) {
364         theError = "The object %1 is a result of mirror";
365         theError.arg(aName);
366         return false;
367       }
368   }
369   return true;
370 }
371
372 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
373                                                     const std::list<std::string>& theArguments,
374                                                     Events_InfoMessage& theError) const
375 {
376   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
377     theError = "The attribute with the %1 type is not processed";
378     theError.arg(theAttribute->attributeType());
379     return false;
380   }
381
382   // there is a check whether the feature contains a point and a linear edge or two point values
383   std::string aParamA = theArguments.front();
384   SessionPtr aMgr = ModelAPI_Session::get();
385   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
386
387   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
388   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
389   if (!aRefAttrA) {
390     theError = "The %1 attribute should be %2";
391     theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
392     return false;
393   }
394
395   AttributeRefAttrPtr aRefAttrB =
396     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
397
398   // first attribute is a point, it may coincide with any object
399   if (!aRefAttrA->isObject())
400     return true;
401   else {
402     ObjectPtr anObject = aRefAttrA->object();
403     if (!anObject.get()) {
404       theError = "%1 attribute has an empty object";
405       theError.arg(aParamA);
406       return false;
407     }
408     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
409     if (!aFeature.get()) {
410       theError = "%1 attribute has an empty feature";
411       theError.arg(aParamA);
412       return false;
413     }
414
415     if (aFeature->getKind() == SketchPlugin_Point::ID())
416       return true;
417   }
418
419   // second attribute is a point, it may coincide with any object
420   if (!aRefAttrB->isObject())
421     return true;
422   else {
423     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
424     if (!aFeature) {
425       theError = "%1 attribute has an empty object";
426       theError.arg(theAttribute->id());
427       return false;
428     }
429     if (aFeature->getKind() == SketchPlugin_Point::ID())
430       return true;
431   }
432   theError = "There is no an attribute filled by a point";
433   return false;
434 }
435
436
437 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
438                                          const std::list<std::string>& theArguments,
439                                          Events_InfoMessage& theError) const
440 {
441   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
442     theError = "The attribute with the %1 type is not processed";
443     theError.arg(theAttribute->attributeType());
444     return false;
445   }
446
447   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
448   AttributeRefListPtr aSelAttr =
449     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
450
451   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
452       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
453   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
454       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
455   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
456   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
457
458   std::list<ObjectPtr>::iterator anObjIter;
459   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
460     ObjectPtr aSelObject = aSelAttr->object(anInd);
461     anObjIter = anInitialObjects.begin();
462     for (; anObjIter != anInitialObjects.end(); anObjIter++)
463       if (aSelObject == *anObjIter)
464         break;
465     if (anObjIter != anInitialObjects.end())
466       continue;
467     anObjIter = aCopiedObjects.begin();
468     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
469       if (aSelObject == *anObjIter) {
470         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
471         theError = "The object %1 is a result of copy";
472         theError.arg(aName);
473         return false;
474       }
475   }
476   return true;
477 }
478
479 bool SketchPlugin_SolverErrorValidator::isValid(
480   const std::shared_ptr<ModelAPI_Feature>& theFeature,
481   const std::list<std::string>& theArguments,
482   Events_InfoMessage& theError) const
483 {
484   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
485
486   if (!aAttributeString->value().empty()) {
487     theError = aAttributeString->value();
488     return false;
489   }
490
491   return true;
492 }
493
494 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
495                                                         std::string theAttribute)
496 {
497   return true;
498 }
499
500 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
501                                   const FeaturePtr theFeature)
502 {
503   for(std::set<AttributePtr>::const_iterator
504       anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
505     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
506     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
507     if (!aFeature)
508       continue;
509     if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
510       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
511         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
512       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
513         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
514       if(anAttrRefA.get()) {
515         ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
516         if(aResA.get()) {
517           DocumentPtr aDoc = aResA->document();
518           if(aDoc.get()) {
519             FeaturePtr aFeatureA = aDoc->feature(aResA);
520             if(aFeatureA.get() && aFeatureA == theFeature) {
521               return true;
522             }
523           }
524         }
525       }
526       if(anAttrRefB.get()) {
527         ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
528         if(aResB.get()) {
529           DocumentPtr aDoc = aResB->document();
530           if(aDoc.get()) {
531             FeaturePtr aFeatureB = aDoc->feature(aResB);
532             if(aFeatureB.get() && aFeatureB == theFeature) {
533               return true;
534             }
535           }
536         }
537       }
538     }
539   }
540   return false;
541 }
542
543 static bool isPointPointCoincidence(const FeaturePtr& theCoincidence)
544 {
545   AttributeRefAttrPtr aRefAttr[2] = {
546       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()),
547       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B())
548   };
549
550   bool arePoints = true;
551   for (int i = 0; i < 2 && arePoints; ++i) {
552     if (aRefAttr[i]->isObject()) {
553       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
554       arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID();
555     } else
556       arePoints = aRefAttr[i]->attr().get() != NULL;
557   }
558   return arePoints;
559 }
560
561 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
562                                                  const std::list<std::string>& theArguments,
563                                                  Events_InfoMessage& theError) const
564 {
565   AttributeRefAttrPtr aPointRefAttr =
566     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
567   if(!aPointRefAttr.get()) {
568     theError = "Error: Point not selected.";
569     return false;
570   }
571
572   AttributePtr aPointAttribute = aPointRefAttr->attr();
573   if (!aPointAttribute.get()) {
574     theError = "Error: Bad point selected.";
575     return false;
576   }
577   std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
578     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
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();
584       anIt != aRefsList.cend(); ++anIt) {
585     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
586     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
587     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
588       if (!isPointPointCoincidence(aConstrFeature))
589         continue;
590
591       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
592         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
593       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
594         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
595
596       AttributePtr anAttrA = anAttrRefA->attr();
597       if(aPointAttribute == anAttrA) {
598         aConstraintCoincidence = aConstrFeature;
599         break;
600       }
601
602       AttributePtr anAttrB = anAttrRefB->attr();
603       if(aPointAttribute == anAttrB) {
604         aConstraintCoincidence = aConstrFeature;
605         break;
606       }
607     }
608   }
609
610   if(!aConstraintCoincidence.get()) {
611     theError = "Error: one of the selected point does not have coincidence.";
612     return false;
613   }
614
615   // Get coincides from constraint.
616   std::set<FeaturePtr> aCoinsides;
617   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
618                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
619                                         aCoinsides,
620                                         true);
621   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
622                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
623                                         aCoinsides,
624                                         true);
625
626   // Remove points and external lines from set of coincides.
627   std::set<FeaturePtr> aNewSetOfCoincides;
628   for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
629       anIt != aCoinsides.end(); ++anIt) {
630     std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
631       std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
632     if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
633       continue;
634     }
635     if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
636         (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
637           continue;
638     }
639     if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
640       AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
641       std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
642         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
643       double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
644       if(aDistSelectedArcCenter < tolerance) {
645         continue;
646       }
647     }
648     aNewSetOfCoincides.insert(*anIt);
649   }
650   aCoinsides = aNewSetOfCoincides;
651
652   // If we still have more than two coincides remove auxilary entities from set of coincides.
653   if(aCoinsides.size() > 2) {
654     aNewSetOfCoincides.clear();
655     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
656         anIt != aCoinsides.end(); ++anIt) {
657       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
658         aNewSetOfCoincides.insert(*anIt);
659       }
660     }
661     aCoinsides = aNewSetOfCoincides;
662   }
663
664   if(aCoinsides.size() != 2) {
665     theError = "Error: One of the selected points does not have two suitable edges for fillet.";
666     return false;
667   }
668
669   // Check that selected edges don't have tangent constraint.
670   std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
671   FeaturePtr aFirstFeature = *anIt++;
672   FeaturePtr aSecondFeature = *anIt;
673   const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
674   if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
675     theError = "Error: Edges in selected point has tangent constraint.";
676     return false;
677   }
678
679   std::list<ResultPtr> aFirstResults = aFirstFeature->results();
680   for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
681       aResIt != aFirstResults.end(); ++aResIt) {
682     ResultPtr aRes = *aResIt;
683     const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
684     if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
685       theError = "Error: Edges in selected point has tangent constraint.";
686       return false;
687     }
688   }
689
690   // Check the features are not tangent
691   std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
692   std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
693   if (!aFirstShape || !aFirstShape->isEdge() ||
694       !aSecondShape || !aSecondShape->isEdge()) {
695     theError = "Error: At least on of the features is not an edge";
696     return false;
697   }
698
699   std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
700   std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
701
702   static const double TOL = 1.e-7;
703   if (anEdge1->isLine() && anEdge2->isLine()) {
704     // Check that lines not collinear
705     std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
706     std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
707     double aCross = aDir1->cross(aDir2)->squareModulus();
708     if (aCross < TOL * TOL)
709       return false;
710   } else if (anEdge1->isArc() && anEdge2->isArc()) {
711     // check the circles are not tangent
712     std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
713     std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
714     double aDistCC = aCirc1->center()->distance(aCirc2->center());
715     double aRadSum = aCirc1->radius() + aCirc2->radius();
716     double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
717     if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
718       return false;
719   } else {
720     // check whether line and arc are tangent
721     std::shared_ptr<GeomAPI_Circ> aCirc;
722     std::shared_ptr<GeomAPI_Lin> aLine;
723     if (anEdge1->isLine()) {
724       aLine = anEdge1->line();
725       aCirc = anEdge2->circle();
726     } else {
727       aCirc = anEdge1->circle();
728       aLine = anEdge2->line();
729     }
730
731     double aDistCL = aLine->distance(aCirc->center());
732     if (fabs(aDistCL - aCirc->radius()) < TOL)
733       return false;
734   }
735
736   return true;
737 }
738
739 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
740                                                     const std::list<std::string>& theArguments,
741                                                     Events_InfoMessage& theError) const
742 {
743   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
744     theError = "The attribute with the %1 type is not processed";
745     theError.arg(theAttribute->attributeType());
746     return false;
747   }
748
749   // there is a check whether the feature contains a point and a linear edge or two point values
750   std::string aParamA = theArguments.front();
751   SessionPtr aMgr = ModelAPI_Session::get();
752   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
753
754   FeaturePtr anAttributeFeature =
755     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
756   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
757   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
758
759   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
760   int aNbPoints = 0;
761   int aNbLines = 0;
762   for (int i = 0; i < 2; ++i) {
763     if (!aRefAttrs[i]->isObject())
764       ++aNbPoints;
765     else {
766       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
767       if (!aFeature) {
768         if (aNbPoints + aNbLines != 0)
769           return true;
770         else continue;
771       }
772
773       if (aFeature->getKind() == SketchPlugin_Point::ID())
774         ++aNbPoints;
775       else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
776                aFeature->getKind() == SketchPlugin_Arc::ID() ||
777                aFeature->getKind() == SketchPlugin_EllipticArc::ID())
778         ++aNbLines;
779     }
780   }
781
782   if (aNbPoints != 1 || aNbLines != 1) {
783     theError = "Middle point constraint allows points and lines only";
784     return false;
785   }
786   return true;
787 }
788
789 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
790                                                     const std::list<std::string>& /*theArguments*/,
791                                                     Events_InfoMessage& theError) const
792 {
793   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
794     theError = "The attribute with the %1 type is not processed";
795     theError.arg(theAttribute->attributeType());
796     return false;
797   }
798   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
799   AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
800   if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
801     return true; // not applicable for non-tangent arcs
802
803   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
804   AttributePtr anAttr = aRefAttr->attr();
805   if (!anAttr) {
806     theError = "The attribute %1 should be a point";
807     theError.arg(theAttribute->id());
808     return false;
809   }
810
811   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
812   const std::string& aFeatureType = anAttrFeature->getKind();
813   if (aFeatureType == SketchPlugin_Arc::ID()) {
814     // selected point should not be a center of arc
815     const std::string& aPntId = anAttr->id();
816     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
817       theError = "The attribute %1 is not supported";
818       theError.arg(aPntId);
819       return false;
820     }
821   }
822   else if (aFeatureType == SketchPlugin_Line::ID()) {
823     // selected point should be bound point of line
824     const std::string& aPntId = anAttr->id();
825     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
826       theError = "The attribute %1 is not supported";
827       theError.arg(aPntId);
828       return false;
829     }
830   }
831   else {
832     theError = "Unable to build tangent arc on %1";
833     theError.arg(anAttrFeature->getKind());
834     return false;
835   }
836
837   return true;
838 }
839
840 bool SketchPlugin_ArcTransversalPointValidator::isValid(
841     const AttributePtr& theAttribute,
842     const std::list<std::string>& /*theArguments*/,
843     Events_InfoMessage& theError) const
844 {
845   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
846     theError = "The attribute with the %1 type is not processed";
847     theError.arg(theAttribute->attributeType());
848     return false;
849   }
850   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
851   AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
852   if (anArcTypeAttr &&
853       anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
854     return true; // not applicable for non-transversal arcs
855
856   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
857   AttributePtr anAttr = aRefAttr->attr();
858   if (!anAttr) {
859     theError = "The attribute %1 should be a point";
860     theError.arg(theAttribute->id());
861     return false;
862   }
863
864   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
865   const std::string& aFeatureType = anAttrFeature->getKind();
866   if (aFeatureType == SketchPlugin_Line::ID()) {
867     // selected point should be bound point of line
868     const std::string& aPntId = anAttr->id();
869     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
870       theError = "The attribute %1 is not supported";
871       theError.arg(aPntId);
872       return false;
873     }
874   }
875   else {
876     theError = "Unable to build perpendicular arc on %1";
877     theError.arg(anAttrFeature->getKind());
878     return false;
879   }
880
881   return true;
882 }
883
884 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
885                                                  const std::list<std::string>& theArguments,
886                                                  Events_InfoMessage& theError) const
887 {
888   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
889     theError = "The attribute with the %1 type is not processed";
890     theError.arg(theAttribute->attributeType());
891     return false;
892   }
893   AttributeSelectionPtr anExternalAttr =
894       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
895   std::shared_ptr<GeomAPI_Edge> anEdge;
896   if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
897     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
898   } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
899             anExternalAttr->context()->shape()->isEdge()) {
900     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
901   }
902
903   if (!anEdge) {
904     theError = "The attribute %1 should be an edge";
905     theError.arg(theAttribute->id());
906     return false;
907   }
908
909   // find a sketch
910   std::shared_ptr<SketchPlugin_Sketch> aSketch;
911   std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
912   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
913   for (; anIt != aRefs.end(); ++anIt) {
914     CompositeFeaturePtr aComp =
915         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
916     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
917       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
918       break;
919     }
920   }
921   if (!aSketch) {
922     theError = "There is no sketch referring to the current feature";
923     return false;
924   }
925
926   // check the edge is intersected with sketch plane
927   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
928
929   std::list<GeomPointPtr> anIntersectionsPoints;
930   anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
931   if (anIntersectionsPoints.empty()) {
932     theError = "The edge is not intersected with sketch plane";
933     return false;
934   }
935   return true;
936 }
937
938 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
939                                           const std::list<std::string>& theArguments,
940                                           Events_InfoMessage& theError) const
941 {
942   bool aValid = false;
943
944   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
945     theError = "The attribute with the %1 type is not processed";
946     theError.arg(theAttribute->attributeType());
947     return aValid;
948   }
949   AttributeReferencePtr aFeatureAttr =
950             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
951   std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
952     std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
953
954   ObjectPtr anAttrObject = aFeatureAttr->value();
955   if (!anAttrObject) {
956     AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
957     aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
958     anAttrObject = aFeatureAttr->value();
959   }
960
961   FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
962   if (!anAttrFeature)
963     return aValid;
964
965   std::set<ResultPtr> anEdgeShapes;
966   ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
967   if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
968     return aValid;
969
970   // coincidences to the feature
971   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
972   ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
973                       SketchPlugin_ConstraintCoincidence::ID(),
974                       aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
975
976   GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
977   std::shared_ptr<SketchPlugin_Feature> aSFeature =
978                                 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
979   if (!aSFeature)
980     return false;
981   SketchPlugin_Sketch* aSketch = aSFeature->sketch();
982
983   std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
984   std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
985       aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
986   std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
987       aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
988   std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
989       aData->attribute(SketchPlugin_Sketch::NORM_ID()));
990   std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
991
992   typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
993                     std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
994                               std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
995   PointToRefsMap aPointsInfo;
996
997   ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
998                                               aX->dir(), aDirY, aPointsInfo);
999   int aCoincidentToFeature = (int)aPointsInfo.size();
1000   if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() ||
1001       anAttrFeature->getKind() == SketchPlugin_Ellipse::ID())
1002     aValid = aCoincidentToFeature >= 2;
1003   else
1004     aValid = aCoincidentToFeature >= 1;
1005
1006   return aValid;
1007 }
1008
1009 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
1010                                          const std::list<std::string>& theArguments,
1011                                          Events_InfoMessage& theError) const
1012 {
1013   bool aValid = false;
1014
1015   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1016     theError = "The attribute with the %1 type is not processed";
1017     theError.arg(theAttribute->attributeType());
1018     return aValid;
1019   }
1020   AttributeReferencePtr aBaseObjectAttr =
1021             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1022
1023   std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
1024                  std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1025
1026   ObjectPtr aBaseObject = aBaseObjectAttr->value();
1027   if (!aBaseObject) {
1028     AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1029     aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1030     aBaseObject = aBaseObjectAttr->value();
1031   }
1032
1033   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1034   if (!aBaseFeature)
1035     return aValid;
1036
1037   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1038                                  std::dynamic_pointer_cast<SketchPlugin_Feature>(aBaseFeature);
1039   if (!aSketchFeature.get() || aSketchFeature->isCopy())
1040     return aValid;
1041
1042   // point on feature
1043   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1044                        aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
1045
1046   SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
1047
1048   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1049   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
1050                                                               anAttributePnt2d->y());
1051
1052   std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
1053   std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
1054            std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1055                      std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
1056   SketchPlugin_SegmentationTools::fillObjectShapes(
1057       aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
1058   const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
1059
1060   return aShapes.size() > 1;
1061 }
1062
1063 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
1064                                                const std::list<std::string>& theArguments,
1065                                                Events_InfoMessage& theError) const
1066 {
1067   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1068     theError = "The attribute with the %1 type is not processed";
1069     theError.arg(theAttribute->attributeType());
1070     return false;
1071   }
1072
1073   AttributeSelectionPtr aFeatureAttr =
1074       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1075   std::shared_ptr<GeomAPI_Edge> anEdge;
1076   std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1077   if (aFeatureAttr.get()) {
1078     GeomShapePtr aVal = aFeatureAttr->value();
1079     ResultPtr aRes = aFeatureAttr->context();
1080     if (aVal && aVal->isVertex())
1081       return true; // vertex is always could be projected
1082     if (aVal && aVal->isEdge()) {
1083       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
1084     } else if(aRes && aRes->shape()) {
1085       if (aRes->shape()->isVertex())
1086         return true; // vertex is always could be projected
1087       else if (aRes->shape()->isEdge())
1088         anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
1089     }
1090
1091     // try to convert result to sketch feature
1092     if (aRes) {
1093       aSketchFeature =
1094         std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1095     }
1096   }
1097   if (!anEdge) {
1098     theError = "The attribute %1 should be an edge or vertex";
1099     theError.arg(theAttribute->id());
1100     return false;
1101   }
1102
1103   // find a sketch
1104   std::shared_ptr<SketchPlugin_Sketch> aSketch;
1105   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1106   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1107   for (; anIt != aRefs.end(); ++anIt) {
1108     CompositeFeaturePtr aComp =
1109         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1110     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1111       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1112       break;
1113     }
1114   }
1115   if (!aSketch) {
1116     theError = "There is no sketch referring to the current feature";
1117     return false;
1118   }
1119   if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1120     theError = "Unable to project feature from the same sketch";
1121     return false;
1122   }
1123
1124   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1125   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1126   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1127
1128   bool aValid = true;
1129   if (anEdge->isLine()) {
1130     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1131     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1132     double aDot = fabs(aNormal->dot(aLineDir));
1133     aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1134     if (!aValid)
1135       theError = "Error: Line is orthogonal to the sketch plane.";
1136   }
1137   else if (anEdge->isCircle() || anEdge->isArc()) {
1138     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1139     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1140     double aDot = fabs(aNormal->dot(aCircNormal));
1141     aValid = aDot >= tolerance * tolerance;
1142     if (!aValid)
1143       theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1144                                       : "Error: Arc is orthogonal to the sketch plane.");
1145   }
1146   else if (anEdge->isEllipse()) {
1147     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1148     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1149     double aDot = fabs(aNormal->dot(anEllipseNormal));
1150     aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
1151     if (!aValid)
1152       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1153                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1154   }
1155
1156   return aValid;
1157 }
1158
1159
1160 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1161                                    const std::set<FeaturePtr>& theSet2)
1162 {
1163   std::set<FeaturePtr> aCommon;
1164   if (theSet1.empty() || theSet2.empty())
1165     return aCommon;
1166
1167   std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1168   for (; anIt2 != theSet2.end(); ++anIt2)
1169     if (theSet1.find(*anIt2) != theSet1.end())
1170       aCommon.insert(*anIt2);
1171   return aCommon;
1172 }
1173
1174 bool SketchPlugin_DifferentReferenceValidator::isValid(
1175     const AttributePtr& theAttribute,
1176     const std::list<std::string>& theArguments,
1177     Events_InfoMessage& theError) const
1178 {
1179   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1180
1181   int aNbFeaturesReferred = 0;
1182   int aNbAttributesReferred = 0;
1183   std::set<FeaturePtr> aCommonReferredFeatures;
1184
1185   // find all features referred by attributes listed in theArguments
1186   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1187   for (; anArgIt != theArguments.end(); ++anArgIt) {
1188     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1189     if (!aRefAttr)
1190       continue;
1191
1192     std::set<FeaturePtr> aCoincidentFeatures;
1193     if (aRefAttr->isObject()) {
1194       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1195       if (aFeature) {
1196         aCoincidentFeatures.insert(aFeature);
1197         aNbFeaturesReferred += 1;
1198       }
1199     } else {
1200       AttributePoint2DPtr aPoint =
1201           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1202       if (aPoint) {
1203         aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1204         aNbAttributesReferred += 1;
1205       }
1206     }
1207
1208     if (aCommonReferredFeatures.empty())
1209       aCommonReferredFeatures = aCoincidentFeatures;
1210     else
1211       aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1212
1213     if (aCommonReferredFeatures.empty())
1214       return true;
1215   }
1216
1217   bool isOk = aNbFeaturesReferred < 1;
1218   if (aNbFeaturesReferred == 1) {
1219     if (aCommonReferredFeatures.size() == 1) {
1220       FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1221       isOk = aNbAttributesReferred <= 1 ||
1222              aFeature->getKind() == SketchPlugin_Circle::ID() ||
1223              aFeature->getKind() == SketchPlugin_Arc::ID();
1224     } else
1225       isOk = false;
1226   }
1227
1228   if (!isOk)
1229     theError = "Attributes are referred to the same feature";
1230   return isOk;
1231 }
1232
1233 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1234     const AttributePtr& theAttribute,
1235     const std::list<std::string>& theArguments,
1236     Events_InfoMessage& theError) const
1237 {
1238   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1239   std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1240
1241   // find all points referred by attributes listed in theArguments
1242   bool hasRefsToPoints = false;
1243   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1244   for (; anArgIt != theArguments.end(); ++anArgIt) {
1245     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1246     if (!aRefAttr)
1247       continue;
1248
1249     if (!aRefAttr->isObject()) {
1250       AttributePoint2DPtr aPoint =
1251           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1252       if (aReferredCoincidentPoints.empty())
1253         aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1254       else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1255         return true; // non-coincident point has been found
1256       else
1257         hasRefsToPoints = true;
1258     }
1259   }
1260
1261   if (hasRefsToPoints)
1262     theError = "Attributes are referred to the same point";
1263   return !hasRefsToPoints;
1264 }
1265
1266 bool SketchPlugin_CirclePassedPointValidator::isValid(
1267     const AttributePtr& theAttribute,
1268     const std::list<std::string>&,
1269     Events_InfoMessage& theError) const
1270 {
1271   static const std::string aErrorMessage(
1272       "Passed point refers to the same feature as a center point");
1273
1274   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1275
1276   AttributeRefAttrPtr aCenterRef =
1277       anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1278   AttributeRefAttrPtr aPassedRef =
1279       anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1280
1281   if (!aPassedRef->isObject())
1282     return true;
1283
1284   FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1285   if (!aPassedFeature)
1286     return true;
1287
1288   if (aCenterRef->isObject()) {
1289     if (aCenterRef->object() == aPassedRef->object()) {
1290       theError = aErrorMessage;
1291       return false;
1292     }
1293   } else {
1294     AttributePoint2DPtr aCenterPoint =
1295         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1296     if (aCenterPoint) {
1297       std::set<FeaturePtr> aCoincidentFeatures =
1298           SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1299       // check one of coincident features is a feature referred by passed point
1300       std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1301       for(; anIt != aCoincidentFeatures.end(); ++anIt)
1302         if (*anIt == aPassedFeature) {
1303           theError = aErrorMessage;
1304           return false;
1305         }
1306     }
1307   }
1308   return true;
1309 }
1310
1311 bool SketchPlugin_ThirdPointValidator::isValid(
1312     const AttributePtr& theAttribute,
1313     const std::list<std::string>& theArguments,
1314     Events_InfoMessage& theError) const
1315 {
1316   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1317   return arePointsNotOnLine(anOwner, theError) &&
1318          arePointsNotSeparated(anOwner, theArguments, theError);
1319 }
1320
1321 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1322                                               const std::string& thePointAttrName,
1323                                               const std::string& theRefPointAttrName)
1324 {
1325   AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1326       theMacroCircle->attribute(thePointAttrName));
1327   AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1328
1329   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1330   if (aRefAttr) {
1331     if (aRefAttr->isObject()) {
1332       // project a point onto selected feature
1333       std::shared_ptr<SketchPlugin_Feature> aFeature =
1334           std::dynamic_pointer_cast<SketchPlugin_Feature>(
1335           ModelAPI_Feature::feature(aRefAttr->object()));
1336       if (aFeature) {
1337         SketchPlugin_Sketch* aSketch = aFeature->sketch();
1338         std::shared_ptr<GeomAPI_Edge> anEdge =
1339             std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1340         if (anEdge) {
1341           std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1342           if (anEdge->isLine())
1343             aPoint3D = anEdge->line()->project(aPoint3D);
1344           else if (anEdge->isCircle())
1345             aPoint3D = anEdge->circle()->project(aPoint3D);
1346           if(aPoint3D)
1347             aPoint = aSketch->to2D(aPoint3D);
1348         }
1349       }
1350     } else {
1351       AttributePoint2DPtr anOtherPoint =
1352           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1353       if (anOtherPoint)
1354         aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1355     }
1356   }
1357
1358   return aPoint;
1359 }
1360
1361 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1362                                  std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1363 {
1364   if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1365     thePoints[0] = toPoint(theMacroFeature,
1366           SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1367           SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1368     thePoints[1] = toPoint(theMacroFeature,
1369           SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1370           SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1371     thePoints[2] = toPoint(theMacroFeature,
1372           SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1373           SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1374   } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1375     thePoints[0] = toPoint(theMacroFeature,
1376           SketchPlugin_MacroArc::START_POINT_2_ID(),
1377           SketchPlugin_MacroArc::START_POINT_REF_ID());
1378     thePoints[1] = toPoint(theMacroFeature,
1379           SketchPlugin_MacroArc::END_POINT_2_ID(),
1380           SketchPlugin_MacroArc::END_POINT_REF_ID());
1381     thePoints[2] = toPoint(theMacroFeature,
1382           SketchPlugin_MacroArc::PASSED_POINT_ID(),
1383           SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1384   }
1385 }
1386
1387 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1388                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1389                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1390 {
1391   static const double aTolerance = 1.e-7;
1392   if (thePoint1->distance(thePoint2) < aTolerance ||
1393       thePoint1->distance(thePoint3) < aTolerance)
1394     return true;
1395
1396   std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1397                                                             thePoint2->y() - thePoint1->y()));
1398   std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1399                                                             thePoint3->y() - thePoint1->y()));
1400   return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1401 }
1402
1403 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1404                          const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1405                          const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1406 {
1407   static const double aTolerance = 1.e-7;
1408   std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1409   std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1410
1411   std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1412   // the first point is on the line
1413   if (aVec1->squareModulus() < aTolerance * aTolerance)
1414     return false;
1415   std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1416   std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1417   // the second point is on the line
1418   if (aVec2->squareModulus() < aTolerance * aTolerance)
1419     return false;
1420   std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1421
1422   return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1423 }
1424
1425 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1426                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint1,
1427                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint2)
1428 {
1429   static const double aTolerance = 1.e-7;
1430   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1431   double aDistP1C = thePoint1->distance(aCenter);
1432   double aDistP2C = thePoint2->distance(aCenter);
1433   return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1434 }
1435
1436 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1437     const FeaturePtr& theMacroFeature,
1438     Events_InfoMessage& theError) const
1439 {
1440   static const std::string aErrorPointsOnLine(
1441       "Selected points are on the same line");
1442
1443   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1444   threePointsOfFeature(theMacroFeature, aPoints);
1445
1446   if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1447     theError = aErrorPointsOnLine;
1448     return false;
1449   }
1450   return true;
1451 }
1452
1453 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1454     const FeaturePtr& theMacroFeature,
1455     const std::list<std::string>& theArguments,
1456     Events_InfoMessage& theError) const
1457 {
1458   static const std::string aErrorPointsApart(
1459       "Selected entity is lying between first two points");
1460
1461   AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1462   FeaturePtr aRefByThird;
1463   if (aThirdPointRef->isObject())
1464     aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1465   if (!aRefByThird)
1466     return true;
1467
1468   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1469   threePointsOfFeature(theMacroFeature, aPoints);
1470
1471   std::shared_ptr<GeomAPI_Edge> aThirdShape =
1472       std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1473   if (!aThirdShape)
1474     return true;
1475
1476   SketchPlugin_Sketch* aSketch =
1477       std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1478   std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1479   std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1480
1481   bool isOk = true;
1482   if (aThirdShape->isLine())
1483     isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1484   else if (aThirdShape->isCircle() || aThirdShape->isArc())
1485     isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1486
1487   if (!isOk)
1488     theError = aErrorPointsApart;
1489   return isOk;
1490 }
1491
1492 bool SketchPlugin_ArcEndPointValidator::isValid(
1493     const AttributePtr& theAttribute,
1494     const std::list<std::string>& theArguments,
1495     Events_InfoMessage& theError) const
1496 {
1497   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1498   AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1499
1500   if(!anEndPointRef.get()) {
1501     return true;
1502   }
1503
1504   ObjectPtr anObject = anEndPointRef->object();
1505   AttributePtr anAttr = anEndPointRef->attr();
1506   if(!anObject.get() && !anAttr.get()) {
1507     return true;
1508   }
1509
1510   if(anEndPointRef->attr().get()) {
1511     return false;
1512   }
1513
1514   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1515   if(aResult.get()) {
1516     GeomShapePtr aShape = aResult->shape();
1517     if(aShape.get() && aShape->isVertex()) {
1518       return false;
1519     }
1520   }
1521
1522   aFeature = ModelAPI_Feature::feature(anObject);
1523   if(aFeature.get()) {
1524     if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1525       return false;
1526     }
1527   }
1528
1529   return true;
1530 }
1531
1532 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1533 {
1534   if(!theShape.get()) {
1535     return theShape;
1536   }
1537
1538   if(!theShape->isEdge()) {
1539     return theShape;
1540   }
1541
1542   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1543
1544   if(!anEdge.get()) {
1545     return theShape;
1546   }
1547
1548   if(anEdge->isLine()) {
1549     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1550     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1551     return aShape;
1552   }
1553
1554   if(anEdge->isCircle() || anEdge->isArc()) {
1555     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1556     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1557     return aShape;
1558   }
1559
1560   return theShape;
1561 }
1562
1563 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1564     const AttributePtr& theAttribute,
1565     const std::list<std::string>& theArguments,
1566     Events_InfoMessage& theError) const
1567 {
1568   std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1569       std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1570   AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1571
1572   if(!anEndPointRef.get()) {
1573     return true;
1574   }
1575
1576   GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1577
1578   if(!anArcShape.get() || anArcShape->isNull()) {
1579     return true;
1580   }
1581
1582   ObjectPtr anObject = anEndPointRef->object();
1583   AttributePtr anAttr = anEndPointRef->attr();
1584   if(!anObject.get() && !anAttr.get()) {
1585     return true;
1586   }
1587
1588   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1589   if(aResult.get()) {
1590     GeomShapePtr aShape = aResult->shape();
1591     if (!aShape->isEdge())
1592       return true;
1593     aShape = toInfiniteEdge(aShape);
1594     if(aShape.get() && !aShape->isNull()) {
1595       if(anArcShape->isIntersect(aShape)) {
1596         return true;
1597       }
1598     }
1599   }
1600
1601   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1602   if(aSelectedFeature.get()) {
1603     std::list<ResultPtr> aResults = aSelectedFeature->results();
1604     for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1605         anIt != aResults.cend();
1606         ++anIt)
1607     {
1608       GeomShapePtr aShape = (*anIt)->shape();
1609       if (!aShape->isEdge())
1610         return true;
1611       aShape = toInfiniteEdge(aShape);
1612       if(aShape.get() && !aShape->isNull()) {
1613         if(anArcShape->isIntersect(aShape)) {
1614           return true;
1615         }
1616       }
1617     }
1618   }
1619
1620   return false;
1621 }
1622
1623 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1624                                            const std::list<std::string>& theArguments,
1625                                            Events_InfoMessage& theError) const
1626 {
1627   std::set<std::string> aFeatureKinds;
1628   for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1629        anArgIt != theArguments.end(); anArgIt++) {
1630     aFeatureKinds.insert(*anArgIt);
1631   }
1632
1633   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1634     theError = "The attribute with the %1 type is not processed";
1635     theError.arg(theAttribute->attributeType());
1636     return false;
1637   }
1638
1639   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1640                                                                       (theAttribute);
1641   bool isObject = aRefAttr->isObject();
1642   if (!isObject) {
1643     theError = "It uses an empty object";
1644     return false;
1645   }
1646   ObjectPtr anObject = aRefAttr->object();
1647   FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1648   if (!aFeature.get()) {
1649     theError = "The feature of the checked attribute is empty";
1650     return false;
1651   }
1652
1653   FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1654
1655   std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1656   std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1657   for (; anIt != aRefsList.end(); anIt++) {
1658     FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1659     if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1660         aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1661       return false; // constraint is found, that means that the check is not valid
1662   }
1663   return true;
1664 }
1665
1666 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1667     const AttributePtr& theAttribute,
1668     const std::list<std::string>& theArguments,
1669     Events_InfoMessage& theError) const
1670 {
1671   AttributeRefAttrPtr aRefAttr =
1672       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1673   if (!aRefAttr)
1674   {
1675     theError = "Incorrect attribute";
1676     return false;
1677   }
1678
1679   ObjectPtr anOwner;
1680   if (aRefAttr->isObject())
1681     anOwner = aRefAttr->object();
1682   else
1683   {
1684     AttributePtr anAttr = aRefAttr->attr();
1685     anOwner = anAttr->owner();
1686   }
1687   FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1688   if (!anAttrOwnerFeature)
1689     return true;
1690   AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1691   if (!aCopyAttr || !aCopyAttr->value())
1692     return true; // feature is not a copy, thus valid
1693
1694   // check the copy feature is already referred by the "Multi" feature
1695   FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1696   AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1697   for (int i = 0; i < aRefList->size(); ++i)
1698   {
1699     FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1700     if (aRefOwner == anAttrOwnerFeature)
1701     {
1702       theError = "Attribute refers to the object generated by this feature";
1703       return false;
1704     }
1705   }
1706
1707   return true;
1708 }
1709
1710 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1711                                                   const std::list<std::string>& theArguments,
1712                                                   Events_InfoMessage& theError) const
1713 {
1714   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1715     theError = "The attribute with the %1 type is not processed";
1716     theError.arg(theAttribute->attributeType());
1717     return false;
1718   }
1719
1720   // check the attribute refers to a sketch feature
1721   AttributeRefAttrPtr aRefAttr =
1722       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1723   bool isSketchFeature = aRefAttr->isObject();
1724   if (isSketchFeature) {
1725     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1726     isSketchFeature = aFeature.get() != NULL;
1727     if (isSketchFeature) {
1728       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1729           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1730       isSketchFeature = aSketchFeature.get() != NULL;
1731     }
1732   }
1733
1734   if (isSketchFeature)
1735     return true;
1736
1737   theError = "The object selected is not a sketch feature";
1738   return false;
1739 }
1740
1741 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1742                                                        const std::list<std::string>& theArguments,
1743                                                        Events_InfoMessage& theError) const
1744 {
1745   if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1746     theError = "The attribute with the %1 type is not processed";
1747     theError.arg(theAttribute->attributeType());
1748     return false;
1749   }
1750
1751   AttributeDoublePtr anAngleAttr =
1752     std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1753
1754   FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1755   AttributeStringPtr anAngleType =
1756       aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1757   AttributeIntegerPtr aNbCopies =
1758       aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1759
1760   if (anAngleType->value() != "FullAngle")
1761   {
1762     double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1763     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1764     {
1765       theError = "Rotation single angle should produce full angle less than 360 degree";
1766       return false;
1767     }
1768   }
1769   else
1770   {
1771     double aFullAngleValue = anAngleAttr->value();
1772     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1773     {
1774       theError = "Rotation full angle should be in range [0, 360]";
1775       return false;
1776     }
1777   }
1778
1779   return true;
1780 }
1781
1782 bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
1783                                             const std::list<std::string>& theArguments,
1784                                             Events_InfoMessage& theError) const
1785 {
1786   AttributePoint2DArrayPtr aPolesArray =
1787       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
1788   if (!aPolesArray)
1789     return false;
1790
1791   if (aPolesArray->size() < 2) {
1792     theError = "Number of B-spline poles should be 2 and more";
1793     return false;
1794   }
1795
1796   return true;
1797 }