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