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