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