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