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