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