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