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