1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
3 // File: SketchPlugin_Validators.cpp
4 // Created: 01 Aug 2014
5 // Author: Vitaly SMETANNIKOV
7 #include "SketchPlugin_Validators.h"
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"
21 #include "SketcherPrs_Tools.h"
23 #include <Events_InfoMessage.h>
25 #include <ModelAPI_Data.h>
26 #include <ModelAPI_Validator.h>
27 #include <ModelAPI_AttributeDouble.h>
28 #include <ModelAPI_AttributeRefAttr.h>
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>
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>
46 const double tolerance = 1.e-7;
48 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
49 const std::list<std::string>& theArguments,
50 Events_InfoMessage& theError) const
52 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
53 theError = "The attribute with the %1 type is not processed";
54 theError.arg(theAttribute->attributeType());
58 // there is a check whether the feature contains a point and a linear edge or two point values
59 std::string aParamA = theArguments.front();
60 SessionPtr aMgr = ModelAPI_Session::get();
61 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
63 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
64 bool isObject = aRefAttr->isObject();
66 // an attribute is a point. A point value is valid always for the distance
69 // 1. check whether the references object is a linear
70 ObjectPtr anObject = aRefAttr->object();
72 const ModelAPI_AttributeValidator* aShapeValidator =
73 dynamic_cast<const ModelAPI_AttributeValidator*>(aFactory->validator("GeomValidators_ShapeType"));
74 std::list<std::string> anArguments;
75 anArguments.push_back("circle");
76 Events_InfoMessage aCircleError;
77 bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
78 // the circle line is not a valid case
80 theError = "Circle can not be used in distance constraint";
85 anArguments.push_back("line");
86 Events_InfoMessage aLineError;
87 aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
88 // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
90 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
91 // If it is a line then we have to check that first attribute id not a line
92 std::shared_ptr<SketchPlugin_Feature> aSFeature =
93 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
94 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
95 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
96 std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
97 aFeature->data(), aParamA, aPlane);
99 theError = "One of parameters of distance constraint should be a point";
108 static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2)
110 FeaturePtr aConstrFeature;
111 std::list<AttributePtr> anAttrList;
112 if (theFeature1->getKind() == SketchPlugin_Circle::ID() ||
113 theFeature2->getKind() == SketchPlugin_Circle::ID())
115 if (theFeature2->getKind() == SketchPlugin_Line::ID()) {
116 anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID()));
117 anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID()));
118 } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) {
119 anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID()));
120 anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID()));
123 const std::set<AttributePtr>& aRefsList = theFeature1->data()->refsToMe();
124 std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
125 for (; aRefIt != aRefsList.end(); ++aRefIt) {
126 aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
127 if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
129 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
130 AttributePtr anAttr = aRefAttr->attr();
131 if (anAttr->id() == SketchPlugin_Arc::CENTER_ID())
134 anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
135 if (anAttr == *aRefIt)
136 anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
138 aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
141 anAttr = aRefAttr->attr();
142 for (std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
143 anIt != anAttrList.end(); ++anIt)
150 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
151 const std::list<std::string>& theArguments,
152 Events_InfoMessage& theError) const
154 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
155 theError = "The attribute with the %1 type is not processed";
156 theError.arg(theAttribute->attributeType());
160 // there is a check whether the feature contains a point and a linear edge or two point values
161 std::string aParamA = theArguments.front();
162 SessionPtr aMgr = ModelAPI_Session::get();
163 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
165 FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
166 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
168 bool isObject = aRefAttr->isObject();
169 ObjectPtr anObject = aRefAttr->object();
170 if (isObject && anObject.get()) {
171 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
173 AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
174 ObjectPtr aOtherObject = aOtherAttr->object();
175 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
179 if ((aRefFea->getKind() == SketchPlugin_Arc::ID() ||
180 aOtherFea->getKind() == SketchPlugin_Arc::ID()) &&
181 !hasCoincidentPoint(aRefFea, aOtherFea))
184 if (aRefFea->getKind() == SketchPlugin_Line::ID()) {
185 if (aOtherFea->getKind() != SketchPlugin_Arc::ID() &&
186 aOtherFea->getKind() != SketchPlugin_Circle::ID()) {
187 theError = "It refers to a %1, but %2 is neither an %3 nor %4";
188 theError.arg(SketchPlugin_Line::ID()).arg(aParamA)
189 .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
193 else if (aRefFea->getKind() == SketchPlugin_Arc::ID()) {
194 if (aOtherFea->getKind() != SketchPlugin_Line::ID() &&
195 aOtherFea->getKind() != SketchPlugin_Arc::ID()) {
196 theError = "It refers to an %1, but %2 is not a %3 or an %4";
197 theError.arg(SketchPlugin_Arc::ID()).arg(aParamA)
198 .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID());
202 else if (aRefFea->getKind() == SketchPlugin_Circle::ID()) {
203 if (aOtherFea->getKind() != SketchPlugin_Line::ID()) {
204 theError = "It refers to an %1, but %2 is not a %3";
205 theError.arg(SketchPlugin_Circle::ID()).arg(aParamA)
206 .arg(SketchPlugin_Line::ID());
211 theError = "It refers to %1, but should refer to %2 or %3 or %4";
212 theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID())
213 .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID());
219 theError = "It uses an empty object";
226 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
227 const std::list<std::string>& theArguments,
228 Events_InfoMessage& theError) const
230 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
231 theError = "The attribute with the %1 type is not processed";
232 theError.arg(theAttribute->attributeType());
236 std::shared_ptr<SketchPlugin_Feature> aFeature =
237 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
241 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
243 SketchPlugin_Sketch* aSketch = aFeature->sketch();
244 int aNbFeatures = aSketch->numberOfSubs();
245 for (int anInd = 0; anInd < aNbFeatures; anInd++) {
246 FeaturePtr aSubFeature = aSketch->subFeature(anInd);
247 if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
249 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
250 aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
251 if (aRefAttr->isObject()) {
252 if (aRefAttr->object() == aRAttr->object()) {
253 ObjectPtr anObject = aRefAttr->object();
254 std::string aName = anObject.get() ? anObject->data()->name() : "";
255 theError = "The object %1 has been already fixed.";
260 else if (aRefAttr->attr() == aRAttr->attr()) {
261 AttributePtr anAttribute = aRefAttr->attr();
262 std::string aName = anAttribute.get() ? anAttribute->id() : "";
263 theError = "The attribute %1 has been already fixed.";
271 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
272 const std::list<std::string>& theArguments,
273 Events_InfoMessage& theError) const
275 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
276 theError = "The attribute with the %1 type is not processed";
277 theError.arg(theAttribute->attributeType());
281 std::string aParamA = theArguments.front();
282 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
283 AttributeRefAttrPtr aRefAttr[2];
284 aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
285 aRefAttr[1] = aFeature->data()->refattr(aParamA);
287 if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
288 theError = "Attributes can not be used in equal constraint";
292 std::string aType[2];
293 std::list<std::string> anArguments;
294 for (int i = 0; i < 2; i++) {
295 ObjectPtr anObject = aRefAttr[i]->object();
296 if (!anObject.get()) {
297 theError = "An empty object is used.";
301 aFeature = ModelAPI_Feature::feature(anObject);
302 if (!aFeature.get()) {
303 theError = "An empty feature is used.";
307 aType[i] = aFeature->getKind();
308 if (aFeature->getKind() != SketchPlugin_Line::ID() &&
309 aFeature->getKind() != SketchPlugin_Circle::ID() &&
310 aFeature->getKind() != SketchPlugin_Arc::ID()) {
311 theError = "The %1 feature kind of attribute is wrong. It should be %2 or %3 or %4";
312 theError.arg(aFeature->getKind()).arg(SketchPlugin_Line::ID())
313 .arg(SketchPlugin_Circle::ID()).arg(SketchPlugin_Arc::ID());
314 // wrong type of attribute
319 if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) &&
320 aType[0] != aType[1]) {
321 theError = "Feature with kinds %1 and %2 can not be equal.";
322 theError.arg(aType[0]).arg(aType[1]);
328 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
329 const std::list<std::string>& theArguments,
330 Events_InfoMessage& theError) const
332 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
333 theError = "The attribute with the %1 type is not processed";
334 theError.arg(theAttribute->attributeType());
338 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
339 AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
341 AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
342 aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
343 std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
345 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
346 ObjectPtr aSelObject = aSelAttr->object(anInd);
347 std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
348 std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
349 for (; aMirIter != aMirroredObjects.end(); aMirIter++)
350 if (aSelObject == *aMirIter) {
351 theError = "The object %1 is a result of mirror";
359 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
360 const std::list<std::string>& theArguments,
361 Events_InfoMessage& theError) const
363 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
364 theError = "The attribute with the %1 type is not processed";
365 theError.arg(theAttribute->attributeType());
369 // there is a check whether the feature contains a point and a linear edge or two point values
370 std::string aParamA = theArguments.front();
371 SessionPtr aMgr = ModelAPI_Session::get();
372 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
374 FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
375 AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
377 theError = "The %1 attribute should be %2";
378 theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
382 AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
384 // first attribute is a point, it may coincide with any object
385 if (!aRefAttrA->isObject())
388 ObjectPtr anObject = aRefAttrA->object();
389 if (!anObject.get()) {
390 theError = "%1 attribute has an empty object";
391 theError.arg(aParamA);
394 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
395 if (!aFeature.get()) {
396 theError = "%1 attribute has an empty feature";
397 theError.arg(aParamA);
401 if (aFeature->getKind() == SketchPlugin_Point::ID())
405 // second attribute is a point, it may coincide with any object
406 if (!aRefAttrB->isObject())
409 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
411 theError = "%1 attribute has an empty object";
412 theError.arg(theAttribute->id());
415 if (aFeature->getKind() == SketchPlugin_Point::ID())
418 theError = "There is no an attribute filled by a point";
423 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
424 const std::list<std::string>& theArguments,
425 Events_InfoMessage& theError) const
427 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
428 theError = "The attribute with the %1 type is not processed";
429 theError.arg(theAttribute->attributeType());
433 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
434 AttributeRefListPtr aSelAttr =
435 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
437 AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
438 aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
439 AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
440 aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
441 std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
442 std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
444 std::list<ObjectPtr>::iterator anObjIter;
445 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
446 ObjectPtr aSelObject = aSelAttr->object(anInd);
447 anObjIter = anInitialObjects.begin();
448 for (; anObjIter != anInitialObjects.end(); anObjIter++)
449 if (aSelObject == *anObjIter)
451 if (anObjIter != anInitialObjects.end())
453 anObjIter = aCopiedObjects.begin();
454 for (; anObjIter != aCopiedObjects.end(); anObjIter++)
455 if (aSelObject == *anObjIter) {
456 std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
457 theError = "The object %1 is a result of copy";
465 bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
466 const std::list<std::string>& theArguments,
467 Events_InfoMessage& theError) const
469 AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
471 if (!aAttributeString->value().empty()) {
472 theError = aAttributeString->value();
479 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature, std::string theAttribute)
484 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList, const FeaturePtr theFeature)
486 for(std::set<AttributePtr>::const_iterator anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
487 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
488 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
489 if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
490 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
491 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
492 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
493 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
494 if(anAttrRefA.get()) {
495 ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
497 DocumentPtr aDoc = aResA->document();
499 FeaturePtr aFeatureA = aDoc->feature(aResA);
500 if(aFeatureA.get() && aFeatureA == theFeature) {
506 if(anAttrRefB.get()) {
507 ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
509 DocumentPtr aDoc = aResB->document();
511 FeaturePtr aFeatureB = aDoc->feature(aResB);
512 if(aFeatureB.get() && aFeatureB == theFeature) {
523 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
524 const std::list<std::string>& theArguments,
525 Events_InfoMessage& theError) const
527 std::shared_ptr<SketchPlugin_ConstraintFillet> aFilletFeature = std::dynamic_pointer_cast<SketchPlugin_ConstraintFillet>(theAttribute->owner());
528 AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(theAttribute);
529 if(aPointsRefList->size() == 0) {
530 theError = "Error: List of points is empty.";
534 std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures> aPointsFeaturesMap = aFilletFeature->pointsFeaturesMap();
535 std::set<AttributePtr> aSetOfPointsOnResultEdges;
536 for(std::map<AttributePtr, SketchPlugin_ConstraintFillet::FilletFeatures>::iterator aPointsIter = aPointsFeaturesMap.begin();
537 aPointsIter != aPointsFeaturesMap.end();
539 const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second;
540 const std::list<FeaturePtr>& aResultEdges = aFeatures.resultEdges;
541 for(std::list<FeaturePtr>::const_iterator aResultIter = aResultEdges.cbegin();
542 aResultIter != aResultEdges.cend();
544 FeaturePtr aResultFeature = *aResultIter;
545 if(aResultFeature->getKind() == SketchPlugin_Line::ID()) {
546 aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID()));
547 aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID()));
548 } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) {
549 aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID()));
550 aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID()));
555 std::list<std::pair<ObjectPtr, AttributePtr>> aPointsList = aPointsRefList->list();
556 for(std::list<std::pair<ObjectPtr, AttributePtr>>::const_iterator aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) {
557 ObjectPtr anObject = (*aPointsIt).first;
558 AttributePtr aPointAttribute = (*aPointsIt).second;
559 if (!aPointAttribute.get())
561 std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
563 // If we alredy have some result then:
564 // - if it is the same point all ok, just skip it
565 // - if it is point on the fillet result edge then it is not valid
566 if(!aPointsFeaturesMap.empty()) {
567 if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) {
571 // Check that selected point not on the one of the fillet result edge.
572 if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) {
577 // Obtain constraint coincidence for the fillet point.
578 const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
579 FeaturePtr aConstraintCoincidence;
580 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) {
581 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
582 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
583 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
584 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
585 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
586 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
587 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
588 if(anAttrRefA.get() && !anAttrRefA->isObject()) {
589 AttributePtr anAttrA = anAttrRefA->attr();
590 if(aPointAttribute == anAttrA) {
591 aConstraintCoincidence = aConstrFeature;
595 if(anAttrRefB.get() && !anAttrRefB->isObject()) {
596 AttributePtr anAttrB = anAttrRefB->attr();
597 if(aPointAttribute == anAttrB) {
598 aConstraintCoincidence = aConstrFeature;
605 if(!aConstraintCoincidence.get()) {
606 theError = "Error: one of the selected point does not have coicidence.";
610 // Get coincides from constraint.
611 std::set<FeaturePtr> aCoinsides;
612 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
613 SketchPlugin_ConstraintCoincidence::ENTITY_A(),
615 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
616 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
619 // Remove points from set of coincides.
620 std::set<FeaturePtr> aNewSetOfCoincides;
621 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
622 if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
623 (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
626 if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
627 AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
628 std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
629 double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
630 if(aDistSelectedArcCenter < tolerance) {
634 aNewSetOfCoincides.insert(*anIt);
636 aCoinsides = aNewSetOfCoincides;
638 // If we still have more than two coincides remove auxilary entities from set of coincides.
639 if(aCoinsides.size() > 2) {
640 aNewSetOfCoincides.clear();
641 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) {
642 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
643 aNewSetOfCoincides.insert(*anIt);
646 aCoinsides = aNewSetOfCoincides;
649 if(aCoinsides.size() != 2) {
650 theError = "Error: One of the selected points does not have two suitable edges for fillet.";
654 // Check that selected edges don't have tangent constraint.
655 std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
656 FeaturePtr aFirstFeature = *anIt++;
657 FeaturePtr aSecondFeature = *anIt;
658 const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
659 if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
660 theError = "Error: Edges in selected point has tangent constraint.";
664 std::list<ResultPtr> aFirstResults = aFirstFeature->results();
665 for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin(); aResIt != aFirstResults.end(); ++aResIt) {
666 ResultPtr aRes = *aResIt;
667 const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
668 if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
669 theError = "Error: Edges in selected point has tangent constraint.";
674 // Check that lines not collinear
675 if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) {
676 std::string aStartAttr = SketchPlugin_Line::START_ID();
677 std::string anEndAttr = SketchPlugin_Line::END_ID();
678 std::shared_ptr<GeomAPI_Pnt2d> aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt;
679 aFirstStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(aStartAttr))->pnt();
680 aFirstEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aFirstFeature->attribute(anEndAttr))->pnt();
681 aSecondStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(aStartAttr))->pnt();
682 aSecondEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSecondFeature->attribute(anEndAttr))->pnt();
683 double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) -
684 (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
685 double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) -
686 (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y()));
687 if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) {
696 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
697 const std::list<std::string>& theArguments,
698 Events_InfoMessage& theError) const
700 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
701 theError = "The attribute with the %1 type is not processed";
702 theError.arg(theAttribute->attributeType());
706 // there is a check whether the feature contains a point and a linear edge or two point values
707 std::string aParamA = theArguments.front();
708 SessionPtr aMgr = ModelAPI_Session::get();
709 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
711 FeaturePtr anAttributeFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
712 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
713 AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
715 AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
718 for (int i = 0; i < 2; ++i) {
719 if (!aRefAttrs[i]->isObject())
722 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
724 if (aNbPoints + aNbLines != 0)
729 if (aFeature->getKind() == SketchPlugin_Point::ID())
731 else if (aFeature->getKind() == SketchPlugin_Line::ID())
736 if (aNbPoints != 1 || aNbLines != 1) {
737 theError = "Middle point constraint allows points and lines only";
743 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
744 const std::list<std::string>& /*theArguments*/,
745 Events_InfoMessage& theError) const
747 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
748 theError = "The attribute with the %1 type is not processed";
749 theError.arg(theAttribute->attributeType());
752 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
753 AttributePtr anAttr = aRefAttr->attr();
755 theError = "The attribute %1 should be a point";
756 theError.arg(theAttribute->id());
760 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
761 const std::string& aFeatureType = anAttrFeature->getKind();
762 if (aFeatureType == SketchPlugin_Arc::ID()) {
763 // selected point should not be a center of arc
764 const std::string& aPntId = anAttr->id();
765 if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
766 theError = "The attribute %1 is not supported";
767 theError.arg(aPntId);
771 else if (aFeatureType == SketchPlugin_Line::ID()) {
772 // selected point should be bound point of line
773 const std::string& aPntId = anAttr->id();
774 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
775 theError = "The attribute %1 is not supported";
776 theError.arg(aPntId);
781 theError = "Unable to build tangent arc on %1";
782 theError.arg(anAttrFeature->getKind());
786 // Check the tangent point is equal to arc end
787 FeaturePtr anArc = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->owner());
788 std::shared_ptr<GeomDataAPI_Point2D> anEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
789 anArc->attribute(SketchPlugin_Arc::END_ID()));
790 if (anEndPoint->isInitialized()) {
791 std::shared_ptr<GeomDataAPI_Point2D> aTangPt =
792 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
793 if (aTangPt->pnt()->distance(anEndPoint->pnt()) < tolerance) {
794 theError = "Unable to build arc on same points";
802 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
803 const std::list<std::string>& theArguments,
804 Events_InfoMessage& theError) const
806 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
807 theError = "The attribute with the %1 type is not processed";
808 theError.arg(theAttribute->attributeType());
811 AttributeSelectionPtr aLineAttr =
812 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
813 std::shared_ptr<GeomAPI_Edge> anEdge;
814 if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) {
815 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->value()));
816 } else if(aLineAttr->context() && aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) {
817 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aLineAttr->context()->shape()));
820 if (!anEdge || !anEdge->isLine()) {
821 theError = "The attribute %1 should be a line";
822 theError.arg(theAttribute->id());
826 std::shared_ptr<GeomAPI_Dir> aLineDir = anEdge->line()->direction();
829 std::shared_ptr<SketchPlugin_Sketch> aSketch;
830 std::set<AttributePtr> aRefs = aLineAttr->owner()->data()->refsToMe();
831 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
832 for (; anIt != aRefs.end(); ++anIt) {
833 CompositeFeaturePtr aComp =
834 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
835 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
836 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
841 theError = "There is no sketch referring to the current feature";
845 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
846 std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
847 return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance;
850 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
851 const std::list<std::string>& theArguments,
852 Events_InfoMessage& theError) const
854 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
855 theError = "The attribute with the %1 type is not processed";
856 theError.arg(theAttribute->attributeType());
860 AttributeSelectionPtr aFeatureAttr =
861 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
862 std::shared_ptr<GeomAPI_Edge> anEdge;
863 if(aFeatureAttr && aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) {
864 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
865 } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() &&
866 aFeatureAttr->context()->shape()->isEdge()) {
867 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
871 theError = "The attribute %1 should be an edge";
872 theError.arg(theAttribute->id());
877 std::shared_ptr<SketchPlugin_Sketch> aSketch;
878 std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
879 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
880 for (; anIt != aRefs.end(); ++anIt) {
881 CompositeFeaturePtr aComp =
882 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
883 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
884 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
889 theError = "There is no sketch referring to the current feature";
893 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
894 std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
895 std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
897 if (anEdge->isLine()) {
898 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
899 std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
900 std::shared_ptr<GeomAPI_Pnt> aLineLoc = aLine->location();
901 double aDot = aNormal->dot(aLineDir);
902 double aDist = aLineLoc->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
903 return (fabs(aDot) >= tolerance && fabs(aDot) < 1.0 - tolerance) ||
904 (fabs(aDot) < tolerance && fabs(aDist) > tolerance);
906 else if (anEdge->isCircle() || anEdge->isArc()) {
907 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
908 std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
909 std::shared_ptr<GeomAPI_Pnt> aCircCenter = aCircle->center();
910 double aDot = fabs(aNormal->dot(aCircNormal));
911 double aDist = aCircCenter->xyz()->decreased(anOrigin->xyz())->dot(aNormal->xyz());
912 return fabs(aDot - 1.0) < tolerance * tolerance && fabs(aDist) > tolerance;