]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_Validators.cpp
Salome HOME
612b083e76516959b6dfe77989ddecd96f2f1e40
[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_ConstraintRigid.h"
14 #include "SketchPlugin_Line.h"
15 #include "SketchPlugin_Point.h"
16 #include "SketchPlugin_Sketch.h"
17 #include "SketchPlugin_Tools.h"
18
19 #include "SketcherPrs_Tools.h"
20
21 #include <ModelAPI_Data.h>
22 #include <ModelAPI_Validator.h>
23 #include <ModelAPI_AttributeDouble.h>
24 #include <ModelAPI_AttributeRefAttr.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_Session.h>
29
30 #include <GeomDataAPI_Point2D.h>
31
32 const double tolerance = 1.e-7;
33
34 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, 
35                                                  const std::list<std::string>& theArguments,
36                                                  std::string& theError) const
37 {
38   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
39     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
40     return false;
41   }
42
43   // there is a check whether the feature contains a point and a linear edge or two point values
44   std::string aParamA = theArguments.front();
45   SessionPtr aMgr = ModelAPI_Session::get();
46   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
47
48   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
49   bool isObject = aRefAttr->isObject();
50   if (!isObject) {
51     // an attribute is a point. A point value is valid always for the distance
52     return true;
53   } else {
54     // 1. check whether the references object is a linear
55     ObjectPtr anObject = aRefAttr->object();
56
57     const ModelAPI_AttributeValidator* aShapeValidator = 
58       dynamic_cast<const ModelAPI_AttributeValidator*>(aFactory->validator("GeomValidators_ShapeType"));
59     std::list<std::string> anArguments;
60     anArguments.push_back("circle");
61     std::string aCircleError;
62     bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
63     // the circle line is not a valid case
64     if (aShapeValid) {
65       theError = "Circle can not be used in distance constraint";
66       return false;
67     }
68       
69     anArguments.clear();
70     anArguments.push_back("line");
71     std::string aLineError;
72     aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
73     // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
74     if (aShapeValid) {
75       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
76       // If it is a line then we have to check that first attribute id not a line
77       std::shared_ptr<SketchPlugin_Feature> aSFeature =
78         std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
79       SketchPlugin_Sketch* aSketch = aSFeature->sketch();
80       std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
81       std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
82         aFeature->data(), aParamA, aPlane);
83       if (!aPoint.get()) {
84         theError = "One of parameters of distance constraint should be a point";
85         return false;
86       }
87     }
88   }
89   return true;
90 }
91
92
93 static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2)
94 {
95   FeaturePtr aConstrFeature;
96   std::list<AttributePtr> anAttrList;
97   if (theFeature1->getKind() == SketchPlugin_Circle::ID() ||
98       theFeature2->getKind() == SketchPlugin_Circle::ID())
99     return false;
100   if (theFeature2->getKind() == SketchPlugin_Line::ID()) {
101     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID()));
102     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID()));
103   } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) {
104     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID()));
105     anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID()));
106   }
107
108   const std::set<AttributePtr>& aRefsList = theFeature1->data()->refsToMe();
109   std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
110   for (; aRefIt != aRefsList.end(); ++aRefIt) {
111     aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
112     if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
113       continue;
114     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
115     AttributePtr anAttr = aRefAttr->attr();
116     if (anAttr->id() == SketchPlugin_Arc::CENTER_ID())
117       continue;
118
119     anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
120     if (anAttr == *aRefIt)
121       anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
122
123     aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
124     anAttr = aRefAttr->attr();
125     for (std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
126          anIt != anAttrList.end(); ++anIt)
127       if (*anIt == anAttr)
128         return true;
129   }
130   return false;
131 }
132
133 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, 
134                                                 const std::list<std::string>& theArguments,
135                                                 std::string& theError) const
136 {
137   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
138     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
139     return false;
140   }
141
142   // there is a check whether the feature contains a point and a linear edge or two point values
143   std::string aParamA = theArguments.front();
144   SessionPtr aMgr = ModelAPI_Session::get();
145   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
146
147   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
148   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
149
150   bool isObject = aRefAttr->isObject();
151   ObjectPtr anObject = aRefAttr->object();
152   if (isObject && anObject.get()) {
153     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
154
155     AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
156     ObjectPtr aOtherObject = aOtherAttr->object();
157     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
158     if (!aOtherFea)
159       return true;
160
161     if ((aRefFea->getKind() == SketchPlugin_Arc::ID() ||
162         aOtherFea->getKind() == SketchPlugin_Arc::ID()) &&
163         !hasCoincidentPoint(aRefFea, aOtherFea))
164       return false;
165
166     if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
167       if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
168           aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
169         theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is neither an "
170           + SketchPlugin_Arc::ID() + " nor " + SketchPlugin_Circle::ID();
171         return false;
172       }
173     }
174     else if (aRefFea->getKind() == SketchPlugin_Arc::ID()) {
175       if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
176         aOtherFea->getKind() != SketchPlugin_Arc::ID()) {
177         theError = "It refers to an " + SketchPlugin_Arc::ID() + ", but " + aParamA + " is not a "
178           + SketchPlugin_Line::ID() + " or an " + SketchPlugin_Arc::ID();
179         return false;
180       }
181     }
182     else if (aRefFea->getKind() == SketchPlugin_Circle::ID()) {
183       if (aOtherFea->getKind() != SketchPlugin_Line::ID()) {
184         theError = "It refers to an " + SketchPlugin_Circle::ID() + ", but " + aParamA + " is not a "
185           + SketchPlugin_Line::ID();
186         return false;
187       }
188     }
189     else {
190       theError = "It refers to " + aRefFea->getKind() + ", but should refer to " + SketchPlugin_Line::ID()
191         + " or " + SketchPlugin_Arc::ID() + " or " + SketchPlugin_Circle::ID();
192       return false;
193     }
194     return true;
195   }
196   else {
197     theError = "It uses an empty object";
198     return false;
199   }
200
201   return true;
202 }
203
204 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute, 
205                                              const std::list<std::string>& theArguments,
206                                              std::string& theError) const
207 {
208   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
209     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
210     return false;
211   }
212
213   std::shared_ptr<SketchPlugin_Feature> aFeature =
214       std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
215   if (!aFeature)
216     return true;
217
218   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
219
220   SketchPlugin_Sketch* aSketch = aFeature->sketch();
221   int aNbFeatures = aSketch->numberOfSubs();
222   for (int anInd = 0; anInd < aNbFeatures; anInd++) {
223     FeaturePtr aSubFeature = aSketch->subFeature(anInd);
224     if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
225       continue;
226     AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
227         aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
228     if (aRefAttr->isObject()) {
229       if (aRefAttr->object() == aRAttr->object()) {
230         ObjectPtr anObject = aRefAttr->object();
231         std::string aName = anObject.get() ? anObject->data()->name() : "";
232         theError = "The object " + aName + " has been already fixed.";
233         return false;
234       }
235     }
236     else if (aRefAttr->attr() == aRAttr->attr()) {
237       AttributePtr anAttribute = aRefAttr->attr();
238       std::string aName = anAttribute.get() ? anAttribute->id() : "";
239       theError = "The attribute " + aName + " has been already fixed.";
240       return false;
241     }
242   }
243   return true;
244 }
245
246 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, 
247                                               const std::list<std::string>& theArguments,
248                                               std::string& theError) const
249 {
250   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
251     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
252     return false;
253   }
254
255   std::string aParamA = theArguments.front();
256   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
257   AttributeRefAttrPtr aRefAttr[2];
258   aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
259   aRefAttr[1] = aFeature->data()->refattr(aParamA);
260
261   if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
262     theError = "Attributes can not be used in equal constraint";
263     return false;
264   }
265
266   int aType[2] = {0, 0}; // types of attributes: 0 - incorrect, 1 - line, 2 - circle, 3 - arc
267   std::list<std::string> anArguments;
268   for (int i = 0; i < 2; i++) {
269     ObjectPtr anObject = aRefAttr[i]->object();
270     if (!anObject.get()) {
271       theError = "An empty object is used.";
272       return false;
273     }
274
275     aFeature = ModelAPI_Feature::feature(anObject);
276     if (!aFeature.get()) {
277       theError = "An empty feature is used.";
278       return false;
279     }
280
281     if (aFeature->getKind() == SketchPlugin_Line::ID()) {
282       aType[i] = 1;
283       continue;
284     }
285     if (aFeature->getKind() == SketchPlugin_Circle::ID()) {
286       aType[i] = 2;
287       continue;
288     }
289     if (aFeature->getKind() == SketchPlugin_Arc::ID()) {
290       aType[i] = 3;
291       continue;
292     }
293     theError = "The " + aFeature->getKind() + " feature kind of attribute is wrong. It should be " +
294                SketchPlugin_Line::ID() + " or " + SketchPlugin_Circle::ID() + " or " + 
295                SketchPlugin_Arc::ID();
296     // wrong type of attribute
297     return false;
298   }
299
300   if ((aType[0] == 1 && aType[1] == 2) ||
301       (aType[0] == 2 && aType[1] == 1)) {
302     theError = "Feature with kinds " + SketchPlugin_Line::ID() + " and " +
303                SketchPlugin_Circle::ID() + "can not be equal.";
304     return false;
305   }
306   return true;
307 }
308
309 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, 
310                                                const std::list<std::string>& theArguments,
311                                                std::string& theError) const
312 {
313   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
314     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
315     return false;
316   }
317
318   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
319   AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
320
321   AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
322       aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
323   std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
324
325   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
326     ObjectPtr aSelObject = aSelAttr->object(anInd);
327     std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
328     std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
329     for (; aMirIter != aMirroredObjects.end(); aMirIter++)
330       if (aSelObject == *aMirIter) {
331         theError = "The object " + aName + " is a result of mirror";
332         return false;
333       }
334   }
335   return true;
336 }
337
338 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, 
339                                                     const std::list<std::string>& theArguments,
340                                                     std::string& theError) const
341 {
342   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
343     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
344     return false;
345   }
346
347   // there is a check whether the feature contains a point and a linear edge or two point values
348   std::string aParamA = theArguments.front();
349   SessionPtr aMgr = ModelAPI_Session::get();
350   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
351
352   FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
353   AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
354   if (!aRefAttrA) {
355     theError = "The " + aParamA + " attribute " + " should be " + ModelAPI_AttributeRefAttr::typeId();
356     return false;
357   }
358
359   AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
360
361   // first attribute is a point, it may coincide with any object
362   if (!aRefAttrA->isObject())
363     return true;
364   else {
365     ObjectPtr anObject = aRefAttrA->object();
366     if (!anObject.get()) {
367       theError = aParamA + " attribute has an empty object";
368       return false;
369     }
370     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
371     if (!aFeature.get()) {
372       theError = aParamA + " attribute has an empty feature";
373       return false;
374     }
375
376     if (aFeature->getKind() == SketchPlugin_Point::ID())
377       return true;
378   }
379
380   // second attribute is a point, it may coincide with any object
381   if (!aRefAttrB->isObject())
382     return true;
383   else {
384     FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
385     if (!aFeature) {
386       theError = theAttribute->id() + " attribute has an empty object";
387       return false;
388     }
389     if (aFeature->getKind() == SketchPlugin_Point::ID())
390       return true;
391   }
392   theError = "There is no an attribute filled by a point";
393   return false;
394 }
395
396
397 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, 
398                                          const std::list<std::string>& theArguments,
399                                          std::string& theError) const
400 {
401   if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
402     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
403     return false;
404   }
405
406   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
407   AttributeRefListPtr aSelAttr = 
408     std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
409
410   AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
411       aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
412   AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
413       aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
414   std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
415   std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
416
417   std::list<ObjectPtr>::iterator anObjIter;
418   for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
419     ObjectPtr aSelObject = aSelAttr->object(anInd);
420     anObjIter = anInitialObjects.begin();
421     for (; anObjIter != anInitialObjects.end(); anObjIter++)
422       if (aSelObject == *anObjIter)
423         break;
424     if (anObjIter != anInitialObjects.end())
425       continue;
426     anObjIter = aCopiedObjects.begin();
427     for (; anObjIter != aCopiedObjects.end(); anObjIter++)
428       if (aSelObject == *anObjIter) {
429         std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
430         theError = "The object " + aName + " is a result of copy";
431         return false;
432       }
433   }
434   return true;
435 }
436
437 bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
438                                                 const std::list<std::string>& theArguments,
439                                                 std::string& theError) const
440 {
441   AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
442
443   if (!aAttributeString->value().empty()) {
444     theError = aAttributeString->value();
445     return false;
446   }
447
448   return true;
449 }
450
451 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature, std::string theAttribute)
452 {
453   return true;
454 }
455
456 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
457                                                  const std::list<std::string>& theArguments,
458                                                  std::string& theError) const
459 {
460   if(!theAttribute.get()) {
461     return false;
462   }
463
464   AttributeRefAttrPtr aBase = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
465   AttributePtr anAttrBase = aBase->attr();
466   if(aBase->isObject()) {
467     return false;
468   }
469
470   // If we alredy have some result then:
471   // - if it is the same point all ok
472   // - if it is point on the fillet arc then it is not valid
473   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
474   AttributePtr aBaseLinesAttribute = aFeature->attribute(SketchPlugin_Constraint::ENTITY_C());
475   AttributeRefListPtr aRefListOfBaseLines = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aBaseLinesAttribute);
476   std::list<ObjectPtr> anOldFeatList = aRefListOfBaseLines->list();
477   if(!aRefListOfBaseLines->list().empty()) {
478     FeaturePtr anOldFeatureA, anOldFeatureB;
479     std::list<ObjectPtr>::iterator aFeatIt = anOldFeatList.begin();
480     anOldFeatureA = ModelAPI_Feature::feature(*aFeatIt++);
481     anOldFeatureB = ModelAPI_Feature::feature(*aFeatIt);
482
483     AttributePtr anAttrStartA = 
484       anOldFeatureA->attribute(anOldFeatureA->getKind() == SketchPlugin_Line::ID() ? SketchPlugin_Line::START_ID() : SketchPlugin_Arc::START_ID());
485     AttributePtr anAttrEndA = 
486       anOldFeatureA->attribute(anOldFeatureA->getKind() == SketchPlugin_Line::ID() ? SketchPlugin_Line::END_ID() : SketchPlugin_Arc::END_ID());
487     AttributePtr anAttrStartB = 
488       anOldFeatureB->attribute(anOldFeatureB->getKind() == SketchPlugin_Line::ID() ? SketchPlugin_Line::START_ID() : SketchPlugin_Arc::START_ID());
489     AttributePtr anAttrEndB = 
490       anOldFeatureB->attribute(anOldFeatureB->getKind() == SketchPlugin_Line::ID() ? SketchPlugin_Line::END_ID() : SketchPlugin_Arc::END_ID());
491
492     std::shared_ptr<GeomAPI_Pnt2d> aBasePnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrBase)->pnt();
493     std::shared_ptr<GeomAPI_Pnt2d> aStartPntA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStartA)->pnt();
494     std::shared_ptr<GeomAPI_Pnt2d> anEndPntA = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEndA)->pnt();
495     std::shared_ptr<GeomAPI_Pnt2d> aStartPntB = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrStartB)->pnt();
496     std::shared_ptr<GeomAPI_Pnt2d> anEndPntB = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrEndB)->pnt();
497     double aDistBaseStartA = aBasePnt->distance(aStartPntA);
498     double aDistBaseEndA = aBasePnt->distance(anEndPntA);
499     double aDistStartAStartB = aStartPntA->distance(aStartPntB);
500     double aDistStartAEndB = aStartPntA->distance(anEndPntB);
501     double aDistEndAStartB = anEndPntA->distance(aStartPntB);
502     double aDistEndAEndB = anEndPntA->distance(anEndPntB);
503
504     if((aDistBaseStartA < tolerance && (aDistStartAStartB < tolerance || aDistStartAEndB < tolerance)) ||
505       (aDistBaseEndA < tolerance && (aDistEndAStartB < tolerance || aDistEndAStartB < tolerance))) {
506       return true;
507     }
508
509     // Check that point not on fillet arc
510     AttributeRefListPtr aRefListOfFillet = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
511         aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
512     std::list<ObjectPtr> aNewFeatList = aRefListOfFillet->list();
513     if(!aNewFeatList.empty()) {
514       aFeatIt = aNewFeatList.begin();
515       FeaturePtr aNewArc;
516       //aNewFeatureA = ModelAPI_Feature::feature(*aFeatIt++);
517       //aNewFeatureB = ModelAPI_Feature::feature(*aFeatIt++);
518       aFeatIt++; aFeatIt++;
519       aNewArc = ModelAPI_Feature::feature(*aFeatIt);
520       AttributePtr anArcStart = aNewArc->attribute(SketchPlugin_Arc::START_ID());
521       AttributePtr anArcEnd = aNewArc->attribute(SketchPlugin_Arc::END_ID());
522       std::shared_ptr<GeomAPI_Pnt2d> anArcStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcStart)->pnt();
523       std::shared_ptr<GeomAPI_Pnt2d> anArcEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcEnd)->pnt();
524       double aDistBaseArcStart = aBasePnt->distance(anArcStartPnt);
525       double aDistBaseArcEnd = aBasePnt->distance(anArcEndPnt);
526       if(aDistBaseArcStart < tolerance || aDistBaseArcEnd < tolerance) {
527         return false;
528       }
529     }
530   }
531
532   const std::set<AttributePtr>& aRefsList = anAttrBase->owner()->data()->refsToMe();
533   std::set<AttributePtr>::const_iterator aIt;
534   FeaturePtr aCoincident;
535   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
536     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
537     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
538     if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
539       AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
540         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
541       AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
542         aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
543       if(anAttrRefA.get() && !anAttrRefA->isObject()) {
544         AttributePtr anAttrA = anAttrRefA->attr();
545         if(anAttrBase == anAttrA) {
546           aCoincident = aConstrFeature;
547           break;
548         }
549       }
550       if(anAttrRefA.get() && !anAttrRefB->isObject()) {
551         AttributePtr anAttrB = anAttrRefB->attr();
552         if(anAttrBase == anAttrB) {
553           aCoincident = aConstrFeature;
554           break;
555         }
556       }
557     }
558   }
559
560   if(!aCoincident.get()) {
561     return false;
562   }
563
564   std::set<FeaturePtr> aCoinsides;
565   SketchPlugin_Tools::findCoincidences(aCoincident,
566                                        SketchPlugin_ConstraintCoincidence::ENTITY_A(),
567                                        aCoinsides);
568   SketchPlugin_Tools::findCoincidences(aCoincident,
569                                        SketchPlugin_ConstraintCoincidence::ENTITY_B(),
570                                        aCoinsides);
571   // Remove points
572   std::set<FeaturePtr> aNewLines;
573   for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
574     if((*anIt)->getKind() != SketchPlugin_Point::ID()) {
575       aNewLines.insert(*anIt);
576     }
577   }
578   aCoinsides = aNewLines;
579
580   // Remove auxilary lines
581   if(aCoinsides.size() > 2) {
582     aNewLines.clear();
583     for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
584       if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
585         aNewLines.insert(*anIt);
586       }
587     }
588     aCoinsides = aNewLines;
589   }
590
591   if(aCoinsides.size() != 2) {
592     return false;
593   }
594
595   // Check that lines not collinear
596   std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
597   FeaturePtr aFirstFeature = *anIt++;
598   FeaturePtr aSecondFeature = *anIt;
599   if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
600     std::string aStartAttr = SketchPlugin_Line::START_ID();
601     std::string anEndAttr = SketchPlugin_Line::END_ID();
602     std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
603     aFirstStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(aStartAttr))->pnt();
604     aFirstEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
605     aSecondStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(aStartAttr))->pnt();
606     aSecondEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(anEndAttr))->pnt();
607     double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) -
608       (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
609     double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) -
610       (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
611     if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
612       return false;
613     }
614   }
615
616   return true;
617 }
618
619 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, 
620                                                     const std::list<std::string>& theArguments,
621                                                     std::string& theError) const
622 {
623   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
624     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
625     return false;
626   }
627
628   // there is a check whether the feature contains a point and a linear edge or two point values
629   std::string aParamA = theArguments.front();
630   SessionPtr aMgr = ModelAPI_Session::get();
631   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
632
633   FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
634   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
635   AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
636
637   AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
638   int aNbPoints = 0;
639   int aNbLines = 0;
640   for (int i = 0; i < 2; ++i) {
641     if (!aRefAttrs[i]->isObject())
642       ++aNbPoints;
643     else {
644       FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
645       if (!aFeature) {
646         if (aNbPoints + aNbLines != 0)
647           return true;
648         else continue;
649       }
650
651       if (aFeature->getKind() == SketchPlugin_Point::ID())
652         ++aNbPoints;
653       else if (aFeature->getKind() == SketchPlugin_Line::ID())
654         ++aNbLines;
655     }
656   }
657
658   if (aNbPoints != 1 || aNbLines != 1) {
659     theError = "Middle point constraint allows points and lines only";
660     return false;
661   }
662   return true;
663 }