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