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