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