]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_Validators.cpp
Salome HOME
Issue #19187: B-Splines - Crash with specific scenario
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
1 // Copyright (C) 2014-2020  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_Line.h"
35 #include "SketchPlugin_MacroArc.h"
36 #include "SketchPlugin_MacroCircle.h"
37 #include "SketchPlugin_MultiRotation.h"
38 #include "SketchPlugin_Point.h"
39 #include "SketchPlugin_Sketch.h"
40 #include "SketchPlugin_Trim.h"
41 #include "SketchPlugin_Tools.h"
42
43 #include "SketcherPrs_Tools.h"
44
45 #include <Events_InfoMessage.h>
46
47 #include <ModelAPI_Data.h>
48 #include <ModelAPI_Validator.h>
49 #include <ModelAPI_AttributeDouble.h>
50 #include <ModelAPI_AttributeInteger.h>
51 #include <ModelAPI_AttributeRefAttr.h>
52 #include <ModelAPI_AttributeRefList.h>
53 #include <ModelAPI_AttributeSelectionList.h>
54 #include <ModelAPI_AttributeString.h>
55 #include <ModelAPI_Session.h>
56 #include <ModelAPI_Tools.h>
57 #include <ModelAPI_ResultConstruction.h>
58
59 #include <ModelGeomAlgo_Point2D.h>
60 #include <ModelGeomAlgo_Shape.h>
61
62 #include <GeomAlgoAPI_EdgeBuilder.h>
63 #include <GeomAlgoAPI_ShapeTools.h>
64
65 #include <GeomAPI_Circ.h>
66 #include <GeomAPI_Dir2d.h>
67 #include <GeomAPI_Ellipse.h>
68 #include <GeomAPI_Lin.h>
69 #include <GeomAPI_Edge.h>
70 #include <GeomAPI_Vertex.h>
71
72 #include <GeomDataAPI_Point2D.h>
73 #include <GeomDataAPI_Point2DArray.h>
74
75 #include <algorithm>
76 #include <cmath>
77
78 #ifdef _MSC_VER
79 #pragma warning(disable: 4100)
80 #endif
81
82 const double tolerance = 1.e-7;
83
84 static bool isSpline(FeaturePtr theFeature)
85 {
86   return theFeature && (theFeature->getKind() == SketchPlugin_BSpline::ID() ||
87                         theFeature->getKind() == SketchPlugin_BSplinePeriodic::ID());
88 }
89
90
91 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
92                                                  const std::list<std::string>& theArguments,
93                                                  Events_InfoMessage& theError) const
94 {
95   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
96     theError = "The attribute with the %1 type is not processed";
97     theError.arg(theAttribute->attributeType());
98     return false;
99   }
100
101   // there is a check whether the feature contains a point and a linear edge or two point values
102   std::string aParamA = theArguments.front();
103   SessionPtr aMgr = ModelAPI_Session::get();
104   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
105
106   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
107                                                                       (theAttribute);
108   bool isObject = aRefAttr->isObject();
109   if (!isObject) {
110     // an attribute is a point. A point value is valid always for the distance
111     return true;
112   } else {
113     // 1. check whether the references object is a linear
114     ObjectPtr anObject = aRefAttr->object();
115
116     const ModelAPI_AttributeValidator* aShapeValidator =
117       dynamic_cast<const ModelAPI_AttributeValidator*>(
118       aFactory->validator("GeomValidators_ShapeType"));
119     std::list<std::string> anArguments;
120     anArguments.push_back("circle");
121     Events_InfoMessage aCircleError;
122     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
123     // the circle line is not a valid case
124     if (aShapeValid) {
125       theError = "Circle can not be used in distance constraint";
126       return false;
127     }
128
129     anArguments.clear();
130     anArguments.push_back("line");
131     Events_InfoMessage aLineError;
132     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
133     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
134     if (aShapeValid) {
135       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
136       // If it is a line then we have to check that first attribute id not a line
137       std::shared_ptr<SketchPlugin_Feature> aSFeature =
138         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
139       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
140       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
141       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
142         aFeature->data(), aParamA, aPlane);
143       if (!aPoint.get()) {
144         theError = "One of parameters of distance constraint should be a point";
145         return false;
146       }
147     }
148   }
149   return true;
150 }
151
152 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
153                                                 const std::list<std::string>& theArguments,
154                                                 Events_InfoMessage& theError) const
155 {
156   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
157     theError = "The attribute with the %1 type is not processed";
158     theError.arg(theAttribute->attributeType());
159     return false;
160   }
161
162   // there is a check whether the feature contains a point and a linear edge or two point values
163   std::string aParamA = theArguments.front();
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       std::set<FeaturePtr>::iterator aFoundCoinc = aCoinc.find(aOtherFea);
243       if (aFoundCoinc != aCoinc.end()) {
244         // do not take into account internal constraints
245         AttributeReferencePtr aParent =
246             (*aFoundCoinc)->reference(SketchPlugin_SketchEntity::PARENT_ID());
247         isValid = !aParent || !aParent->isInitialized() || aParent->value() != aRefFea;
248       }
249     }
250   }
251
252   return isValid;
253 }
254
255 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
256                                                       const std::list<std::string>& theArguments,
257                                                       Events_InfoMessage& theError) const
258 {
259   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
260     theError = "The attribute with the %1 type is not processed";
261     theError.arg(theAttribute->attributeType());
262     return false;
263   }
264
265   std::string aParamA = theArguments.front();
266
267   FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
268   AttributeRefAttrPtr aRefAttr =
269       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
270
271   bool isObject = aRefAttr->isObject();
272   ObjectPtr anObject = aRefAttr->object();
273   if (isObject && anObject.get()) {
274     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
275
276     AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
277     ObjectPtr aOtherObject = aOtherAttr->object();
278     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
279
280     // at least one feature should be a line
281     if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
282         aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) {
283       theError = "At least one feature should be a line";
284       return false;
285     }
286     else if (isSpline(aRefFea) || isSpline(aOtherFea)) {
287       theError = "B-spline is not supported";
288       return false;
289     }
290   }
291   else {
292     theError = "It uses an empty object";
293     return false;
294   }
295
296   return true;
297 }
298
299 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
300                                              const std::list<std::string>& theArguments,
301                                              Events_InfoMessage& theError) const
302 {
303   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
304     theError = "The attribute with the %1 type is not processed";
305     theError.arg(theAttribute->attributeType());
306     return false;
307   }
308
309   std::shared_ptr<SketchPlugin_Feature> aFeature =
310       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
311   if (!aFeature)
312     return true;
313
314   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
315
316   SketchPlugin_Sketch* aSketch = aFeature->sketch();
317   int aNbFeatures = aSketch->numberOfSubs();
318   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
319     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
320     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
321       continue;
322     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
323         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
324     if (aRefAttr->isObject()) {
325       if (aRefAttr->object() == aRAttr->object()) {
326         ObjectPtr anObject = aRefAttr->object();
327         std::string aName = anObject.get() ? anObject->data()->name() : "";
328         theError = "The object %1 has been already fixed.";
329         theError.arg(aName);
330         return false;
331       }
332     }
333     else if (aRefAttr->attr() == aRAttr->attr()) {
334       AttributePtr anAttribute = aRefAttr->attr();
335       std::string aName = anAttribute.get() ? anAttribute->id() : "";
336       theError = "The attribute %1 has been already fixed.";
337       theError.arg(aName);
338       return false;
339     }
340   }
341   return true;
342 }
343
344 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
345                                               const std::list<std::string>& theArguments,
346                                               Events_InfoMessage& theError) const
347 {
348   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
349     theError = "The attribute with the %1 type is not processed";
350     theError.arg(theAttribute->attributeType());
351     return false;
352   }
353
354   std::string aParamA = theArguments.front();
355   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
356   AttributeRefAttrPtr aRefAttr[2];
357   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
358   aRefAttr[1] = aFeature->data()->refattr(aParamA);
359
360   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
361     theError = "Attributes can not be used in equal constraint";
362     return false;
363   }
364
365   std::string aType[2];
366   std::list<std::string> anArguments;
367   for (int i = 0; i < 2; i++) {
368     aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
369     if (!aFeature.get())
370       return true;
371
372     aType[i] = aFeature->getKind();
373     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
374         aFeature->getKind() != SketchPlugin_Circle::ID() &&
375         aFeature->getKind() != SketchPlugin_Arc::ID() &&
376         aFeature->getKind() != SketchPlugin_Ellipse::ID() &&
377         aFeature->getKind() != SketchPlugin_EllipticArc::ID()) {
378       theError = "The %1 feature is not supported by the Equal constraint.";
379       theError.arg(aFeature->getKind());
380       // wrong type of attribute
381       return false;
382     }
383   }
384
385   bool isOk = aType[0] == aType[1];
386   if (!isOk) {
387     // circle and arc may be equal
388     isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
389         || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
390   }
391   if (!isOk) {
392     // ellipse and elliptic arc may be equal
393     isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID())
394         || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID());
395   }
396   if (!isOk) {
397     theError = "Features with kinds %1 and %2 can not be equal.";
398     theError.arg(aType[0]).arg(aType[1]);
399     return false;
400   }
401   return true;
402 }
403
404 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
405                                                const std::list<std::string>& theArguments,
406                                                Events_InfoMessage& theError) const
407 {
408   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
409     theError = "The attribute with the %1 type is not processed";
410     theError.arg(theAttribute->attributeType());
411     return false;
412   }
413
414   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
415   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
416
417   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
418       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
419   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
420
421   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
422     ObjectPtr aSelObject = aSelAttr->object(anInd);
423
424     // B-splines are not supported in Mirror yet
425     FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
426     if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
427         aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
428       theError = "Not supported";
429       return false;
430     }
431
432     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
433     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
434     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
435       if (aSelObject == *aMirIter) {
436         theError = "The object %1 is a result of mirror";
437         theError.arg(aName);
438         return false;
439       }
440   }
441   return true;
442 }
443
444 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
445                                                     const std::list<std::string>& theArguments,
446                                                     Events_InfoMessage& theError) const
447 {
448   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
449     theError = "The attribute with the %1 type is not processed";
450     theError.arg(theAttribute->attributeType());
451     return false;
452   }
453
454   // there is a check whether the feature contains a point and a linear edge or two point values
455   std::string aParamA = theArguments.front();
456
457   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
458   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
459   if (!aRefAttrA) {
460     theError = "The %1 attribute should be %2";
461     theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
462     return false;
463   }
464
465   AttributeRefAttrPtr aRefAttrB =
466     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
467
468   // first attribute is a point, it may coincide with any object
469   if (!aRefAttrA->isObject())
470     return true;
471   else {
472     ObjectPtr anObject = aRefAttrA->object();
473     if (!anObject.get()) {
474       theError = "%1 attribute has an empty object";
475       theError.arg(aParamA);
476       return false;
477     }
478     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
479     if (!aFeature.get()) {
480       theError = "%1 attribute has an empty feature";
481       theError.arg(aParamA);
482       return false;
483     }
484
485     if (aFeature->getKind() == SketchPlugin_Point::ID())
486       return true;
487   }
488
489   // second attribute is a point, it may coincide with any object
490   if (!aRefAttrB->isObject())
491     return true;
492   else {
493     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
494     if (!aFeature) {
495       theError = "%1 attribute has an empty object";
496       theError.arg(theAttribute->id());
497       return false;
498     }
499     if (aFeature->getKind() == SketchPlugin_Point::ID())
500       return true;
501   }
502   theError = "There is no an attribute filled by a point";
503   return false;
504 }
505
506
507 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
508                                          const std::list<std::string>& theArguments,
509                                          Events_InfoMessage& theError) const
510 {
511   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
512     theError = "The attribute with the %1 type is not processed";
513     theError.arg(theAttribute->attributeType());
514     return false;
515   }
516
517   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
518   AttributeRefListPtr aSelAttr =
519     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
520
521   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
522       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
523   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
524       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
525   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
526   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
527
528   std::list<ObjectPtr>::iterator anObjIter;
529   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
530     ObjectPtr aSelObject = aSelAttr->object(anInd);
531     anObjIter = anInitialObjects.begin();
532     for (; anObjIter != anInitialObjects.end(); anObjIter++)
533       if (aSelObject == *anObjIter)
534         break;
535     if (anObjIter != anInitialObjects.end())
536       continue;
537
538     // B-splines are not supported in Copying features
539     FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject);
540     if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() ||
541         aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) {
542       theError = "Not supported";
543       return false;
544     }
545
546     anObjIter = aCopiedObjects.begin();
547     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
548       if (aSelObject == *anObjIter) {
549         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
550         theError = "The object %1 is a result of copy";
551         theError.arg(aName);
552         return false;
553       }
554   }
555   return true;
556 }
557
558 bool SketchPlugin_SolverErrorValidator::isValid(
559   const std::shared_ptr<ModelAPI_Feature>& theFeature,
560   const std::list<std::string>& theArguments,
561   Events_InfoMessage& theError) const
562 {
563   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
564
565   if (!aAttributeString->value().empty()) {
566     theError = aAttributeString->value();
567     return false;
568   }
569
570   return true;
571 }
572
573 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
574                                                         std::string theAttribute)
575 {
576   return true;
577 }
578
579 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
580                                   const FeaturePtr theFeature)
581 {
582   for(std::set<AttributePtr>::const_iterator
583       anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
584     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
585     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
586     if (!aFeature)
587       continue;
588     if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
589       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
590         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
591       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
592         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
593       if(anAttrRefA.get()) {
594         ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
595         if(aResA.get()) {
596           DocumentPtr aDoc = aResA->document();
597           if(aDoc.get()) {
598             FeaturePtr aFeatureA = aDoc->feature(aResA);
599             if(aFeatureA.get() && aFeatureA == theFeature) {
600               return true;
601             }
602           }
603         }
604       }
605       if(anAttrRefB.get()) {
606         ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
607         if(aResB.get()) {
608           DocumentPtr aDoc = aResB->document();
609           if(aDoc.get()) {
610             FeaturePtr aFeatureB = aDoc->feature(aResB);
611             if(aFeatureB.get() && aFeatureB == theFeature) {
612               return true;
613             }
614           }
615         }
616       }
617     }
618   }
619   return false;
620 }
621
622 static bool isPointPointCoincidence(const FeaturePtr& theCoincidence)
623 {
624   AttributeRefAttrPtr aRefAttr[2] = {
625       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()),
626       theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B())
627   };
628
629   bool arePoints = true;
630   for (int i = 0; i < 2 && arePoints; ++i) {
631     if (aRefAttr[i]->isObject()) {
632       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
633       arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID();
634     } else
635       arePoints = aRefAttr[i]->attr().get() != NULL;
636   }
637   return arePoints;
638 }
639
640 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
641                                                  const std::list<std::string>& theArguments,
642                                                  Events_InfoMessage& theError) const
643 {
644   AttributeRefAttrPtr aPointRefAttr =
645     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
646   if(!aPointRefAttr.get()) {
647     theError = "Error: Point not selected.";
648     return false;
649   }
650
651   AttributePtr aPointAttribute = aPointRefAttr->attr();
652   if (!aPointAttribute.get()) {
653     theError = "Error: Bad point selected.";
654     return false;
655   }
656   std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
657     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
658
659   // Obtain constraint coincidence for the fillet point.
660   const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
661   FeaturePtr aConstraintCoincidence;
662   for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
663       anIt != aRefsList.cend(); ++anIt) {
664     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
665     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
666     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
667       if (!isPointPointCoincidence(aConstrFeature))
668         continue;
669
670       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
671         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
672       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
673         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
674
675       AttributePtr anAttrA = anAttrRefA->attr();
676       if(aPointAttribute == anAttrA) {
677         aConstraintCoincidence = aConstrFeature;
678         break;
679       }
680
681       AttributePtr anAttrB = anAttrRefB->attr();
682       if(aPointAttribute == anAttrB) {
683         aConstraintCoincidence = aConstrFeature;
684         break;
685       }
686     }
687   }
688
689   if(!aConstraintCoincidence.get()) {
690     theError = "Error: one of the selected point does not have coincidence.";
691     return false;
692   }
693
694   // Get coincides from constraint.
695   std::set<FeaturePtr> aCoinsides;
696   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
697                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
698                                         aCoinsides,
699                                         true);
700   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
701                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
702                                         aCoinsides,
703                                         true);
704
705   // Remove points and external lines from set of coincides.
706   std::set<FeaturePtr> aNewSetOfCoincides;
707   for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
708       anIt != aCoinsides.end(); ++anIt) {
709     std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
710       std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
711     if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
712       continue;
713     }
714     if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
715         (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
716           continue;
717     }
718     if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
719       AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
720       std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
721         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
722       double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
723       if(aDistSelectedArcCenter < tolerance) {
724         continue;
725       }
726     }
727     aNewSetOfCoincides.insert(*anIt);
728   }
729   aCoinsides = aNewSetOfCoincides;
730
731   // If we still have more than two coincides remove auxilary entities from set of coincides.
732   if(aCoinsides.size() > 2) {
733     aNewSetOfCoincides.clear();
734     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
735         anIt != aCoinsides.end(); ++anIt) {
736       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
737         aNewSetOfCoincides.insert(*anIt);
738       }
739     }
740     aCoinsides = aNewSetOfCoincides;
741   }
742
743   if(aCoinsides.size() != 2) {
744     theError = "Error: One of the selected points does not have two suitable edges for fillet.";
745     return false;
746   }
747
748   // Check that selected edges don't have tangent constraint.
749   std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
750   FeaturePtr aFirstFeature = *anIt++;
751   FeaturePtr aSecondFeature = *anIt;
752   const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
753   if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
754     theError = "Error: Edges in selected point has tangent constraint.";
755     return false;
756   }
757
758   std::list<ResultPtr> aFirstResults = aFirstFeature->results();
759   for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
760       aResIt != aFirstResults.end(); ++aResIt) {
761     ResultPtr aRes = *aResIt;
762     const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
763     if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
764       theError = "Error: Edges in selected point has tangent constraint.";
765       return false;
766     }
767   }
768
769   // Check the features are not tangent
770   std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
771   std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
772   if (!aFirstShape || !aFirstShape->isEdge() ||
773       !aSecondShape || !aSecondShape->isEdge()) {
774     theError = "Error: At least on of the features is not an edge";
775     return false;
776   }
777
778   std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
779   std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
780
781   static const double TOL = 1.e-7;
782   if (anEdge1->isLine() && anEdge2->isLine()) {
783     // Check that lines not collinear
784     std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
785     std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
786     double aCross = aDir1->cross(aDir2)->squareModulus();
787     if (aCross < TOL * TOL)
788       return false;
789   } else if (anEdge1->isArc() && anEdge2->isArc()) {
790     // check the circles are not tangent
791     std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
792     std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
793     double aDistCC = aCirc1->center()->distance(aCirc2->center());
794     double aRadSum = aCirc1->radius() + aCirc2->radius();
795     double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
796     if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
797       return false;
798   } else {
799     // check whether line and arc are tangent
800     std::shared_ptr<GeomAPI_Circ> aCirc;
801     std::shared_ptr<GeomAPI_Lin> aLine;
802     if (anEdge1->isLine()) {
803       aLine = anEdge1->line();
804       aCirc = anEdge2->circle();
805     } else {
806       aCirc = anEdge1->circle();
807       aLine = anEdge2->line();
808     }
809
810     double aDistCL = aLine->distance(aCirc->center());
811     if (fabs(aDistCL - aCirc->radius()) < TOL)
812       return false;
813   }
814
815   return true;
816 }
817
818 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
819                                                     const std::list<std::string>& theArguments,
820                                                     Events_InfoMessage& theError) const
821 {
822   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
823     theError = "The attribute with the %1 type is not processed";
824     theError.arg(theAttribute->attributeType());
825     return false;
826   }
827
828   // there is a check whether the feature contains a point and a linear edge or two point values
829   std::string aParamA = theArguments.front();
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_Vertex> aVertex;
1167   std::shared_ptr<GeomAPI_Edge> anEdge;
1168   std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1169   if (aFeatureAttr.get()) {
1170     GeomShapePtr aVal = aFeatureAttr->value();
1171     ResultPtr aRes = aFeatureAttr->context();
1172     if (aVal && aVal->isVertex())
1173       aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aVal));
1174     else if (aVal && aVal->isEdge()) {
1175       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aVal));
1176     } else if(aRes && aRes->shape()) {
1177       if (aRes->shape()->isVertex())
1178         aVertex = std::shared_ptr<GeomAPI_Vertex>(new GeomAPI_Vertex(aRes->shape()));
1179       else if (aRes->shape()->isEdge())
1180         anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aRes->shape()));
1181     }
1182
1183     // try to convert result to sketch feature
1184     if (aRes) {
1185       aSketchFeature =
1186         std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1187     }
1188   }
1189   if (!aVertex && !anEdge) {
1190     theError = "The attribute %1 should be an edge or vertex";
1191     theError.arg(theAttribute->id());
1192     return false;
1193   }
1194
1195   // find a sketch
1196   std::shared_ptr<SketchPlugin_Sketch> aSketch;
1197   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1198   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1199   for (; anIt != aRefs.end(); ++anIt) {
1200     CompositeFeaturePtr aComp =
1201         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1202     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1203       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1204       break;
1205     }
1206   }
1207   if (!aSketch) {
1208     theError = "There is no sketch referring to the current feature";
1209     return false;
1210   }
1211   if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1212     theError = "Unable to project feature from the same sketch";
1213     return false;
1214   }
1215
1216   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1217   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1218   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1219
1220   bool aValid = true;
1221   if (aVertex)
1222     aValid = true; // vertex is always could be projected
1223   else if (anEdge->isLine()) {
1224     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1225     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1226     double aDot = fabs(aNormal->dot(aLineDir));
1227     aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1228     if (!aValid)
1229       theError = "Error: Line is orthogonal to the sketch plane.";
1230   }
1231   else if (anEdge->isCircle() || anEdge->isArc()) {
1232     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1233     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1234     double aDot = fabs(aNormal->dot(aCircNormal));
1235     aValid = aDot >= tolerance * tolerance;
1236     if (!aValid)
1237       theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1238                                       : "Error: Arc is orthogonal to the sketch plane.");
1239   }
1240   else if (anEdge->isEllipse()) {
1241     std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1242     std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1243     double aDot = fabs(aNormal->dot(anEllipseNormal));
1244     aValid = fabs(aDot - 1.0) <= tolerance * tolerance;
1245     if (!aValid)
1246       theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane."
1247                                       : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1248   }
1249
1250   return aValid;
1251 }
1252
1253
1254 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1255                                    const std::set<FeaturePtr>& theSet2)
1256 {
1257   std::set<FeaturePtr> aCommon;
1258   if (theSet1.empty() || theSet2.empty())
1259     return aCommon;
1260
1261   std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1262   for (; anIt2 != theSet2.end(); ++anIt2)
1263     if (theSet1.find(*anIt2) != theSet1.end())
1264       aCommon.insert(*anIt2);
1265   return aCommon;
1266 }
1267
1268 bool SketchPlugin_DifferentReferenceValidator::isValid(
1269     const AttributePtr& theAttribute,
1270     const std::list<std::string>& theArguments,
1271     Events_InfoMessage& theError) const
1272 {
1273   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1274
1275   int aNbFeaturesReferred = 0;
1276   int aNbAttributesReferred = 0;
1277   std::set<FeaturePtr> aCommonReferredFeatures;
1278
1279   // find all features referred by attributes listed in theArguments
1280   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1281   for (; anArgIt != theArguments.end(); ++anArgIt) {
1282     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1283     if (!aRefAttr)
1284       continue;
1285
1286     std::set<FeaturePtr> aCoincidentFeatures;
1287     if (aRefAttr->isObject()) {
1288       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1289       if (aFeature) {
1290         aCoincidentFeatures.insert(aFeature);
1291         aNbFeaturesReferred += 1;
1292       }
1293     } else {
1294       AttributePoint2DPtr aPoint =
1295           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1296       if (aPoint) {
1297         aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1298         aNbAttributesReferred += 1;
1299       }
1300     }
1301
1302     if (aCommonReferredFeatures.empty())
1303       aCommonReferredFeatures = aCoincidentFeatures;
1304     else
1305       aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1306
1307     if (aCommonReferredFeatures.empty())
1308       return true;
1309   }
1310
1311   bool isOk = aNbFeaturesReferred < 1;
1312   if (aNbFeaturesReferred == 1) {
1313     if (aCommonReferredFeatures.size() == 1) {
1314       FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1315       isOk = aNbAttributesReferred <= 1 ||
1316              aFeature->getKind() == SketchPlugin_Circle::ID() ||
1317              aFeature->getKind() == SketchPlugin_Arc::ID();
1318     } else
1319       isOk = false;
1320   }
1321
1322   if (!isOk)
1323     theError = "Attributes are referred to the same feature";
1324   return isOk;
1325 }
1326
1327 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1328     const AttributePtr& theAttribute,
1329     const std::list<std::string>& theArguments,
1330     Events_InfoMessage& theError) const
1331 {
1332   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1333   std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1334
1335   // find all points referred by attributes listed in theArguments
1336   bool hasRefsToPoints = false;
1337   std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1338   for (; anArgIt != theArguments.end(); ++anArgIt) {
1339     AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1340     if (!aRefAttr)
1341       continue;
1342
1343     if (!aRefAttr->isObject()) {
1344       AttributePoint2DPtr aPoint =
1345           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1346       if (aReferredCoincidentPoints.empty())
1347         aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1348       else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1349         return true; // non-coincident point has been found
1350       else
1351         hasRefsToPoints = true;
1352     }
1353   }
1354
1355   if (hasRefsToPoints)
1356     theError = "Attributes are referred to the same point";
1357   return !hasRefsToPoints;
1358 }
1359
1360 bool SketchPlugin_CirclePassedPointValidator::isValid(
1361     const AttributePtr& theAttribute,
1362     const std::list<std::string>&,
1363     Events_InfoMessage& theError) const
1364 {
1365   static const std::string aErrorMessage(
1366       "Passed point refers to the same feature as a center point");
1367
1368   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1369
1370   AttributeRefAttrPtr aCenterRef =
1371       anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1372   AttributeRefAttrPtr aPassedRef =
1373       anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1374
1375   if (!aPassedRef->isObject())
1376     return true;
1377
1378   FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1379   if (!aPassedFeature)
1380     return true;
1381
1382   if (aCenterRef->isObject()) {
1383     if (aCenterRef->object() == aPassedRef->object()) {
1384       theError = aErrorMessage;
1385       return false;
1386     }
1387   } else {
1388     AttributePoint2DPtr aCenterPoint =
1389         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1390     if (aCenterPoint) {
1391       std::set<FeaturePtr> aCoincidentFeatures =
1392           SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1393       // check one of coincident features is a feature referred by passed point
1394       std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1395       for(; anIt != aCoincidentFeatures.end(); ++anIt)
1396         if (*anIt == aPassedFeature) {
1397           theError = aErrorMessage;
1398           return false;
1399         }
1400     }
1401   }
1402   return true;
1403 }
1404
1405 bool SketchPlugin_ThirdPointValidator::isValid(
1406     const AttributePtr& theAttribute,
1407     const std::list<std::string>& theArguments,
1408     Events_InfoMessage& theError) const
1409 {
1410   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1411   return arePointsNotOnLine(anOwner, theError) &&
1412          arePointsNotSeparated(anOwner, theArguments, theError);
1413 }
1414
1415 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1416                                               const std::string& thePointAttrName,
1417                                               const std::string& theRefPointAttrName)
1418 {
1419   AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1420       theMacroCircle->attribute(thePointAttrName));
1421   AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1422
1423   std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1424   if (aRefAttr) {
1425     if (aRefAttr->isObject()) {
1426       // project a point onto selected feature
1427       std::shared_ptr<SketchPlugin_Feature> aFeature =
1428           std::dynamic_pointer_cast<SketchPlugin_Feature>(
1429           ModelAPI_Feature::feature(aRefAttr->object()));
1430       if (aFeature) {
1431         SketchPlugin_Sketch* aSketch = aFeature->sketch();
1432         std::shared_ptr<GeomAPI_Edge> anEdge =
1433             std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1434         if (anEdge) {
1435           std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1436           if (anEdge->isLine())
1437             aPoint3D = anEdge->line()->project(aPoint3D);
1438           else if (anEdge->isCircle())
1439             aPoint3D = anEdge->circle()->project(aPoint3D);
1440           if(aPoint3D)
1441             aPoint = aSketch->to2D(aPoint3D);
1442         }
1443       }
1444     } else {
1445       AttributePoint2DPtr anOtherPoint =
1446           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1447       if (anOtherPoint)
1448         aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1449     }
1450   }
1451
1452   return aPoint;
1453 }
1454
1455 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1456                                  std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1457 {
1458   if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1459     thePoints[0] = toPoint(theMacroFeature,
1460           SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1461           SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1462     thePoints[1] = toPoint(theMacroFeature,
1463           SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1464           SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1465     thePoints[2] = toPoint(theMacroFeature,
1466           SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1467           SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1468   } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1469     thePoints[0] = toPoint(theMacroFeature,
1470           SketchPlugin_MacroArc::START_POINT_2_ID(),
1471           SketchPlugin_MacroArc::START_POINT_REF_ID());
1472     thePoints[1] = toPoint(theMacroFeature,
1473           SketchPlugin_MacroArc::END_POINT_2_ID(),
1474           SketchPlugin_MacroArc::END_POINT_REF_ID());
1475     thePoints[2] = toPoint(theMacroFeature,
1476           SketchPlugin_MacroArc::PASSED_POINT_ID(),
1477           SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1478   }
1479 }
1480
1481 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1482                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1483                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1484 {
1485   static const double aTolerance = 1.e-7;
1486   if (thePoint1->distance(thePoint2) < aTolerance ||
1487       thePoint1->distance(thePoint3) < aTolerance)
1488     return true;
1489
1490   std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1491                                                             thePoint2->y() - thePoint1->y()));
1492   std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1493                                                             thePoint3->y() - thePoint1->y()));
1494   return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1495 }
1496
1497 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1498                          const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1499                          const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1500 {
1501   static const double aTolerance = 1.e-7;
1502   std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1503   std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1504
1505   std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1506   // the first point is on the line
1507   if (aVec1->squareModulus() < aTolerance * aTolerance)
1508     return false;
1509   std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1510   std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1511   // the second point is on the line
1512   if (aVec2->squareModulus() < aTolerance * aTolerance)
1513     return false;
1514   std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1515
1516   return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1517 }
1518
1519 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1520                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint1,
1521                          const std::shared_ptr<GeomAPI_Pnt>&  thePoint2)
1522 {
1523   static const double aTolerance = 1.e-7;
1524   std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1525   double aDistP1C = thePoint1->distance(aCenter);
1526   double aDistP2C = thePoint2->distance(aCenter);
1527   return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1528 }
1529
1530 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1531     const FeaturePtr& theMacroFeature,
1532     Events_InfoMessage& theError) const
1533 {
1534   static const std::string aErrorPointsOnLine(
1535       "Selected points are on the same line");
1536
1537   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1538   threePointsOfFeature(theMacroFeature, aPoints);
1539
1540   if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1541     theError = aErrorPointsOnLine;
1542     return false;
1543   }
1544   return true;
1545 }
1546
1547 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1548     const FeaturePtr& theMacroFeature,
1549     const std::list<std::string>& theArguments,
1550     Events_InfoMessage& theError) const
1551 {
1552   static const std::string aErrorPointsApart(
1553       "Selected entity is lying between first two points");
1554
1555   AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1556   FeaturePtr aRefByThird;
1557   if (aThirdPointRef->isObject())
1558     aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1559   if (!aRefByThird)
1560     return true;
1561
1562   std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1563   threePointsOfFeature(theMacroFeature, aPoints);
1564
1565   std::shared_ptr<GeomAPI_Edge> aThirdShape =
1566       std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1567   if (!aThirdShape)
1568     return true;
1569
1570   SketchPlugin_Sketch* aSketch =
1571       std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1572   std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1573   std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1574
1575   bool isOk = true;
1576   if (aThirdShape->isLine())
1577     isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1578   else if (aThirdShape->isCircle() || aThirdShape->isArc())
1579     isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1580
1581   if (!isOk)
1582     theError = aErrorPointsApart;
1583   return isOk;
1584 }
1585
1586 bool SketchPlugin_ArcEndPointValidator::isValid(
1587     const AttributePtr& theAttribute,
1588     const std::list<std::string>& theArguments,
1589     Events_InfoMessage& theError) const
1590 {
1591   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1592   AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1593
1594   if(!anEndPointRef.get()) {
1595     return true;
1596   }
1597
1598   ObjectPtr anObject = anEndPointRef->object();
1599   AttributePtr anAttr = anEndPointRef->attr();
1600   if(!anObject.get() && !anAttr.get()) {
1601     return true;
1602   }
1603
1604   if(anEndPointRef->attr().get()) {
1605     return false;
1606   }
1607
1608   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1609   if(aResult.get()) {
1610     GeomShapePtr aShape = aResult->shape();
1611     if(aShape.get() && aShape->isVertex()) {
1612       return false;
1613     }
1614   }
1615
1616   aFeature = ModelAPI_Feature::feature(anObject);
1617   if(aFeature.get()) {
1618     if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1619       return false;
1620     }
1621   }
1622
1623   return true;
1624 }
1625
1626 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1627 {
1628   if(!theShape.get()) {
1629     return theShape;
1630   }
1631
1632   if(!theShape->isEdge()) {
1633     return theShape;
1634   }
1635
1636   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1637
1638   if(!anEdge.get()) {
1639     return theShape;
1640   }
1641
1642   if(anEdge->isLine()) {
1643     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1644     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1645     return aShape;
1646   }
1647
1648   if(anEdge->isCircle() || anEdge->isArc()) {
1649     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1650     GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1651     return aShape;
1652   }
1653
1654   return theShape;
1655 }
1656
1657 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1658     const AttributePtr& theAttribute,
1659     const std::list<std::string>& theArguments,
1660     Events_InfoMessage& theError) const
1661 {
1662   std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1663       std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1664   AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1665
1666   if(!anEndPointRef.get()) {
1667     return true;
1668   }
1669
1670   GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1671
1672   if(!anArcShape.get() || anArcShape->isNull()) {
1673     return true;
1674   }
1675
1676   ObjectPtr anObject = anEndPointRef->object();
1677   AttributePtr anAttr = anEndPointRef->attr();
1678   if(!anObject.get() && !anAttr.get()) {
1679     return true;
1680   }
1681
1682   ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1683   if(aResult.get()) {
1684     GeomShapePtr aShape = aResult->shape();
1685     if (!aShape->isEdge())
1686       return true;
1687     aShape = toInfiniteEdge(aShape);
1688     if(aShape.get() && !aShape->isNull()) {
1689       if(anArcShape->isIntersect(aShape)) {
1690         return true;
1691       }
1692     }
1693   }
1694
1695   FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1696   if(aSelectedFeature.get()) {
1697     std::list<ResultPtr> aResults = aSelectedFeature->results();
1698     for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1699         anIt != aResults.cend();
1700         ++anIt)
1701     {
1702       GeomShapePtr aShape = (*anIt)->shape();
1703       if (!aShape->isEdge())
1704         return true;
1705       aShape = toInfiniteEdge(aShape);
1706       if(aShape.get() && !aShape->isNull()) {
1707         if(anArcShape->isIntersect(aShape)) {
1708           return true;
1709         }
1710       }
1711     }
1712   }
1713
1714   return false;
1715 }
1716
1717 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1718                                            const std::list<std::string>& theArguments,
1719                                            Events_InfoMessage& theError) const
1720 {
1721   std::set<std::string> aFeatureKinds;
1722   for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1723        anArgIt != theArguments.end(); anArgIt++) {
1724     aFeatureKinds.insert(*anArgIt);
1725   }
1726
1727   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1728     theError = "The attribute with the %1 type is not processed";
1729     theError.arg(theAttribute->attributeType());
1730     return false;
1731   }
1732
1733   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1734                                                                       (theAttribute);
1735   bool isObject = aRefAttr->isObject();
1736   if (!isObject) {
1737     theError = "It uses an empty object";
1738     return false;
1739   }
1740   ObjectPtr anObject = aRefAttr->object();
1741   FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1742   if (!aFeature.get()) {
1743     theError = "The feature of the checked attribute is empty";
1744     return false;
1745   }
1746
1747   FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1748
1749   std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1750   std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1751   for (; anIt != aRefsList.end(); anIt++) {
1752     FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1753     if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1754         aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1755       return false; // constraint is found, that means that the check is not valid
1756   }
1757   return true;
1758 }
1759
1760 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1761     const AttributePtr& theAttribute,
1762     const std::list<std::string>& theArguments,
1763     Events_InfoMessage& theError) const
1764 {
1765   AttributeRefAttrPtr aRefAttr =
1766       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1767   if (!aRefAttr)
1768   {
1769     theError = "Incorrect attribute";
1770     return false;
1771   }
1772
1773   ObjectPtr anOwner;
1774   if (aRefAttr->isObject())
1775     anOwner = aRefAttr->object();
1776   else
1777   {
1778     AttributePtr anAttr = aRefAttr->attr();
1779     anOwner = anAttr->owner();
1780   }
1781   FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1782   if (!anAttrOwnerFeature)
1783     return true;
1784   AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1785   if (!aCopyAttr || !aCopyAttr->value())
1786     return true; // feature is not a copy, thus valid
1787
1788   FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1789   // Collect original entities
1790   std::set<FeaturePtr> anOriginalFeatures;
1791   if (theArguments.size() > 1) {
1792     AttributeRefListPtr anOrigList = aMultiFeature->reflist(theArguments.back());
1793     for (int i = 0; i < anOrigList->size(); ++i)
1794     {
1795       FeaturePtr aFeature = ModelAPI_Feature::feature(anOrigList->object(i));
1796       if (aFeature == anAttrOwnerFeature)
1797         return true;
1798     }
1799   }
1800
1801   // check the copy feature is already referred by the "Multi" feature
1802   AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1803   for (int i = 0; i < aRefList->size(); ++i)
1804   {
1805     FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1806     if (aRefOwner == anAttrOwnerFeature)
1807     {
1808       theError = "Attribute refers to the object generated by this feature";
1809       return false;
1810     }
1811   }
1812
1813   return true;
1814 }
1815
1816 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1817                                                   const std::list<std::string>& theArguments,
1818                                                   Events_InfoMessage& theError) const
1819 {
1820   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId() &&
1821       theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1822     theError = "The attribute with the %1 type is not processed";
1823     theError.arg(theAttribute->attributeType());
1824     return false;
1825   }
1826
1827   // check the attribute refers to a sketch feature
1828   bool isSketchFeature = false;
1829   AttributeRefAttrPtr aRefAttr =
1830       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1831   if (aRefAttr) {
1832     isSketchFeature = aRefAttr->isObject();
1833     if (isSketchFeature) {
1834       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1835       isSketchFeature = aFeature.get() != NULL;
1836       if (isSketchFeature) {
1837         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1838             std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1839         isSketchFeature = aSketchFeature.get() != NULL;
1840       }
1841     }
1842   }
1843   else {
1844     AttributeReferencePtr aReference =
1845       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1846     if (aReference) {
1847       FeaturePtr aFeature = ModelAPI_Feature::feature(aReference->value());
1848       isSketchFeature = aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID();
1849     }
1850   }
1851
1852   if (!isSketchFeature)
1853     theError = "The object selected is not a sketch feature";
1854   return isSketchFeature;
1855 }
1856
1857 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1858                                                        const std::list<std::string>& theArguments,
1859                                                        Events_InfoMessage& theError) const
1860 {
1861   if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1862     theError = "The attribute with the %1 type is not processed";
1863     theError.arg(theAttribute->attributeType());
1864     return false;
1865   }
1866
1867   AttributeDoublePtr anAngleAttr =
1868     std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1869
1870   FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1871   AttributeStringPtr anAngleType =
1872       aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1873   AttributeIntegerPtr aNbCopies =
1874       aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1875
1876   if (anAngleType->value() != "FullAngle")
1877   {
1878     double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1879     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1880     {
1881       theError = "Rotation single angle should produce full angle less than 360 degree";
1882       return false;
1883     }
1884   }
1885   else
1886   {
1887     double aFullAngleValue = anAngleAttr->value();
1888     if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1889     {
1890       theError = "Rotation full angle should be in range [0, 360]";
1891       return false;
1892     }
1893   }
1894
1895   return true;
1896 }
1897
1898 bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
1899                                             const std::list<std::string>& theArguments,
1900                                             Events_InfoMessage& theError) const
1901 {
1902   AttributePoint2DArrayPtr aPolesArray =
1903       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
1904   if (!aPolesArray)
1905     return false;
1906
1907   if (aPolesArray->size() < 2) {
1908     theError = "Number of B-spline poles should be 2 or more";
1909     return false;
1910   }
1911
1912   return true;
1913 }