Salome HOME
#2027 Sketcher Trim Feature: 1. preview/selected attributes in trim; 2. avoid includi...
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_Validators.cpp
4 // Created:     01 Aug 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "SketchPlugin_Validators.h"
8
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_Circle.h"
11 #include "SketchPlugin_ConstraintCoincidence.h"
12 #include "SketchPlugin_ConstraintDistance.h"
13 #include "SketchPlugin_Fillet.h"
14 #include "SketchPlugin_ConstraintRigid.h"
15 #include "SketchPlugin_ConstraintTangent.h"
16 #include "SketchPlugin_Line.h"
17 #include "SketchPlugin_Point.h"
18 #include "SketchPlugin_Sketch.h"
19 #include "SketchPlugin_Trim.h"
20 #include "SketchPlugin_Tools.h"
21
22 #include "SketcherPrs_Tools.h"
23
24 #include <Events_InfoMessage.h>
25
26 #include <ModelAPI_Data.h>
27 #include <ModelAPI_Validator.h>
28 #include <ModelAPI_AttributeDouble.h>
29 #include <ModelAPI_AttributeRefAttr.h>
30
31 #include <ModelAPI_AttributeRefAttrList.h>
32 #include <ModelAPI_AttributeRefList.h>
33 #include <ModelAPI_AttributeSelectionList.h>
34 #include <ModelAPI_AttributeString.h>
35 #include <ModelAPI_Session.h>
36 #include <ModelAPI_Tools.h>
37 #include <ModelAPI_ResultConstruction.h>
38
39 #include <ModelGeomAlgo_Point2D.h>
40 #include <ModelGeomAlgo_Shape.h>
41
42 #include <GeomAPI_Circ.h>
43 #include <GeomAPI_Lin.h>
44 #include <GeomAPI_Edge.h>
45 #include <GeomAPI_Vertex.h>
46 #include <GeomDataAPI_Point2D.h>
47
48 #include <algorithm>
49 #include <cmath>
50
51 const double tolerance = 1.e-7;
52
53 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
54                                                  const std::list<std::string>& theArguments,
55                                                  Events_InfoMessage& theError) const
56 {
57   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
58     theError = "The attribute with the %1 type is not processed";
59     theError.arg(theAttribute->attributeType());
60     return false;
61   }
62
63   // there is a check whether the feature contains a point and a linear edge or two point values
64   std::string aParamA = theArguments.front();
65   SessionPtr aMgr = ModelAPI_Session::get();
66   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
67
68   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
69                                                                       (theAttribute);
70   bool isObject = aRefAttr->isObject();
71   if (!isObject) {
72     // an attribute is a point. A point value is valid always for the distance
73     return true;
74   } else {
75     // 1. check whether the references object is a linear
76     ObjectPtr anObject = aRefAttr->object();
77
78     const ModelAPI_AttributeValidator* aShapeValidator =
79       dynamic_cast<const ModelAPI_AttributeValidator*>(
80       aFactory->validator("GeomValidators_ShapeType"));
81     std::list<std::string> anArguments;
82     anArguments.push_back("circle");
83     Events_InfoMessage aCircleError;
84     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
85     // the circle line is not a valid case
86     if (aShapeValid) {
87       theError = "Circle can not be used in distance constraint";
88       return false;
89     }
90
91     anArguments.clear();
92     anArguments.push_back("line");
93     Events_InfoMessage aLineError;
94     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
95     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
96     if (aShapeValid) {
97       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
98       // If it is a line then we have to check that first attribute id not a line
99       std::shared_ptr<SketchPlugin_Feature> aSFeature =
100         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
101       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
102       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
103       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
104         aFeature->data(), aParamA, aPlane);
105       if (!aPoint.get()) {
106         theError = "One of parameters of distance constraint should be a point";
107         return false;
108       }
109     }
110   }
111   return true;
112 }
113
114 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
115                                                 const std::list<std::string>& theArguments,
116                                                 Events_InfoMessage& theError) const
117 {
118   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
119     theError = "The attribute with the %1 type is not processed";
120     theError.arg(theAttribute->attributeType());
121     return false;
122   }
123
124   // there is a check whether the feature contains a point and a linear edge or two point values
125   std::string aParamA = theArguments.front();
126   SessionPtr aMgr = ModelAPI_Session::get();
127   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
128
129   FeaturePtr anAttributeFeature =
130     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
131   AttributeRefAttrPtr aRefAttr =
132     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
133
134   bool isObject = aRefAttr->isObject();
135   ObjectPtr anObject = aRefAttr->object();
136   if (isObject && anObject.get()) {
137     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
138
139     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
140     ObjectPtr aOtherObject = aOtherAttr->object();
141     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
142     if (!aOtherFea)
143       return true;
144
145     if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
146       if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
147           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
148         theError = "It refers to a %1, but %2 is neither an %3 nor %4";
149         theError.arg(SketchPlugin_Line::ID()).arg(aParamA)
150             .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
151         return false;
152       }
153     }
154     else if (aRefFea->getKind() == SketchPlugin_Arc::ID() ||
155              aRefFea->getKind() == SketchPlugin_Circle::ID()) {
156       if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
157           aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
158           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
159         theError = "It refers to an %1, but %2 is not a %3 or an %4 or a %5";
160         theError.arg(SketchPlugin_Arc::ID()).arg(aParamA)
161             .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID())
162             .arg(SketchPlugin_Circle::ID());
163         return false;
164       }
165     }
166     else {
167       theError = "It refers to %1, but should refer to %2 or %3 or %4";
168       theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID())
169           .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
170       return false;
171     }
172     return true;
173   }
174   else {
175     theError = "It uses an empty object";
176     return false;
177   }
178
179   return true;
180 }
181
182 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
183                                              const std::list<std::string>& theArguments,
184                                              Events_InfoMessage& theError) const
185 {
186   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
187     theError = "The attribute with the %1 type is not processed";
188     theError.arg(theAttribute->attributeType());
189     return false;
190   }
191
192   std::shared_ptr<SketchPlugin_Feature> aFeature =
193       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
194   if (!aFeature)
195     return true;
196
197   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
198
199   SketchPlugin_Sketch* aSketch = aFeature->sketch();
200   int aNbFeatures = aSketch->numberOfSubs();
201   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
202     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
203     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
204       continue;
205     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
206         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
207     if (aRefAttr->isObject()) {
208       if (aRefAttr->object() == aRAttr->object()) {
209         ObjectPtr anObject = aRefAttr->object();
210         std::string aName = anObject.get() ? anObject->data()->name() : "";
211         theError = "The object %1 has been already fixed.";
212         theError.arg(aName);
213         return false;
214       }
215     }
216     else if (aRefAttr->attr() == aRAttr->attr()) {
217       AttributePtr anAttribute = aRefAttr->attr();
218       std::string aName = anAttribute.get() ? anAttribute->id() : "";
219       theError = "The attribute %1 has been already fixed.";
220       theError.arg(aName);
221       return false;
222     }
223   }
224   return true;
225 }
226
227 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
228                                               const std::list<std::string>& theArguments,
229                                               Events_InfoMessage& theError) const
230 {
231   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
232     theError = "The attribute with the %1 type is not processed";
233     theError.arg(theAttribute->attributeType());
234     return false;
235   }
236
237   std::string aParamA = theArguments.front();
238   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
239   AttributeRefAttrPtr aRefAttr[2];
240   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
241   aRefAttr[1] = aFeature->data()->refattr(aParamA);
242
243   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
244     theError = "Attributes can not be used in equal constraint";
245     return false;
246   }
247
248   std::string aType[2];
249   std::list<std::string> anArguments;
250   for (int i = 0; i < 2; i++) {
251     ObjectPtr anObject = aRefAttr[i]->object();
252     if (!anObject.get()) {
253       theError = "An empty object is used.";
254       return false;
255     }
256
257     aFeature = ModelAPI_Feature::feature(anObject);
258     if (!aFeature.get()) {
259       theError = "An empty feature is used.";
260       return false;
261     }
262
263     aType[i] = aFeature->getKind();
264     if (aFeature->getKind() != SketchPlugin_Line::ID() &&
265         aFeature->getKind() != SketchPlugin_Circle::ID() &&
266         aFeature->getKind() != SketchPlugin_Arc::ID()) {
267       theError = "The %1 feature kind of attribute is wrong. It should be %2 or %3 or %4";
268       theError.arg(aFeature->getKind()).arg(SketchPlugin_Line::ID())
269           .arg(SketchPlugin_Circle::ID()).arg(SketchPlugin_Arc::ID());
270       // wrong type of attribute
271       return false;
272     }
273   }
274
275   if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) &&
276       aType[0] != aType[1]) {
277     theError = "Feature with kinds %1 and %2 can not be equal.";
278     theError.arg(aType[0]).arg(aType[1]);
279     return false;
280   }
281   return true;
282 }
283
284 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
285                                                const std::list<std::string>& theArguments,
286                                                Events_InfoMessage& theError) const
287 {
288   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
289     theError = "The attribute with the %1 type is not processed";
290     theError.arg(theAttribute->attributeType());
291     return false;
292   }
293
294   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
295   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
296
297   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
298       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
299   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
300
301   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
302     ObjectPtr aSelObject = aSelAttr->object(anInd);
303     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
304     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
305     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
306       if (aSelObject == *aMirIter) {
307         theError = "The object %1 is a result of mirror";
308         theError.arg(aName);
309         return false;
310       }
311   }
312   return true;
313 }
314
315 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
316                                                     const std::list<std::string>& theArguments,
317                                                     Events_InfoMessage& theError) const
318 {
319   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
320     theError = "The attribute with the %1 type is not processed";
321     theError.arg(theAttribute->attributeType());
322     return false;
323   }
324
325   // there is a check whether the feature contains a point and a linear edge or two point values
326   std::string aParamA = theArguments.front();
327   SessionPtr aMgr = ModelAPI_Session::get();
328   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
329
330   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
331   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
332   if (!aRefAttrA) {
333     theError = "The %1 attribute should be %2";
334     theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
335     return false;
336   }
337
338   AttributeRefAttrPtr aRefAttrB =
339     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
340
341   // first attribute is a point, it may coincide with any object
342   if (!aRefAttrA->isObject())
343     return true;
344   else {
345     ObjectPtr anObject = aRefAttrA->object();
346     if (!anObject.get()) {
347       theError = "%1 attribute has an empty object";
348       theError.arg(aParamA);
349       return false;
350     }
351     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
352     if (!aFeature.get()) {
353       theError = "%1 attribute has an empty feature";
354       theError.arg(aParamA);
355       return false;
356     }
357
358     if (aFeature->getKind() == SketchPlugin_Point::ID())
359       return true;
360   }
361
362   // second attribute is a point, it may coincide with any object
363   if (!aRefAttrB->isObject())
364     return true;
365   else {
366     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
367     if (!aFeature) {
368       theError = "%1 attribute has an empty object";
369       theError.arg(theAttribute->id());
370       return false;
371     }
372     if (aFeature->getKind() == SketchPlugin_Point::ID())
373       return true;
374   }
375   theError = "There is no an attribute filled by a point";
376   return false;
377 }
378
379
380 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
381                                          const std::list<std::string>& theArguments,
382                                          Events_InfoMessage& theError) const
383 {
384   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
385     theError = "The attribute with the %1 type is not processed";
386     theError.arg(theAttribute->attributeType());
387     return false;
388   }
389
390   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
391   AttributeRefListPtr aSelAttr =
392     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
393
394   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
395       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
396   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
397       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
398   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
399   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
400
401   std::list<ObjectPtr>::iterator anObjIter;
402   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
403     ObjectPtr aSelObject = aSelAttr->object(anInd);
404     anObjIter = anInitialObjects.begin();
405     for (; anObjIter != anInitialObjects.end(); anObjIter++)
406       if (aSelObject == *anObjIter)
407         break;
408     if (anObjIter != anInitialObjects.end())
409       continue;
410     anObjIter = aCopiedObjects.begin();
411     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
412       if (aSelObject == *anObjIter) {
413         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
414         theError = "The object %1 is a result of copy";
415         theError.arg(aName);
416         return false;
417       }
418   }
419   return true;
420 }
421
422 bool SketchPlugin_SolverErrorValidator::isValid(
423   const std::shared_ptr<ModelAPI_Feature>& theFeature,
424   const std::list<std::string>& theArguments,
425   Events_InfoMessage& theError) const
426 {
427   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
428
429   if (!aAttributeString->value().empty()) {
430     theError = aAttributeString->value();
431     return false;
432   }
433
434   return true;
435 }
436
437 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
438                                                         std::string theAttribute)
439 {
440   return true;
441 }
442
443 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
444                                   const FeaturePtr theFeature)
445 {
446   for(std::set<AttributePtr>::const_iterator
447       anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
448     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
449     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
450     if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
451       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
452         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
453       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
454         aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
455       if(anAttrRefA.get()) {
456         ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
457         if(aResA.get()) {
458           DocumentPtr aDoc = aResA->document();
459           if(aDoc.get()) {
460             FeaturePtr aFeatureA = aDoc->feature(aResA);
461             if(aFeatureA.get() && aFeatureA == theFeature) {
462               return true;
463             }
464           }
465         }
466       }
467       if(anAttrRefB.get()) {
468         ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
469         if(aResB.get()) {
470           DocumentPtr aDoc = aResB->document();
471           if(aDoc.get()) {
472             FeaturePtr aFeatureB = aDoc->feature(aResB);
473             if(aFeatureB.get() && aFeatureB == theFeature) {
474               return true;
475             }
476           }
477         }
478       }
479     }
480   }
481   return false;
482 }
483
484 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
485                                                  const std::list<std::string>& theArguments,
486                                                  Events_InfoMessage& theError) const
487 {
488   AttributeRefAttrPtr aPointRefAttr =
489     std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
490   if(!aPointRefAttr.get()) {
491     theError = "Error: Point not selected.";
492     return false;
493   }
494
495   AttributePtr aPointAttribute = aPointRefAttr->attr();
496   if (!aPointAttribute.get()) {
497     theError = "Error: Bad point selected.";
498     return false;
499   }
500   std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
501     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
502
503   // Obtain constraint coincidence for the fillet point.
504   const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
505   FeaturePtr aConstraintCoincidence;
506   for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
507       anIt != aRefsList.cend(); ++anIt) {
508     std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
509     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
510     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
511       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
512         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
513       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
514         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
515       if(anAttrRefA.get() && !anAttrRefA->isObject()) {
516         AttributePtr anAttrA = anAttrRefA->attr();
517         if(aPointAttribute == anAttrA) {
518           aConstraintCoincidence = aConstrFeature;
519           break;
520         }
521       }
522       if(anAttrRefB.get() && !anAttrRefB->isObject()) {
523         AttributePtr anAttrB = anAttrRefB->attr();
524         if(aPointAttribute == anAttrB) {
525           aConstraintCoincidence = aConstrFeature;
526           break;
527         }
528       }
529     }
530   }
531
532   if(!aConstraintCoincidence.get()) {
533     theError = "Error: one of the selected point does not have coicidence.";
534     return false;
535   }
536
537   // Get coincides from constraint.
538   std::set<FeaturePtr> aCoinsides;
539   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
540                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
541                                         aCoinsides);
542   SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
543                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
544                                         aCoinsides);
545
546   // Remove points from set of coincides.
547   std::set<FeaturePtr> aNewSetOfCoincides;
548   for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
549       anIt != aCoinsides.end(); ++anIt) {
550     std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
551       std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
552     if(aSketchEntity.get() && aSketchEntity->isCopy()) {
553       continue;
554     }
555     if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
556         (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
557           continue;
558     }
559     if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
560       AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
561       std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
562         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
563       double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
564       if(aDistSelectedArcCenter < tolerance) {
565         continue;
566       }
567     }
568     aNewSetOfCoincides.insert(*anIt);
569   }
570   aCoinsides = aNewSetOfCoincides;
571
572   // If we still have more than two coincides remove auxilary entities from set of coincides.
573   if(aCoinsides.size() > 2) {
574     aNewSetOfCoincides.clear();
575     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
576         anIt != aCoinsides.end(); ++anIt) {
577       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
578         aNewSetOfCoincides.insert(*anIt);
579       }
580     }
581     aCoinsides = aNewSetOfCoincides;
582   }
583
584   if(aCoinsides.size() != 2) {
585     theError = "Error: One of the selected points does not have two suitable edges for fillet.";
586     return false;
587   }
588
589   // Check that selected edges don't have tangent constraint.
590   std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
591   FeaturePtr aFirstFeature = *anIt++;
592   FeaturePtr aSecondFeature = *anIt;
593   const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
594   if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
595     theError = "Error: Edges in selected point has tangent constraint.";
596     return false;
597   }
598
599   std::list<ResultPtr> aFirstResults = aFirstFeature->results();
600   for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
601       aResIt != aFirstResults.end(); ++aResIt) {
602     ResultPtr aRes = *aResIt;
603     const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
604     if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
605       theError = "Error: Edges in selected point has tangent constraint.";
606       return false;
607     }
608   }
609
610   // Check that lines not collinear
611   if(aFirstFeature->getKind() == SketchPlugin_Line::ID() &&
612       aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
613     std::string aStartAttr = SketchPlugin_Line::START_ID();
614     std::string anEndAttr = SketchPlugin_Line::END_ID();
615     std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
616     aFirstStartPnt =
617       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
618       aFirstFeature->attribute(aStartAttr))->pnt();
619     aFirstEndPnt =
620       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
621     aSecondStartPnt =
622       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
623       aSecondFeature->attribute(aStartAttr))->pnt();
624     aSecondEndPnt =
625       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
626       aSecondFeature->attribute(anEndAttr))->pnt();
627     double aCheck1 =
628       fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
629       (aSecondStartPnt->y() - aFirstStartPnt->y()) -
630       (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
631     double aCheck2 =
632       fabs((aFirstEndPnt->x() - aFirstStartPnt->x()) *
633       (aSecondEndPnt->y() - aFirstStartPnt->y()) -
634       (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
635     if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
636       return false;
637     }
638   }
639
640
641   return true;
642 }
643
644 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
645                                                     const std::list<std::string>& theArguments,
646                                                     Events_InfoMessage& theError) const
647 {
648   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
649     theError = "The attribute with the %1 type is not processed";
650     theError.arg(theAttribute->attributeType());
651     return false;
652   }
653
654   // there is a check whether the feature contains a point and a linear edge or two point values
655   std::string aParamA = theArguments.front();
656   SessionPtr aMgr = ModelAPI_Session::get();
657   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
658
659   FeaturePtr anAttributeFeature =
660     std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
661   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
662   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
663
664   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
665   int aNbPoints = 0;
666   int aNbLines = 0;
667   for (int i = 0; i < 2; ++i) {
668     if (!aRefAttrs[i]->isObject())
669       ++aNbPoints;
670     else {
671       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
672       if (!aFeature) {
673         if (aNbPoints + aNbLines != 0)
674           return true;
675         else continue;
676       }
677
678       if (aFeature->getKind() == SketchPlugin_Point::ID())
679         ++aNbPoints;
680       else if (aFeature->getKind() == SketchPlugin_Line::ID())
681         ++aNbLines;
682     }
683   }
684
685   if (aNbPoints != 1 || aNbLines != 1) {
686     theError = "Middle point constraint allows points and lines only";
687     return false;
688   }
689   return true;
690 }
691
692 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
693                                                     const std::list<std::string>& /*theArguments*/,
694                                                     Events_InfoMessage& theError) const
695 {
696   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
697     theError = "The attribute with the %1 type is not processed";
698     theError.arg(theAttribute->attributeType());
699     return false;
700   }
701   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
702   AttributePtr anAttr = aRefAttr->attr();
703   if (!anAttr) {
704     theError = "The attribute %1 should be a point";
705     theError.arg(theAttribute->id());
706     return false;
707   }
708
709   FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
710   const std::string& aFeatureType = anAttrFeature->getKind();
711   if (aFeatureType == SketchPlugin_Arc::ID()) {
712     // selected point should not be a center of arc
713     const std::string& aPntId = anAttr->id();
714     if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
715       theError = "The attribute %1 is not supported";
716       theError.arg(aPntId);
717       return false;
718     }
719   }
720   else if (aFeatureType == SketchPlugin_Line::ID()) {
721     // selected point should be bound point of line
722     const std::string& aPntId = anAttr->id();
723     if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
724       theError = "The attribute %1 is not supported";
725       theError.arg(aPntId);
726       return false;
727     }
728   }
729   else {
730     theError = "Unable to build tangent arc on %1";
731     theError.arg(anAttrFeature->getKind());
732     return false;
733   }
734
735   // Check the tangent point is equal to arc end
736   FeaturePtr anArc = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->owner());
737   std::shared_ptr<GeomDataAPI_Point2D> anEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
738       anArc->attribute(SketchPlugin_Arc::END_ID()));
739   if (anEndPoint->isInitialized()) {
740     std::shared_ptr<GeomDataAPI_Point2D> aTangPt =
741         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
742     if (aTangPt->pnt()->distance(anEndPoint->pnt()) < tolerance) {
743       theError = "Unable to build arc on same points";
744       return false;
745     }
746   }
747
748   return true;
749 }
750
751 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
752                                                  const std::list<std::string>& theArguments,
753                                                  Events_InfoMessage& theError) const
754 {
755   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
756     theError = "The attribute with the %1 type is not processed";
757     theError.arg(theAttribute->attributeType());
758     return false;
759   }
760   AttributeSelectionPtr aLineAttr =
761                        std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
762   std::shared_ptr<GeomAPI_Edge> anEdge;
763   if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
764     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
765   } else if(aLineAttr->context() &&
766             aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) {
767     anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
768   }
769
770   if (!anEdge || !anEdge->isLine()) {
771     theError = "The attribute %1 should be a line";
772     theError.arg(theAttribute->id());
773     return false;
774   }
775
776   std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
777
778   // find a sketch
779   std::shared_ptr<SketchPlugin_Sketch> aSketch;
780   std::set<AttributePtr> aRefs = aLineAttr->owner()->data()->refsToMe();
781   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
782   for (; anIt != aRefs.end(); ++anIt) {
783     CompositeFeaturePtr aComp =
784         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
785     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
786       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
787       break;
788     }
789   }
790   if (!aSketch) {
791     theError = "There is no sketch referring to the current feature";
792     return false;
793   }
794
795   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
796   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
797   return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
798 }
799
800 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
801                                           const std::list<std::string>& theArguments,
802                                           Events_InfoMessage& theError) const
803 {
804   bool aValid = false;
805
806   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
807     theError = "The attribute with the %1 type is not processed";
808     theError.arg(theAttribute->attributeType());
809     return aValid;
810   }
811   AttributeReferencePtr aFeatureAttr =
812             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
813
814   ObjectPtr anAttrObject = aFeatureAttr->value();
815   FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
816   if (!anAttrFeature)
817     return aValid;
818
819   std::string aKind = anAttrFeature->getKind();
820   if (aKind == SketchPlugin_Line::ID() ||
821       aKind == SketchPlugin_Arc::ID() ||
822       aKind == SketchPlugin_Circle::ID()) {
823
824     std::set<ResultPtr> anEdgeShapes;
825     ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
826     if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
827       return aValid;
828
829     // coincidences to the feature
830     std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
831     ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
832                         SketchPlugin_ConstraintCoincidence::ID(),
833                         aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
834
835     GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
836     std::shared_ptr<SketchPlugin_Feature> aSFeature =
837                                  std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
838     SketchPlugin_Sketch* aSketch = aSFeature->sketch();
839
840     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
841     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
842         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
843     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
844         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
845     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
846         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
847     std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
848
849     typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
850                      std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
851                                std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
852     PointToRefsMap aPointsInfo;
853
854     ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
855                                                 aX->dir(), aDirY, aPointsInfo);
856     int aCoincidentToFeature = (int)aPointsInfo.size();
857     if (aKind == SketchPlugin_Circle::ID())
858       aValid = aCoincidentToFeature >= 2;
859     else
860       aValid = aCoincidentToFeature >= 1;
861   }
862
863   return aValid;
864 }
865
866 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
867                                          const std::list<std::string>& theArguments,
868                                          Events_InfoMessage& theError) const
869 {
870   bool aValid = false;
871
872   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
873     theError = "The attribute with the %1 type is not processed";
874     theError.arg(theAttribute->attributeType());
875     return aValid;
876   }
877   AttributeReferencePtr aBaseObjectAttr =
878             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
879
880   std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
881                  std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
882
883   ObjectPtr aBaseObject = aBaseObjectAttr->value();
884   if (!aBaseObject) {
885     AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
886     aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
887     aBaseObject = aBaseObjectAttr->value();
888
889     //return aValid;
890   }
891
892   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
893   if (!aBaseFeature)
894     return aValid;
895
896   std::string aKind = aBaseFeature->getKind();
897   if (aKind != SketchPlugin_Line::ID() &&
898       aKind != SketchPlugin_Arc::ID() &&
899       aKind != SketchPlugin_Circle::ID())
900     return aValid;
901
902   // point on feature
903   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
904                        aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
905
906   SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
907
908   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
909   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
910                                                               anAttributePnt2d->y());
911
912   std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
913   std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
914            std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
915                      std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
916   SketchPlugin_Trim::fillObjectShapes(aBaseObject, aSketch->data()->owner(),
917                                       aCashedShapes, anObjectToPoints);
918   const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
919
920   return aShapes.size() > 1;
921 }
922
923 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
924                                                const std::list<std::string>& theArguments,
925                                                Events_InfoMessage& theError) const
926 {
927   if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
928     theError = "The attribute with the %1 type is not processed";
929     theError.arg(theAttribute->attributeType());
930     return false;
931   }
932
933   AttributeSelectionPtr aFeatureAttr =
934       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
935   std::shared_ptr<GeomAPI_Edge> anEdge;
936   if (aFeatureAttr.get()) {
937     GeomShapePtr aVal = aFeatureAttr->value();
938     ResultPtr aRes = aFeatureAttr->context();
939     if(aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) {
940       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
941     } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() &&
942               aFeatureAttr->context()->shape()->isEdge()) {
943       anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
944     }
945   }
946   if (!anEdge) {
947     theError = "The attribute %1 should be an edge";
948     theError.arg(theAttribute->id());
949     return false;
950   }
951
952   // find a sketch
953   std::shared_ptr<SketchPlugin_Sketch> aSketch;
954   std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
955   std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
956   for (; anIt != aRefs.end(); ++anIt) {
957     CompositeFeaturePtr aComp =
958         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
959     if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
960       aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
961       break;
962     }
963   }
964   if (!aSketch) {
965     theError = "There is no sketch referring to the current feature";
966     return false;
967   }
968
969   std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
970   std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
971   std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
972
973   if (anEdge->isLine()) {
974     std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
975     std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
976     std::shared_ptr<GeomAPI_Pnt> aLineLoc = aLine->location();
977     double aDot = aNormal->dot(aLineDir);
978     double aDist = aLineLoc->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
979     bool aValid = (fabs(aDot) >= tolerance && fabs(aDot) < 1.0 - tolerance) ||
980            (fabs(aDot) < tolerance && fabs(aDist) > tolerance);
981     if (!aValid)
982       theError = "Error: Edge is already in the sketch plane.";
983     return aValid;
984   }
985   else if (anEdge->isCircle() || anEdge->isArc()) {
986     std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
987     std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
988     std::shared_ptr<GeomAPI_Pnt> aCircCenter = aCircle->center();
989     double aDot = fabs(aNormal->dot(aCircNormal));
990     double aDist = aCircCenter->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
991     bool aValid = fabs(aDot - 1.0) < tolerance * tolerance && fabs(aDist) > tolerance;
992     if (!aValid)
993       theError.arg(anEdge->isCircle() ? "Error: Cirlce is already in the sketch plane."
994                                       : "Error: Arc is already in the sketch plane.");
995     return aValid;
996   }
997
998   theError = "Error: Selected object is not line, circle or arc.";
999   return false;
1000 }