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