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