Salome HOME
Task #3235: Projection without link to source shape
[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_Circ.h>
69 #include <GeomAPI_Dir2d.h>
70 #include <GeomAPI_Ellipse.h>
71 #include <GeomAPI_Lin.h>
72 #include <GeomAPI_Edge.h>
73 #include <GeomAPI_Vertex.h>
74
75 #include <GeomDataAPI_Point2D.h>
76 #include <GeomDataAPI_Point2DArray.h>
77
78 #include <algorithm>
79 #include <cmath>
80
81 #ifdef _MSC_VER
82 #pragma warning(disable: 4100)
83 #endif
84
85 const double tolerance = 1.e-7;
86
87 static bool isSpline(FeaturePtr theFeature)
88 {
89   return theFeature && (theFeature->getKind() == SketchPlugin_BSpline::ID() ||
90                         theFeature->getKind() == SketchPlugin_BSplinePeriodic::ID());
91 }
92
93
94 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
95                                                  const std::list<std::string>& theArguments,
96                                                  Events_InfoMessage& theError) const
97 {
98   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
99     theError = "The attribute with the %1 type is not processed";
100     theError.arg(theAttribute->attributeType());
101     return false;
102   }
103
104   // there is a check whether the feature contains a point and a linear edge or two point values
105   std::string aParamA = theArguments.front();
106   SessionPtr aMgr = ModelAPI_Session::get();
107   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
108
109   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
110                                                                       (theAttribute);
111   bool isObject = aRefAttr->isObject();
112   if (!isObject) {
113     // an attribute is a point. A point value is valid always for the distance
114     return true;
115   } else {
116     // 1. check whether the references object is a linear
117     ObjectPtr anObject = aRefAttr->object();
118
119     const ModelAPI_AttributeValidator* aShapeValidator =
120       dynamic_cast<const ModelAPI_AttributeValidator*>(
121       aFactory->validator("GeomValidators_ShapeType"));
122     std::list<std::string> anArguments;
123     anArguments.push_back("circle");
124     Events_InfoMessage aCircleError;
125     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
126     // the circle line is not a valid case
127     if (aShapeValid) {
128       theError = "Circle can not be used in distance constraint";
129       return false;
130     }
131
132     anArguments.clear();
133     anArguments.push_back("line");
134     Events_InfoMessage aLineError;
135     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
136     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
137     if (aShapeValid) {
138       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
139       // If it is a line then we have to check that first attribute id not a line
140       std::shared_ptr<SketchPlugin_Feature> aSFeature =
141         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
142       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
143       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
144       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
145         aFeature->data(), aParamA, aPlane);
146       if (!aPoint.get()) {
147         theError = "One of parameters of distance constraint should be a point";
148         return false;
149       }
150     }
151   }
152   return true;
153 }
154
155 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
156                                                 const std::list<std::string>& theArguments,
157                                                 Events_InfoMessage& theError) const
158 {
159   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
160     theError = "The attribute with the %1 type is not processed";
161     theError.arg(theAttribute->attributeType());
162     return false;
163   }
164
165   // there is a check whether the feature contains a point and a linear edge or two point values
166   std::string aParamA = theArguments.front();
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
264   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
265   AttributeRefAttrPtr aRefAttr =
266       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
267
268   bool isObject = aRefAttr->isObject();
269   ObjectPtr anObject = aRefAttr->object();
270   if (isObject && anObject.get()) {
271     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
272
273     AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
274     ObjectPtr aOtherObject = aOtherAttr->object();
275     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
276
277     // at least one feature should be a line
278     if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
279         aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) {
280       theError = "At least one feature should be a line";
281       return false;
282     }
283     else if (isSpline(aRefFea) || isSpline(aOtherFea)) {
284       theError = "B-spline is not supported";
285       return false;
286     }
287   }
288   else {
289     theError = "It uses an empty object";
290     return false;
291   }
292
293   return true;
294 }
295
296 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
297                                              const std::list<std::string>& theArguments,
298                                              Events_InfoMessage& theError) const
299 {
300   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
301     theError = "The attribute with the %1 type is not processed";
302     theError.arg(theAttribute->attributeType());
303     return false;
304   }
305
306   std::shared_ptr<SketchPlugin_Feature> aFeature =
307       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
308   if (!aFeature)
309     return true;
310
311   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
312
313   SketchPlugin_Sketch* aSketch = aFeature->sketch();
314   int aNbFeatures = aSketch->numberOfSubs();
315   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
316     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
317     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
318       continue;
319     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
320         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
321     if (aRefAttr->isObject()) {
322       if (aRefAttr->object() == aRAttr->object()) {
323         ObjectPtr anObject = aRefAttr->object();
324         std::string aName = anObject.get() ? anObject->data()->name() : "";
325         theError = "The object %1 has been already fixed.";
326         theError.arg(aName);
327         return false;
328       }
329     }
330     else if (aRefAttr->attr() == aRAttr->attr()) {
331       AttributePtr anAttribute = aRefAttr->attr();
332       std::string aName = anAttribute.get() ? anAttribute->id() : "";
333       theError = "The attribute %1 has been already fixed.";
334       theError.arg(aName);
335       return false;
336     }
337   }
338   return true;
339 }
340
341 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
342                                               const std::list<std::string>& theArguments,
343                                               Events_InfoMessage& theError) const
344 {
345   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
346     theError = "The attribute with the %1 type is not processed";
347     theError.arg(theAttribute->attributeType());
348     return false;
349   }
350
351   std::string aParamA = theArguments.front();
352   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
353   AttributeRefAttrPtr aRefAttr[2];
354   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
355   aRefAttr[1] = aFeature->data()->refattr(aParamA);
356
357   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
358     theError = "Attributes can not be used in equal constraint";
359     return false;
360   }
361
362   std::string aType[2];
363   std::list<std::string> anArguments;
364   for (int i = 0; i < 2; i++) {
365     aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
366     if (!aFeature.get())
367       return true;
368
369     aType[i] = aFeature->getKind();
370     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
371         aFeature->getKind() != SketchPlugin_Circle::ID() &&
372         aFeature->getKind() != SketchPlugin_Arc::ID() &&
373         aFeature->getKind() != SketchPlugin_Ellipse::ID() &&
374         aFeature->getKind() != SketchPlugin_EllipticArc::ID()) {
375       theError = "The %1 feature is not supported by the Equal constraint.";
376       theError.arg(aFeature->getKind());
377       // wrong type of attribute
378       return false;
379     }
380   }
381
382   bool isOk = aType[0] == aType[1];
383   if (!isOk) {
384     // circle and arc may be equal
385     isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
386         || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
387   }
388   if (!isOk) {
389     // ellipse and elliptic arc may be equal
390     isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID())
391         || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID());
392   }
393   if (!isOk) {
394     theError = "Features with kinds %1 and %2 can not be equal.";
395     theError.arg(aType[0]).arg(aType[1]);
396     return false;
397   }
398   return true;
399 }
400
401 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
402                                                const std::list<std::string>& theArguments,
403                                                Events_InfoMessage& theError) const
404 {
405   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
406     theError = "The attribute with the %1 type is not processed";
407     theError.arg(theAttribute->attributeType());
408     return false;
409   }
410
411   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
412   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
413
414   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
415       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
416   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
417
418   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
419     ObjectPtr aSelObject = aSelAttr->object(anInd);
420
421     // B-splines are not supported in Mirror yet
422     FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
423     if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
424         aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
425       theError = "Not supported";
426       return false;
427     }
428
429     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
430     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
431     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
432       if (aSelObject == *aMirIter) {
433         theError = "The object %1 is a result of mirror";
434         theError.arg(aName);
435         return false;
436       }
437   }
438   return true;
439 }
440
441 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
442                                                     const std::list<std::string>& theArguments,
443                                                     Events_InfoMessage& theError) const
444 {
445   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
446     theError = "The attribute with the %1 type is not processed";
447     theError.arg(theAttribute->attributeType());
448     return false;
449   }
450
451   // there is a check whether the feature contains a point and a linear edge or two point values
452   std::string aParamA = theArguments.front();
453
454   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
455   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
456   if (!aRefAttrA) {
457     theError = "The %1 attribute should be %2";
458     theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
459     return false;
460   }
461
462   AttributeRefAttrPtr aRefAttrB =
463     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
464
465   // first attribute is a point, it may coincide with any object
466   if (!aRefAttrA->isObject())
467     return true;
468   else {
469     ObjectPtr anObject = aRefAttrA->object();
470     if (!anObject.get()) {
471       theError = "%1 attribute has an empty object";
472       theError.arg(aParamA);
473       return false;
474     }
475     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
476     if (!aFeature.get()) {
477       theError = "%1 attribute has an empty feature";
478       theError.arg(aParamA);
479       return false;
480     }
481
482     if (aFeature->getKind() == SketchPlugin_Point::ID())
483       return true;
484   }
485
486   // second attribute is a point, it may coincide with any object
487   if (!aRefAttrB->isObject())
488     return true;
489   else {
490     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
491     if (!aFeature) {
492       theError = "%1 attribute has an empty object";
493       theError.arg(theAttribute->id());
494       return false;
495     }
496     if (aFeature->getKind() == SketchPlugin_Point::ID())
497       return true;
498   }
499   theError = "There is no an attribute filled by a point";
500   return false;
501 }
502
503
504 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
505                                          const std::list<std::string>& theArguments,
506                                          Events_InfoMessage& theError) const
507 {
508   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
509     theError = "The attribute with the %1 type is not processed";
510     theError.arg(theAttribute->attributeType());
511     return false;
512   }
513
514   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
515   AttributeRefListPtr aSelAttr =
516     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
517   std::set<ObjectPtr> aSelected;
518
519   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
520       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
521   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
522       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
523   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
524   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
525
526   std::list<ObjectPtr>::iterator anObjIter;
527   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
528     ObjectPtr aSelObject = aSelAttr->object(anInd);
529     if (aSelected.find(aSelObject) != aSelected.end()) {
530       theError = "Error: An object selected twice";
531       return false;
532     }
533     aSelected.insert(aSelObject);
534
535     anObjIter = anInitialObjects.begin();
536     for (; anObjIter != anInitialObjects.end(); anObjIter++)
537       if (aSelObject == *anObjIter)
538         break;
539     if (anObjIter != anInitialObjects.end())
540       continue;
541
542     // B-splines are not supported in Copying features
543     FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
544     if (aFeature->getKind() != SketchPlugin_Offset::ID() &&
545         aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
546         aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
547       theError = "Not supported";
548       return false;
549     }
550
551     anObjIter = aCopiedObjects.begin();
552     for (; anObjIter != aCopiedObjects.end(); anObjIter++) {
553       bool isFound = aSelObject == *anObjIter;
554       if (!isFound) {
555         // check in the results of the feature
556         FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
557         if (aFeature) {
558           const std::list<ResultPtr>& aResults = aFeature->results();
559           for (std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
560             aResIt != aResults.end() && !isFound; ++aResIt) {
561             isFound = aSelObject == *aResIt;
562           }
563         }
564       }
565       if (isFound) {
566         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
567         theError = "The object %1 is a result of copy";
568         theError.arg(aName);
569         return false;
570       }
571     }
572   }
573   return true;
574 }
575
576 bool SketchPlugin_SolverErrorValidator::isValid(
577   const std::shared_ptr<ModelAPI_Feature>& theFeature,
578   const std::list<std::string>& theArguments,
579   Events_InfoMessage& theError) const
580 {
581   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
582
583   if (!aAttributeString->value().empty()) {
584     theError = aAttributeString->value();
585     return false;
586   }
587
588   return true;
589 }
590
591 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
592                                                         std::string theAttribute)
593 {
594   return true;
595 }
596
597 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
598                                   const FeaturePtr theFeature)
599 {
600   for(std::set<AttributePtr>::const_iterator
601       anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
602     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
603     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
604     if (!aFeature)
605       continue;
606     if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
607       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
608         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
609       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
610         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
611       if(anAttrRefA.get()) {
612         ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
613         if(aResA.get()) {
614           DocumentPtr aDoc = aResA->document();
615           if(aDoc.get()) {
616             FeaturePtr aFeatureA = aDoc->feature(aResA);
617             if(aFeatureA.get() && aFeatureA == theFeature) {
618               return true;
619             }
620           }
621         }
622       }
623       if(anAttrRefB.get()) {
624         ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
625         if(aResB.get()) {
626           DocumentPtr aDoc = aResB->document();
627           if(aDoc.get()) {
628             FeaturePtr aFeatureB = aDoc->feature(aResB);
629             if(aFeatureB.get() && aFeatureB == theFeature) {
630               return true;
631             }
632           }
633         }
634       }
635     }
636   }
637   return false;
638 }
639
640 static bool isPointPointCoincidence(const FeaturePtr& theCoincidence)
641 {
642   AttributeRefAttrPtr aRefAttr[2] = {
643       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()),
644       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B())
645   };
646
647   bool arePoints = true;
648   for (int i = 0; i < 2 && arePoints; ++i) {
649     if (aRefAttr[i]->isObject()) {
650       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
651       arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID();
652     } else
653       arePoints = aRefAttr[i]->attr().get() != NULL;
654   }
655   return arePoints;
656 }
657
658 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
659                                                  const std::list<std::string>& theArguments,
660                                                  Events_InfoMessage& theError) const
661 {
662   AttributeRefAttrPtr aPointRefAttr =
663     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
664   if(!aPointRefAttr.get()) {
665     theError = "Error: Point not selected.";
666     return false;
667   }
668
669   AttributePtr aPointAttribute = aPointRefAttr->attr();
670   if (!aPointAttribute.get()) {
671     theError = "Error: Bad point selected.";
672     return false;
673   }
674   std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
675     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
676
677   // Obtain constraint coincidence for the fillet point.
678   const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
679   FeaturePtr aConstraintCoincidence;
680   for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
681       anIt != aRefsList.cend(); ++anIt) {
682     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
683     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
684     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
685       if (!isPointPointCoincidence(aConstrFeature))
686         continue;
687
688       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
689         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
690       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
691         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
692
693       AttributePtr anAttrA = anAttrRefA->attr();
694       if(aPointAttribute == anAttrA) {
695         aConstraintCoincidence = aConstrFeature;
696         break;
697       }
698
699       AttributePtr anAttrB = anAttrRefB->attr();
700       if(aPointAttribute == anAttrB) {
701         aConstraintCoincidence = aConstrFeature;
702         break;
703       }
704     }
705   }
706
707   if(!aConstraintCoincidence.get()) {
708     theError = "Error: one of the selected point does not have coincidence.";
709     return false;
710   }
711
712   // Get coincides from constraint.
713   std::set<FeaturePtr> aCoinsides;
714   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
715                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
716                                         aCoinsides,
717                                         true);
718   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
719                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
720                                         aCoinsides,
721                                         true);
722
723   // Remove points and external lines from set of coincides.
724   std::set<FeaturePtr> aNewSetOfCoincides;
725   for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
726       anIt != aCoinsides.end(); ++anIt) {
727     std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
728       std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
729     if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
730       continue;
731     }
732     if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
733         (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
734           continue;
735     }
736     if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
737       AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
738       std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
739         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
740       double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
741       if(aDistSelectedArcCenter < tolerance) {
742         continue;
743       }
744     }
745     aNewSetOfCoincides.insert(*anIt);
746   }
747   aCoinsides = aNewSetOfCoincides;
748
749   // If we still have more than two coincides remove auxilary entities from set of coincides.
750   if(aCoinsides.size() > 2) {
751     aNewSetOfCoincides.clear();
752     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
753         anIt != aCoinsides.end(); ++anIt) {
754       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
755         aNewSetOfCoincides.insert(*anIt);
756       }
757     }
758     aCoinsides = aNewSetOfCoincides;
759   }
760
761   if(aCoinsides.size() != 2) {
762     theError = "Error: One of the selected points does not have two suitable edges for fillet.";
763     return false;
764   }
765
766   // Check that selected edges don't have tangent constraint.
767   std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
768   FeaturePtr aFirstFeature = *anIt++;
769   FeaturePtr aSecondFeature = *anIt;
770   const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
771   if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
772     theError = "Error: Edges in selected point has tangent constraint.";
773     return false;
774   }
775
776   std::list<ResultPtr> aFirstResults = aFirstFeature->results();
777   for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
778       aResIt != aFirstResults.end(); ++aResIt) {
779     ResultPtr aRes = *aResIt;
780     const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
781     if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
782       theError = "Error: Edges in selected point has tangent constraint.";
783       return false;
784     }
785   }
786
787   // Check the features are not tangent
788   std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
789   std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
790   if (!aFirstShape || !aFirstShape->isEdge() ||
791       !aSecondShape || !aSecondShape->isEdge()) {
792     theError = "Error: At least on of the features is not an edge";
793     return false;
794   }
795
796   std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
797   std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
798
799   static const double TOL = 1.e-7;
800   if (anEdge1->isLine() && anEdge2->isLine()) {
801     // Check that lines not collinear
802     std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
803     std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
804     double aCross = aDir1->cross(aDir2)->squareModulus();
805     if (aCross < TOL * TOL)
806       return false;
807   } else if (anEdge1->isArc() && anEdge2->isArc()) {
808     // check the circles are not tangent
809     std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
810     std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
811     double aDistCC = aCirc1->center()->distance(aCirc2->center());
812     double aRadSum = aCirc1->radius() + aCirc2->radius();
813     double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
814     if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
815       return false;
816   } else {
817     // check whether line and arc are tangent
818     std::shared_ptr<GeomAPI_Circ> aCirc;
819     std::shared_ptr<GeomAPI_Lin> aLine;
820     if (anEdge1->isLine()) {
821       aLine = anEdge1->line();
822       aCirc = anEdge2->circle();
823     } else {
824       aCirc = anEdge1->circle();
825       aLine = anEdge2->line();
826     }
827
828     double aDistCL = aLine->distance(aCirc->center());
829     if (fabs(aDistCL - aCirc->radius()) < TOL)
830       return false;
831   }
832
833   return true;
834 }
835
836 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
837                                                     const std::list<std::string>& theArguments,
838                                                     Events_InfoMessage& theError) const
839 {
840   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
841     theError = "The attribute with the %1 type is not processed";
842     theError.arg(theAttribute->attributeType());
843     return false;
844   }
845
846   // there is a check whether the feature contains a point and a linear edge or two point values
847   std::string aParamA = theArguments.front();
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_Vertex> aVertex;
1185   std::shared_ptr<GeomAPI_Edge> anEdge;
1186   std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1187   if (aFeatureAttr.get()) {
1188     GeomShapePtr aVal = aFeatureAttr->value();
1189     ResultPtr aRes = aFeatureAttr->context();
1190     if (aVal && aVal->isVertex())
1191       aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aVal));
1192     else if (aVal && aVal->isEdge()) {
1193       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aVal));
1194     } else if(aRes && aRes->shape()) {
1195       if (aRes->shape()->isVertex())
1196         aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aRes->shape()));
1197       else if (aRes->shape()->isEdge())
1198         anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aRes->shape()));
1199     }
1200
1201     // try to convert result to sketch feature
1202     if (aRes) {
1203       aSketchFeature =
1204         std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1205     }
1206   }
1207   if (!aVertex && !anEdge) {
1208     theError = "The attribute %1 should be an edge or vertex";
1209     theError.arg(theAttribute->id());
1210     return false;
1211   }
1212
1213   // find a sketch
1214   std::shared_ptr<SketchPlugin_Sketch> aSketch;
1215   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1216   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1217   for (; anIt != aRefs.end(); ++anIt) {
1218     CompositeFeaturePtr aComp =
1219         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1220     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1221       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1222       break;
1223     }
1224   }
1225   if (!aSketch) {
1226     theError = "There is no sketch referring to the current feature";
1227     return false;
1228   }
1229   if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1230     theError = "Unable to project feature from the same sketch";
1231     return false;
1232   }
1233
1234   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1235   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1236   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1237
1238   bool aValid = true;
1239   if (aVertex)
1240     aValid = true; // vertex is always could be projected
1241   else if (anEdge->isLine()) {
1242     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1243     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1244     double aDot = fabs(aNormal->dot(aLineDir));
1245     aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1246     if (!aValid)
1247       theError = "Error: Line is orthogonal to the sketch plane.";
1248   }
1249   else if (anEdge->isCircle() || anEdge->isArc()) {
1250     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1251     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1252     double aDot = fabs(aNormal->dot(aCircNormal));
1253     aValid = aDot >= tolerance * tolerance;
1254     if (!aValid)
1255       theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1256                                       : "Error: Arc is orthogonal to the sketch plane.");
1257   }
1258   else if (anEdge->isEllipse()) {
1259     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1260     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1261     double aDot = fabs(aNormal->dot(anEllipseNormal));
1262     aValid = aDot >= tolerance * tolerance;
1263     if (!aValid)
1264       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1265                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1266   }
1267
1268   return aValid;
1269 }
1270
1271
1272 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1273                                    const std::set<FeaturePtr>& theSet2)
1274 {
1275   std::set<FeaturePtr> aCommon;
1276   if (theSet1.empty() || theSet2.empty())
1277     return aCommon;
1278
1279   std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1280   for (; anIt2 != theSet2.end(); ++anIt2)
1281     if (theSet1.find(*anIt2) != theSet1.end())
1282       aCommon.insert(*anIt2);
1283   return aCommon;
1284 }
1285
1286 bool SketchPlugin_DifferentReferenceValidator::isValid(
1287     const AttributePtr& theAttribute,
1288     const std::list<std::string>& theArguments,
1289     Events_InfoMessage& theError) const
1290 {
1291   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1292
1293   int aNbFeaturesReferred = 0;
1294   int aNbAttributesReferred = 0;
1295   std::set<FeaturePtr> aCommonReferredFeatures;
1296
1297   // find all features referred by attributes listed in theArguments
1298   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1299   for (; anArgIt != theArguments.end(); ++anArgIt) {
1300     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1301     if (!aRefAttr)
1302       continue;
1303
1304     std::set<FeaturePtr> aCoincidentFeatures;
1305     if (aRefAttr->isObject()) {
1306       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1307       if (aFeature) {
1308         aCoincidentFeatures.insert(aFeature);
1309         aNbFeaturesReferred += 1;
1310       }
1311     } else {
1312       AttributePoint2DPtr aPoint =
1313           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1314       if (aPoint) {
1315         aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1316         aNbAttributesReferred += 1;
1317       }
1318     }
1319
1320     if (aCommonReferredFeatures.empty())
1321       aCommonReferredFeatures = aCoincidentFeatures;
1322     else
1323       aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1324
1325     if (aCommonReferredFeatures.empty())
1326       return true;
1327   }
1328
1329   bool isOk = aNbFeaturesReferred < 1;
1330   if (aNbFeaturesReferred == 1) {
1331     if (aCommonReferredFeatures.size() == 1) {
1332       FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1333       isOk = aNbAttributesReferred <= 1 ||
1334              aFeature->getKind() == SketchPlugin_Circle::ID() ||
1335              aFeature->getKind() == SketchPlugin_Arc::ID();
1336     } else
1337       isOk = false;
1338   }
1339
1340   if (!isOk)
1341     theError = "Attributes are referred to the same feature";
1342   return isOk;
1343 }
1344
1345 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1346     const AttributePtr& theAttribute,
1347     const std::list<std::string>& theArguments,
1348     Events_InfoMessage& theError) const
1349 {
1350   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1351   std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1352
1353   // find all points referred by attributes listed in theArguments
1354   bool hasRefsToPoints = false;
1355   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1356   for (; anArgIt != theArguments.end(); ++anArgIt) {
1357     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1358     if (!aRefAttr)
1359       continue;
1360
1361     if (!aRefAttr->isObject()) {
1362       AttributePoint2DPtr aPoint =
1363           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1364       if (aReferredCoincidentPoints.empty())
1365         aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1366       else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1367         return true; // non-coincident point has been found
1368       else
1369         hasRefsToPoints = true;
1370     }
1371   }
1372
1373   if (hasRefsToPoints)
1374     theError = "Attributes are referred to the same point";
1375   return !hasRefsToPoints;
1376 }
1377
1378 bool SketchPlugin_CirclePassedPointValidator::isValid(
1379     const AttributePtr& theAttribute,
1380     const std::list<std::string>&,
1381     Events_InfoMessage& theError) const
1382 {
1383   static const std::string aErrorMessage(
1384       "Passed point refers to the same feature as a center point");
1385
1386   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1387
1388   AttributeRefAttrPtr aCenterRef =
1389       anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1390   AttributeRefAttrPtr aPassedRef =
1391       anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1392
1393   if (!aPassedRef->isObject())
1394     return true;
1395
1396   FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1397   if (!aPassedFeature)
1398     return true;
1399
1400   if (aCenterRef->isObject()) {
1401     if (aCenterRef->object() == aPassedRef->object()) {
1402       theError = aErrorMessage;
1403       return false;
1404     }
1405   } else {
1406     AttributePoint2DPtr aCenterPoint =
1407         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1408     if (aCenterPoint) {
1409       std::set<FeaturePtr> aCoincidentFeatures =
1410           SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1411       // check one of coincident features is a feature referred by passed point
1412       std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1413       for(; anIt != aCoincidentFeatures.end(); ++anIt)
1414         if (*anIt == aPassedFeature) {
1415           theError = aErrorMessage;
1416           return false;
1417         }
1418     }
1419   }
1420   return true;
1421 }
1422
1423 bool SketchPlugin_ThirdPointValidator::isValid(
1424     const AttributePtr& theAttribute,
1425     const std::list<std::string>& theArguments,
1426     Events_InfoMessage& theError) const
1427 {
1428   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1429   return arePointsNotOnLine(anOwner, theError) &&
1430          arePointsNotSeparated(anOwner, theArguments, theError);
1431 }
1432
1433 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1434                                               const std::string& thePointAttrName,
1435                                               const std::string& theRefPointAttrName)
1436 {
1437   AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1438       theMacroCircle->attribute(thePointAttrName));
1439   AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1440
1441   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1442   if (aRefAttr) {
1443     if (aRefAttr->isObject()) {
1444       // project a point onto selected feature
1445       std::shared_ptr<SketchPlugin_Feature> aFeature =
1446           std::dynamic_pointer_cast<SketchPlugin_Feature>(
1447           ModelAPI_Feature::feature(aRefAttr->object()));
1448       if (aFeature) {
1449         SketchPlugin_Sketch* aSketch = aFeature->sketch();
1450         std::shared_ptr<GeomAPI_Edge> anEdge =
1451             std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1452         if (anEdge) {
1453           std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1454           if (anEdge->isLine())
1455             aPoint3D = anEdge->line()->project(aPoint3D);
1456           else if (anEdge->isCircle())
1457             aPoint3D = anEdge->circle()->project(aPoint3D);
1458           if(aPoint3D)
1459             aPoint = aSketch->to2D(aPoint3D);
1460         }
1461       }
1462     } else {
1463       AttributePoint2DPtr anOtherPoint =
1464           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1465       if (anOtherPoint)
1466         aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1467     }
1468   }
1469
1470   return aPoint;
1471 }
1472
1473 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1474                                  std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1475 {
1476   if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1477     thePoints[0] = toPoint(theMacroFeature,
1478           SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1479           SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1480     thePoints[1] = toPoint(theMacroFeature,
1481           SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1482           SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1483     thePoints[2] = toPoint(theMacroFeature,
1484           SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1485           SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1486   } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1487     thePoints[0] = toPoint(theMacroFeature,
1488           SketchPlugin_MacroArc::START_POINT_2_ID(),
1489           SketchPlugin_MacroArc::START_POINT_REF_ID());
1490     thePoints[1] = toPoint(theMacroFeature,
1491           SketchPlugin_MacroArc::END_POINT_2_ID(),
1492           SketchPlugin_MacroArc::END_POINT_REF_ID());
1493     thePoints[2] = toPoint(theMacroFeature,
1494           SketchPlugin_MacroArc::PASSED_POINT_ID(),
1495           SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1496   }
1497 }
1498
1499 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1500                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1501                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1502 {
1503   static const double aTolerance = 1.e-7;
1504   if (thePoint1->distance(thePoint2) < aTolerance ||
1505       thePoint1->distance(thePoint3) < aTolerance)
1506     return true;
1507
1508   std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1509                                                             thePoint2->y() - thePoint1->y()));
1510   std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1511                                                             thePoint3->y() - thePoint1->y()));
1512   return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1513 }
1514
1515 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1516                          const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1517                          const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1518 {
1519   static const double aTolerance = 1.e-7;
1520   std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1521   std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1522
1523   std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1524   // the first point is on the line
1525   if (aVec1->squareModulus() < aTolerance * aTolerance)
1526     return false;
1527   std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1528   std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1529   // the second point is on the line
1530   if (aVec2->squareModulus() < aTolerance * aTolerance)
1531     return false;
1532   std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1533
1534   return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1535 }
1536
1537 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1538                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint1,
1539                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint2)
1540 {
1541   static const double aTolerance = 1.e-7;
1542   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1543   double aDistP1C = thePoint1->distance(aCenter);
1544   double aDistP2C = thePoint2->distance(aCenter);
1545   return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1546 }
1547
1548 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1549     const FeaturePtr& theMacroFeature,
1550     Events_InfoMessage& theError) const
1551 {
1552   static const std::string aErrorPointsOnLine(
1553       "Selected points are on the same line");
1554
1555   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1556   threePointsOfFeature(theMacroFeature, aPoints);
1557
1558   if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1559     theError = aErrorPointsOnLine;
1560     return false;
1561   }
1562   return true;
1563 }
1564
1565 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1566     const FeaturePtr& theMacroFeature,
1567     const std::list<std::string>& theArguments,
1568     Events_InfoMessage& theError) const
1569 {
1570   static const std::string aErrorPointsApart(
1571       "Selected entity is lying between first two points");
1572
1573   AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1574   FeaturePtr aRefByThird;
1575   if (aThirdPointRef->isObject())
1576     aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1577   if (!aRefByThird)
1578     return true;
1579
1580   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1581   threePointsOfFeature(theMacroFeature, aPoints);
1582
1583   std::shared_ptr<GeomAPI_Edge> aThirdShape =
1584       std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1585   if (!aThirdShape)
1586     return true;
1587
1588   SketchPlugin_Sketch* aSketch =
1589       std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1590   std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1591   std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1592
1593   bool isOk = true;
1594   if (aThirdShape->isLine())
1595     isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1596   else if (aThirdShape->isCircle() || aThirdShape->isArc())
1597     isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1598
1599   if (!isOk)
1600     theError = aErrorPointsApart;
1601   return isOk;
1602 }
1603
1604 bool SketchPlugin_ArcEndPointValidator::isValid(
1605     const AttributePtr& theAttribute,
1606     const std::list<std::string>& theArguments,
1607     Events_InfoMessage& theError) const
1608 {
1609   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1610   AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1611
1612   if(!anEndPointRef.get()) {
1613     return true;
1614   }
1615
1616   ObjectPtr anObject = anEndPointRef->object();
1617   AttributePtr anAttr = anEndPointRef->attr();
1618   if(!anObject.get() && !anAttr.get()) {
1619     return true;
1620   }
1621
1622   if(anEndPointRef->attr().get()) {
1623     return false;
1624   }
1625
1626   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1627   if(aResult.get()) {
1628     GeomShapePtr aShape = aResult->shape();
1629     if(aShape.get() && aShape->isVertex()) {
1630       return false;
1631     }
1632   }
1633
1634   aFeature = ModelAPI_Feature::feature(anObject);
1635   if(aFeature.get()) {
1636     if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1637       return false;
1638     }
1639   }
1640
1641   return true;
1642 }
1643
1644 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1645 {
1646   if(!theShape.get()) {
1647     return theShape;
1648   }
1649
1650   if(!theShape->isEdge()) {
1651     return theShape;
1652   }
1653
1654   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1655
1656   if(!anEdge.get()) {
1657     return theShape;
1658   }
1659
1660   if(anEdge->isLine()) {
1661     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1662     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1663     return aShape;
1664   }
1665
1666   if(anEdge->isCircle() || anEdge->isArc()) {
1667     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1668     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1669     return aShape;
1670   }
1671
1672   return theShape;
1673 }
1674
1675 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1676     const AttributePtr& theAttribute,
1677     const std::list<std::string>& theArguments,
1678     Events_InfoMessage& theError) const
1679 {
1680   std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1681       std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1682   AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1683
1684   if(!anEndPointRef.get()) {
1685     return true;
1686   }
1687
1688   GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1689
1690   if(!anArcShape.get() || anArcShape->isNull()) {
1691     return true;
1692   }
1693
1694   ObjectPtr anObject = anEndPointRef->object();
1695   AttributePtr anAttr = anEndPointRef->attr();
1696   if(!anObject.get() && !anAttr.get()) {
1697     return true;
1698   }
1699
1700   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1701   if(aResult.get()) {
1702     GeomShapePtr aShape = aResult->shape();
1703     if (!aShape->isEdge())
1704       return true;
1705     aShape = toInfiniteEdge(aShape);
1706     if(aShape.get() && !aShape->isNull()) {
1707       if(anArcShape->isIntersect(aShape)) {
1708         return true;
1709       }
1710     }
1711   }
1712
1713   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1714   if(aSelectedFeature.get()) {
1715     std::list<ResultPtr> aResults = aSelectedFeature->results();
1716     for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1717         anIt != aResults.cend();
1718         ++anIt)
1719     {
1720       GeomShapePtr aShape = (*anIt)->shape();
1721       if (!aShape->isEdge())
1722         return true;
1723       aShape = toInfiniteEdge(aShape);
1724       if(aShape.get() && !aShape->isNull()) {
1725         if(anArcShape->isIntersect(aShape)) {
1726           return true;
1727         }
1728       }
1729     }
1730   }
1731
1732   return false;
1733 }
1734
1735 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1736                                            const std::list<std::string>& theArguments,
1737                                            Events_InfoMessage& theError) const
1738 {
1739   std::set<std::string> aFeatureKinds;
1740   for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1741        anArgIt != theArguments.end(); anArgIt++) {
1742     aFeatureKinds.insert(*anArgIt);
1743   }
1744
1745   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1746     theError = "The attribute with the %1 type is not processed";
1747     theError.arg(theAttribute->attributeType());
1748     return false;
1749   }
1750
1751   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1752                                                                       (theAttribute);
1753   bool isObject = aRefAttr->isObject();
1754   if (!isObject) {
1755     theError = "It uses an empty object";
1756     return false;
1757   }
1758   ObjectPtr anObject = aRefAttr->object();
1759   FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1760   if (!aFeature.get()) {
1761     theError = "The feature of the checked attribute is empty";
1762     return false;
1763   }
1764
1765   FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1766
1767   std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1768   std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1769   for (; anIt != aRefsList.end(); anIt++) {
1770     FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1771     if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1772         aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1773       return false; // constraint is found, that means that the check is not valid
1774   }
1775   return true;
1776 }
1777
1778 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1779     const AttributePtr& theAttribute,
1780     const std::list<std::string>& theArguments,
1781     Events_InfoMessage& theError) const
1782 {
1783   AttributeRefAttrPtr aRefAttr =
1784       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1785   if (!aRefAttr)
1786   {
1787     theError = "Incorrect attribute";
1788     return false;
1789   }
1790
1791   ObjectPtr anOwner;
1792   if (aRefAttr->isObject())
1793     anOwner = aRefAttr->object();
1794   else
1795   {
1796     AttributePtr anAttr = aRefAttr->attr();
1797     anOwner = anAttr->owner();
1798   }
1799   FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1800   if (!anAttrOwnerFeature)
1801     return true;
1802   AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1803   if (!aCopyAttr || !aCopyAttr->value())
1804     return true; // feature is not a copy, thus valid
1805
1806   // check the copy feature is already referred by the "Multi" feature
1807   FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1808   AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1809   for (int i = 0; i < aRefList->size(); ++i)
1810   {
1811     FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1812     if (aRefOwner == anAttrOwnerFeature)
1813     {
1814       theError = "Attribute refers to the object generated by this feature";
1815       return false;
1816     }
1817   }
1818
1819   return true;
1820 }
1821
1822 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1823                                                   const std::list<std::string>& theArguments,
1824                                                   Events_InfoMessage& theError) const
1825 {
1826   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId() &&
1827       theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1828     theError = "The attribute with the %1 type is not processed";
1829     theError.arg(theAttribute->attributeType());
1830     return false;
1831   }
1832
1833   // check the attribute refers to a sketch feature
1834   bool isSketchFeature = false;
1835   AttributeRefAttrPtr aRefAttr =
1836       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1837   if (aRefAttr) {
1838     isSketchFeature = aRefAttr->isObject();
1839     if (isSketchFeature) {
1840       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1841       isSketchFeature = aFeature.get() != NULL;
1842       if (isSketchFeature) {
1843         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1844             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1845         isSketchFeature = aSketchFeature.get() != NULL;
1846       }
1847     }
1848   }
1849   else {
1850     AttributeReferencePtr aReference =
1851       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1852     if (aReference) {
1853       FeaturePtr aFeature = ModelAPI_Feature::feature(aReference->value());
1854       isSketchFeature = aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID();
1855     }
1856   }
1857
1858   if (!isSketchFeature)
1859     theError = "The object selected is not a sketch feature";
1860   return isSketchFeature;
1861 }
1862
1863 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1864                                                        const std::list<std::string>& theArguments,
1865                                                        Events_InfoMessage& theError) const
1866 {
1867   if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1868     theError = "The attribute with the %1 type is not processed";
1869     theError.arg(theAttribute->attributeType());
1870     return false;
1871   }
1872
1873   AttributeDoublePtr anAngleAttr =
1874     std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1875
1876   FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1877   AttributeStringPtr anAngleType =
1878       aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1879   AttributeIntegerPtr aNbCopies =
1880       aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1881
1882   if (anAngleType->value() != "FullAngle")
1883   {
1884     double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1885     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1886     {
1887       theError = "Rotation single angle should produce full angle less than 360 degree";
1888       return false;
1889     }
1890   }
1891   else
1892   {
1893     double aFullAngleValue = anAngleAttr->value();
1894     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1895     {
1896       theError = "Rotation full angle should be in range [0, 360]";
1897       return false;
1898     }
1899   }
1900
1901   return true;
1902 }
1903
1904 bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
1905                                             const std::list<std::string>& theArguments,
1906                                             Events_InfoMessage& theError) const
1907 {
1908   AttributePoint2DArrayPtr aPolesArray =
1909       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
1910   if (!aPolesArray)
1911     return false;
1912
1913   if (aPolesArray->size() < 2) {
1914     theError = "Number of B-spline poles should be 2 or more";
1915     return false;
1916   }
1917
1918   return true;
1919 }
1920
1921 bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature,
1922                                                  const std::list<std::string>& theArguments,
1923                                                  Events_InfoMessage& theError) const
1924 {
1925   AttributeRefAttrListPtr aRefAttrList =
1926       theFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID());
1927   AttributeBooleanPtr aPeriodicAttr =
1928       theFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID());
1929
1930   // check number of selected entities
1931   int aMinNbPoints = aPeriodicAttr->value() ? 3 : 2;
1932   if (aRefAttrList->size() < aMinNbPoints) {
1933     theError = "Not enough points selected. Need at least %1 points.";
1934     theError.arg(aMinNbPoints);
1935     return false;
1936   }
1937   return true;
1938 }