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