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