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