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