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