Salome HOME
Issue #3123: Provide chain of create Angle constraint operations
[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                aFeature->getKind() == SketchPlugin_EllipticArc::ID())
776         ++aNbLines;
777     }
778   }
779
780   if (aNbPoints != 1 || aNbLines != 1) {
781     theError = "Middle point constraint allows points and lines only";
782     return false;
783   }
784   return true;
785 }
786
787 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
788                                                     const std::list<std::string>& /*theArguments*/,
789                                                     Events_InfoMessage& theError) const
790 {
791   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
792     theError = "The attribute with the %1 type is not processed";
793     theError.arg(theAttribute->attributeType());
794     return false;
795   }
796   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
797   AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
798   if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
799     return true; // not applicable for non-tangent arcs
800
801   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
802   AttributePtr anAttr = aRefAttr->attr();
803   if (!anAttr) {
804     theError = "The attribute %1 should be a point";
805     theError.arg(theAttribute->id());
806     return false;
807   }
808
809   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
810   const std::string& aFeatureType = anAttrFeature->getKind();
811   if (aFeatureType == SketchPlugin_Arc::ID()) {
812     // selected point should not be a center of arc
813     const std::string& aPntId = anAttr->id();
814     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
815       theError = "The attribute %1 is not supported";
816       theError.arg(aPntId);
817       return false;
818     }
819   }
820   else if (aFeatureType == SketchPlugin_Line::ID()) {
821     // selected point should be bound point of line
822     const std::string& aPntId = anAttr->id();
823     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
824       theError = "The attribute %1 is not supported";
825       theError.arg(aPntId);
826       return false;
827     }
828   }
829   else {
830     theError = "Unable to build tangent arc on %1";
831     theError.arg(anAttrFeature->getKind());
832     return false;
833   }
834
835   return true;
836 }
837
838 bool SketchPlugin_ArcTransversalPointValidator::isValid(
839     const AttributePtr& theAttribute,
840     const std::list<std::string>& /*theArguments*/,
841     Events_InfoMessage& theError) const
842 {
843   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
844     theError = "The attribute with the %1 type is not processed";
845     theError.arg(theAttribute->attributeType());
846     return false;
847   }
848   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
849   AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
850   if (anArcTypeAttr &&
851       anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
852     return true; // not applicable for non-transversal arcs
853
854   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
855   AttributePtr anAttr = aRefAttr->attr();
856   if (!anAttr) {
857     theError = "The attribute %1 should be a point";
858     theError.arg(theAttribute->id());
859     return false;
860   }
861
862   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
863   const std::string& aFeatureType = anAttrFeature->getKind();
864   if (aFeatureType == SketchPlugin_Line::ID()) {
865     // selected point should be bound point of line
866     const std::string& aPntId = anAttr->id();
867     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
868       theError = "The attribute %1 is not supported";
869       theError.arg(aPntId);
870       return false;
871     }
872   }
873   else {
874     theError = "Unable to build perpendicular arc on %1";
875     theError.arg(anAttrFeature->getKind());
876     return false;
877   }
878
879   return true;
880 }
881
882 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
883                                                  const std::list<std::string>& theArguments,
884                                                  Events_InfoMessage& theError) const
885 {
886   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
887     theError = "The attribute with the %1 type is not processed";
888     theError.arg(theAttribute->attributeType());
889     return false;
890   }
891   AttributeSelectionPtr anExternalAttr =
892       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
893   std::shared_ptr<GeomAPI_Edge> anEdge;
894   if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
895     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
896   } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
897             anExternalAttr->context()->shape()->isEdge()) {
898     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
899   }
900
901   if (!anEdge) {
902     theError = "The attribute %1 should be an edge";
903     theError.arg(theAttribute->id());
904     return false;
905   }
906
907   // find a sketch
908   std::shared_ptr<SketchPlugin_Sketch> aSketch;
909   std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
910   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
911   for (; anIt != aRefs.end(); ++anIt) {
912     CompositeFeaturePtr aComp =
913         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
914     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
915       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
916       break;
917     }
918   }
919   if (!aSketch) {
920     theError = "There is no sketch referring to the current feature";
921     return false;
922   }
923
924   // check the edge is intersected with sketch plane
925   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
926
927   std::list<GeomPointPtr> anIntersectionsPoints;
928   anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
929   if (anIntersectionsPoints.empty()) {
930     theError = "The edge is not intersected with sketch plane";
931     return false;
932   }
933   return true;
934 }
935
936 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
937                                           const std::list<std::string>& theArguments,
938                                           Events_InfoMessage& theError) const
939 {
940   bool aValid = false;
941
942   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
943     theError = "The attribute with the %1 type is not processed";
944     theError.arg(theAttribute->attributeType());
945     return aValid;
946   }
947   AttributeReferencePtr aFeatureAttr =
948             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
949   std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
950     std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
951
952   ObjectPtr anAttrObject = aFeatureAttr->value();
953   if (!anAttrObject) {
954     AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
955     aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
956     anAttrObject = aFeatureAttr->value();
957   }
958
959   FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
960   if (!anAttrFeature)
961     return aValid;
962
963   std::set<ResultPtr> anEdgeShapes;
964   ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
965   if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
966     return aValid;
967
968   // coincidences to the feature
969   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
970   ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
971                       SketchPlugin_ConstraintCoincidence::ID(),
972                       aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
973
974   GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
975   std::shared_ptr<SketchPlugin_Feature> aSFeature =
976                                 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
977   if (!aSFeature)
978     return false;
979   SketchPlugin_Sketch* aSketch = aSFeature->sketch();
980
981   std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
982   std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
983       aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
984   std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
985       aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
986   std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
987       aData->attribute(SketchPlugin_Sketch::NORM_ID()));
988   std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
989
990   typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
991                     std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
992                               std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
993   PointToRefsMap aPointsInfo;
994
995   ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
996                                               aX->dir(), aDirY, aPointsInfo);
997   int aCoincidentToFeature = (int)aPointsInfo.size();
998   if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() ||
999       anAttrFeature->getKind() == SketchPlugin_Ellipse::ID())
1000     aValid = aCoincidentToFeature >= 2;
1001   else
1002     aValid = aCoincidentToFeature >= 1;
1003
1004   return aValid;
1005 }
1006
1007 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
1008                                          const std::list<std::string>& theArguments,
1009                                          Events_InfoMessage& theError) const
1010 {
1011   bool aValid = false;
1012
1013   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1014     theError = "The attribute with the %1 type is not processed";
1015     theError.arg(theAttribute->attributeType());
1016     return aValid;
1017   }
1018   AttributeReferencePtr aBaseObjectAttr =
1019             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1020
1021   std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
1022                  std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1023
1024   ObjectPtr aBaseObject = aBaseObjectAttr->value();
1025   if (!aBaseObject) {
1026     AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1027     aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1028     aBaseObject = aBaseObjectAttr->value();
1029   }
1030
1031   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1032   if (!aBaseFeature)
1033     return aValid;
1034
1035   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1036                                  std::dynamic_pointer_cast<SketchPlugin_Feature>(aBaseFeature);
1037   if (!aSketchFeature.get() || aSketchFeature->isCopy())
1038     return aValid;
1039
1040   // point on feature
1041   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1042                        aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
1043
1044   SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
1045
1046   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1047   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
1048                                                               anAttributePnt2d->y());
1049
1050   std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
1051   std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
1052            std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1053                      std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
1054   SketchPlugin_SegmentationTools::fillObjectShapes(
1055       aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
1056   const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
1057
1058   return aShapes.size() > 1;
1059 }
1060
1061 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
1062                                                const std::list<std::string>& theArguments,
1063                                                Events_InfoMessage& theError) const
1064 {
1065   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1066     theError = "The attribute with the %1 type is not processed";
1067     theError.arg(theAttribute->attributeType());
1068     return false;
1069   }
1070
1071   AttributeSelectionPtr aFeatureAttr =
1072       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1073   std::shared_ptr<GeomAPI_Edge> anEdge;
1074   std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1075   if (aFeatureAttr.get()) {
1076     GeomShapePtr aVal = aFeatureAttr->value();
1077     ResultPtr aRes = aFeatureAttr->context();
1078     if (aVal && aVal->isVertex())
1079       return true; // vertex is always could be projected
1080     if (aVal && aVal->isEdge()) {
1081       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
1082     } else if(aRes && aRes->shape()) {
1083       if (aRes->shape()->isVertex())
1084         return true; // vertex is always could be projected
1085       else if (aRes->shape()->isEdge())
1086         anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
1087     }
1088
1089     // try to convert result to sketch feature
1090     if (aRes) {
1091       aSketchFeature =
1092         std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1093     }
1094   }
1095   if (!anEdge) {
1096     theError = "The attribute %1 should be an edge or vertex";
1097     theError.arg(theAttribute->id());
1098     return false;
1099   }
1100
1101   // find a sketch
1102   std::shared_ptr<SketchPlugin_Sketch> aSketch;
1103   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1104   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1105   for (; anIt != aRefs.end(); ++anIt) {
1106     CompositeFeaturePtr aComp =
1107         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1108     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1109       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1110       break;
1111     }
1112   }
1113   if (!aSketch) {
1114     theError = "There is no sketch referring to the current feature";
1115     return false;
1116   }
1117   if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1118     theError = "Unable to project feature from the same sketch";
1119     return false;
1120   }
1121
1122   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1123   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1124   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1125
1126   if (anEdge->isLine()) {
1127     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1128     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1129     double aDot = fabs(aNormal->dot(aLineDir));
1130     bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1131     if (!aValid)
1132       theError = "Error: Line is orthogonal to the sketch plane.";
1133     return aValid;
1134   }
1135   else if (anEdge->isCircle() || anEdge->isArc()) {
1136     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1137     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1138     double aDot = fabs(aNormal->dot(aCircNormal));
1139     bool aValid = aDot >= tolerance * tolerance;
1140     if (!aValid)
1141       theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1142                                       : "Error: Arc is orthogonal to the sketch plane.");
1143     return aValid;
1144   }
1145   else if (anEdge->isEllipse()) {
1146     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1147     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1148     double aDot = fabs(aNormal->dot(anEllipseNormal));
1149     bool aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
1150     if (!aValid)
1151       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1152                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1153     return aValid;
1154   }
1155
1156   theError = "Error: Selected object is not supported for projection.";
1157   return false;
1158 }
1159
1160
1161 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1162                                    const std::set<FeaturePtr>& theSet2)
1163 {
1164   std::set<FeaturePtr> aCommon;
1165   if (theSet1.empty() || theSet2.empty())
1166     return aCommon;
1167
1168   std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1169   for (; anIt2 != theSet2.end(); ++anIt2)
1170     if (theSet1.find(*anIt2) != theSet1.end())
1171       aCommon.insert(*anIt2);
1172   return aCommon;
1173 }
1174
1175 bool SketchPlugin_DifferentReferenceValidator::isValid(
1176     const AttributePtr& theAttribute,
1177     const std::list<std::string>& theArguments,
1178     Events_InfoMessage& theError) const
1179 {
1180   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1181
1182   int aNbFeaturesReferred = 0;
1183   int aNbAttributesReferred = 0;
1184   std::set<FeaturePtr> aCommonReferredFeatures;
1185
1186   // find all features referred by attributes listed in theArguments
1187   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1188   for (; anArgIt != theArguments.end(); ++anArgIt) {
1189     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1190     if (!aRefAttr)
1191       continue;
1192
1193     std::set<FeaturePtr> aCoincidentFeatures;
1194     if (aRefAttr->isObject()) {
1195       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1196       if (aFeature) {
1197         aCoincidentFeatures.insert(aFeature);
1198         aNbFeaturesReferred += 1;
1199       }
1200     } else {
1201       AttributePoint2DPtr aPoint =
1202           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1203       if (aPoint) {
1204         aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1205         aNbAttributesReferred += 1;
1206       }
1207     }
1208
1209     if (aCommonReferredFeatures.empty())
1210       aCommonReferredFeatures = aCoincidentFeatures;
1211     else
1212       aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1213
1214     if (aCommonReferredFeatures.empty())
1215       return true;
1216   }
1217
1218   bool isOk = aNbFeaturesReferred < 1;
1219   if (aNbFeaturesReferred == 1) {
1220     if (aCommonReferredFeatures.size() == 1) {
1221       FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1222       isOk = aNbAttributesReferred <= 1 ||
1223              aFeature->getKind() == SketchPlugin_Circle::ID() ||
1224              aFeature->getKind() == SketchPlugin_Arc::ID();
1225     } else
1226       isOk = false;
1227   }
1228
1229   if (!isOk)
1230     theError = "Attributes are referred to the same feature";
1231   return isOk;
1232 }
1233
1234 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1235     const AttributePtr& theAttribute,
1236     const std::list<std::string>& theArguments,
1237     Events_InfoMessage& theError) const
1238 {
1239   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1240   std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1241
1242   // find all points referred by attributes listed in theArguments
1243   bool hasRefsToPoints = false;
1244   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1245   for (; anArgIt != theArguments.end(); ++anArgIt) {
1246     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1247     if (!aRefAttr)
1248       continue;
1249
1250     if (!aRefAttr->isObject()) {
1251       AttributePoint2DPtr aPoint =
1252           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1253       if (aReferredCoincidentPoints.empty())
1254         aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1255       else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1256         return true; // non-coincident point has been found
1257       else
1258         hasRefsToPoints = true;
1259     }
1260   }
1261
1262   if (hasRefsToPoints)
1263     theError = "Attributes are referred to the same point";
1264   return !hasRefsToPoints;
1265 }
1266
1267 bool SketchPlugin_CirclePassedPointValidator::isValid(
1268     const AttributePtr& theAttribute,
1269     const std::list<std::string>&,
1270     Events_InfoMessage& theError) const
1271 {
1272   static const std::string aErrorMessage(
1273       "Passed point refers to the same feature as a center point");
1274
1275   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1276
1277   AttributeRefAttrPtr aCenterRef =
1278       anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1279   AttributeRefAttrPtr aPassedRef =
1280       anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1281
1282   if (!aPassedRef->isObject())
1283     return true;
1284
1285   FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1286   if (!aPassedFeature)
1287     return true;
1288
1289   if (aCenterRef->isObject()) {
1290     if (aCenterRef->object() == aPassedRef->object()) {
1291       theError = aErrorMessage;
1292       return false;
1293     }
1294   } else {
1295     AttributePoint2DPtr aCenterPoint =
1296         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1297     if (aCenterPoint) {
1298       std::set<FeaturePtr> aCoincidentFeatures =
1299           SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1300       // check one of coincident features is a feature referred by passed point
1301       std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1302       for(; anIt != aCoincidentFeatures.end(); ++anIt)
1303         if (*anIt == aPassedFeature) {
1304           theError = aErrorMessage;
1305           return false;
1306         }
1307     }
1308   }
1309   return true;
1310 }
1311
1312 bool SketchPlugin_ThirdPointValidator::isValid(
1313     const AttributePtr& theAttribute,
1314     const std::list<std::string>& theArguments,
1315     Events_InfoMessage& theError) const
1316 {
1317   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1318   return arePointsNotOnLine(anOwner, theError) &&
1319          arePointsNotSeparated(anOwner, theArguments, theError);
1320 }
1321
1322 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1323                                               const std::string& thePointAttrName,
1324                                               const std::string& theRefPointAttrName)
1325 {
1326   AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1327       theMacroCircle->attribute(thePointAttrName));
1328   AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1329
1330   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1331   if (aRefAttr) {
1332     if (aRefAttr->isObject()) {
1333       // project a point onto selected feature
1334       std::shared_ptr<SketchPlugin_Feature> aFeature =
1335           std::dynamic_pointer_cast<SketchPlugin_Feature>(
1336           ModelAPI_Feature::feature(aRefAttr->object()));
1337       if (aFeature) {
1338         SketchPlugin_Sketch* aSketch = aFeature->sketch();
1339         std::shared_ptr<GeomAPI_Edge> anEdge =
1340             std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1341         if (anEdge) {
1342           std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1343           if (anEdge->isLine())
1344             aPoint3D = anEdge->line()->project(aPoint3D);
1345           else if (anEdge->isCircle())
1346             aPoint3D = anEdge->circle()->project(aPoint3D);
1347           if(aPoint3D)
1348             aPoint = aSketch->to2D(aPoint3D);
1349         }
1350       }
1351     } else {
1352       AttributePoint2DPtr anOtherPoint =
1353           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1354       if (anOtherPoint)
1355         aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1356     }
1357   }
1358
1359   return aPoint;
1360 }
1361
1362 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1363                                  std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1364 {
1365   if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1366     thePoints[0] = toPoint(theMacroFeature,
1367           SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1368           SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1369     thePoints[1] = toPoint(theMacroFeature,
1370           SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1371           SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1372     thePoints[2] = toPoint(theMacroFeature,
1373           SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1374           SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1375   } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1376     thePoints[0] = toPoint(theMacroFeature,
1377           SketchPlugin_MacroArc::START_POINT_2_ID(),
1378           SketchPlugin_MacroArc::START_POINT_REF_ID());
1379     thePoints[1] = toPoint(theMacroFeature,
1380           SketchPlugin_MacroArc::END_POINT_2_ID(),
1381           SketchPlugin_MacroArc::END_POINT_REF_ID());
1382     thePoints[2] = toPoint(theMacroFeature,
1383           SketchPlugin_MacroArc::PASSED_POINT_ID(),
1384           SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1385   }
1386 }
1387
1388 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1389                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1390                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1391 {
1392   static const double aTolerance = 1.e-7;
1393   if (thePoint1->distance(thePoint2) < aTolerance ||
1394       thePoint1->distance(thePoint3) < aTolerance)
1395     return true;
1396
1397   std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1398                                                             thePoint2->y() - thePoint1->y()));
1399   std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1400                                                             thePoint3->y() - thePoint1->y()));
1401   return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1402 }
1403
1404 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1405                          const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1406                          const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1407 {
1408   static const double aTolerance = 1.e-7;
1409   std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1410   std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1411
1412   std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1413   // the first point is on the line
1414   if (aVec1->squareModulus() < aTolerance * aTolerance)
1415     return false;
1416   std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1417   std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1418   // the second point is on the line
1419   if (aVec2->squareModulus() < aTolerance * aTolerance)
1420     return false;
1421   std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1422
1423   return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1424 }
1425
1426 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1427                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint1,
1428                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint2)
1429 {
1430   static const double aTolerance = 1.e-7;
1431   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1432   double aDistP1C = thePoint1->distance(aCenter);
1433   double aDistP2C = thePoint2->distance(aCenter);
1434   return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1435 }
1436
1437 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1438     const FeaturePtr& theMacroFeature,
1439     Events_InfoMessage& theError) const
1440 {
1441   static const std::string aErrorPointsOnLine(
1442       "Selected points are on the same line");
1443
1444   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1445   threePointsOfFeature(theMacroFeature, aPoints);
1446
1447   if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1448     theError = aErrorPointsOnLine;
1449     return false;
1450   }
1451   return true;
1452 }
1453
1454 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1455     const FeaturePtr& theMacroFeature,
1456     const std::list<std::string>& theArguments,
1457     Events_InfoMessage& theError) const
1458 {
1459   static const std::string aErrorPointsApart(
1460       "Selected entity is lying between first two points");
1461
1462   AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1463   FeaturePtr aRefByThird;
1464   if (aThirdPointRef->isObject())
1465     aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1466   if (!aRefByThird)
1467     return true;
1468
1469   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1470   threePointsOfFeature(theMacroFeature, aPoints);
1471
1472   std::shared_ptr<GeomAPI_Edge> aThirdShape =
1473       std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1474   if (!aThirdShape)
1475     return true;
1476
1477   SketchPlugin_Sketch* aSketch =
1478       std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1479   std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1480   std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1481
1482   bool isOk = true;
1483   if (aThirdShape->isLine())
1484     isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1485   else if (aThirdShape->isCircle() || aThirdShape->isArc())
1486     isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1487
1488   if (!isOk)
1489     theError = aErrorPointsApart;
1490   return isOk;
1491 }
1492
1493 bool SketchPlugin_ArcEndPointValidator::isValid(
1494     const AttributePtr& theAttribute,
1495     const std::list<std::string>& theArguments,
1496     Events_InfoMessage& theError) const
1497 {
1498   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1499   AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1500
1501   if(!anEndPointRef.get()) {
1502     return true;
1503   }
1504
1505   ObjectPtr anObject = anEndPointRef->object();
1506   AttributePtr anAttr = anEndPointRef->attr();
1507   if(!anObject.get() && !anAttr.get()) {
1508     return true;
1509   }
1510
1511   if(anEndPointRef->attr().get()) {
1512     return false;
1513   }
1514
1515   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1516   if(aResult.get()) {
1517     GeomShapePtr aShape = aResult->shape();
1518     if(aShape.get() && aShape->isVertex()) {
1519       return false;
1520     }
1521   }
1522
1523   aFeature = ModelAPI_Feature::feature(anObject);
1524   if(aFeature.get()) {
1525     if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1526       return false;
1527     }
1528   }
1529
1530   return true;
1531 }
1532
1533 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1534 {
1535   if(!theShape.get()) {
1536     return theShape;
1537   }
1538
1539   if(!theShape->isEdge()) {
1540     return theShape;
1541   }
1542
1543   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1544
1545   if(!anEdge.get()) {
1546     return theShape;
1547   }
1548
1549   if(anEdge->isLine()) {
1550     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1551     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1552     return aShape;
1553   }
1554
1555   if(anEdge->isCircle() || anEdge->isArc()) {
1556     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1557     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1558     return aShape;
1559   }
1560
1561   return theShape;
1562 }
1563
1564 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1565     const AttributePtr& theAttribute,
1566     const std::list<std::string>& theArguments,
1567     Events_InfoMessage& theError) const
1568 {
1569   std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1570       std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1571   AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1572
1573   if(!anEndPointRef.get()) {
1574     return true;
1575   }
1576
1577   GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1578
1579   if(!anArcShape.get() || anArcShape->isNull()) {
1580     return true;
1581   }
1582
1583   ObjectPtr anObject = anEndPointRef->object();
1584   AttributePtr anAttr = anEndPointRef->attr();
1585   if(!anObject.get() && !anAttr.get()) {
1586     return true;
1587   }
1588
1589   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1590   if(aResult.get()) {
1591     GeomShapePtr aShape = aResult->shape();
1592     if (!aShape->isEdge())
1593       return true;
1594     aShape = toInfiniteEdge(aShape);
1595     if(aShape.get() && !aShape->isNull()) {
1596       if(anArcShape->isIntersect(aShape)) {
1597         return true;
1598       }
1599     }
1600   }
1601
1602   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1603   if(aSelectedFeature.get()) {
1604     std::list<ResultPtr> aResults = aSelectedFeature->results();
1605     for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1606         anIt != aResults.cend();
1607         ++anIt)
1608     {
1609       GeomShapePtr aShape = (*anIt)->shape();
1610       if (!aShape->isEdge())
1611         return true;
1612       aShape = toInfiniteEdge(aShape);
1613       if(aShape.get() && !aShape->isNull()) {
1614         if(anArcShape->isIntersect(aShape)) {
1615           return true;
1616         }
1617       }
1618     }
1619   }
1620
1621   return false;
1622 }
1623
1624 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1625                                            const std::list<std::string>& theArguments,
1626                                            Events_InfoMessage& theError) const
1627 {
1628   std::set<std::string> aFeatureKinds;
1629   for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1630        anArgIt != theArguments.end(); anArgIt++) {
1631     aFeatureKinds.insert(*anArgIt);
1632   }
1633
1634   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1635     theError = "The attribute with the %1 type is not processed";
1636     theError.arg(theAttribute->attributeType());
1637     return false;
1638   }
1639
1640   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1641                                                                       (theAttribute);
1642   bool isObject = aRefAttr->isObject();
1643   if (!isObject) {
1644     theError = "It uses an empty object";
1645     return false;
1646   }
1647   ObjectPtr anObject = aRefAttr->object();
1648   FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1649   if (!aFeature.get()) {
1650     theError = "The feature of the checked attribute is empty";
1651     return false;
1652   }
1653
1654   FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1655
1656   std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1657   std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1658   for (; anIt != aRefsList.end(); anIt++) {
1659     FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1660     if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1661         aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1662       return false; // constraint is found, that means that the check is not valid
1663   }
1664   return true;
1665 }
1666
1667 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1668     const AttributePtr& theAttribute,
1669     const std::list<std::string>& theArguments,
1670     Events_InfoMessage& theError) const
1671 {
1672   AttributeRefAttrPtr aRefAttr =
1673       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1674   if (!aRefAttr)
1675   {
1676     theError = "Incorrect attribute";
1677     return false;
1678   }
1679
1680   ObjectPtr anOwner;
1681   if (aRefAttr->isObject())
1682     anOwner = aRefAttr->object();
1683   else
1684   {
1685     AttributePtr anAttr = aRefAttr->attr();
1686     anOwner = anAttr->owner();
1687   }
1688   FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1689   if (!anAttrOwnerFeature)
1690     return true;
1691   AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1692   if (!aCopyAttr || !aCopyAttr->value())
1693     return true; // feature is not a copy, thus valid
1694
1695   // check the copy feature is already referred by the "Multi" feature
1696   FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1697   AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1698   for (int i = 0; i < aRefList->size(); ++i)
1699   {
1700     FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1701     if (aRefOwner == anAttrOwnerFeature)
1702     {
1703       theError = "Attribute refers to the object generated by this feature";
1704       return false;
1705     }
1706   }
1707
1708   return true;
1709 }
1710
1711 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1712                                                   const std::list<std::string>& theArguments,
1713                                                   Events_InfoMessage& theError) const
1714 {
1715   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1716     theError = "The attribute with the %1 type is not processed";
1717     theError.arg(theAttribute->attributeType());
1718     return false;
1719   }
1720
1721   // check the attribute refers to a sketch feature
1722   AttributeRefAttrPtr aRefAttr =
1723       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1724   bool isSketchFeature = aRefAttr->isObject();
1725   if (isSketchFeature) {
1726     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1727     isSketchFeature = aFeature.get() != NULL;
1728     if (isSketchFeature) {
1729       std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1730           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1731       isSketchFeature = aSketchFeature.get() != NULL;
1732     }
1733   }
1734
1735   if (isSketchFeature)
1736     return true;
1737
1738   theError = "The object selected is not a sketch feature";
1739   return false;
1740 }
1741
1742 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1743                                                        const std::list<std::string>& theArguments,
1744                                                        Events_InfoMessage& theError) const
1745 {
1746   if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1747     theError = "The attribute with the %1 type is not processed";
1748     theError.arg(theAttribute->attributeType());
1749     return false;
1750   }
1751
1752   AttributeDoublePtr anAngleAttr =
1753     std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1754
1755   FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1756   AttributeStringPtr anAngleType =
1757       aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1758   AttributeIntegerPtr aNbCopies =
1759       aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1760
1761   if (anAngleType->value() != "FullAngle")
1762   {
1763     double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1764     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1765     {
1766       theError = "Rotation single angle should produce full angle less than 360 degree";
1767       return false;
1768     }
1769   }
1770   else
1771   {
1772     double aFullAngleValue = anAngleAttr->value();
1773     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1774     {
1775       theError = "Rotation full angle should be in range [0, 360]";
1776       return false;
1777     }
1778   }
1779
1780   return true;
1781 }