1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SketchPlugin_Validators.h"
22 #include "SketchPlugin_Arc.h"
23 #include "SketchPlugin_Circle.h"
24 #include "SketchPlugin_ConstraintCoincidence.h"
25 #include "SketchPlugin_ConstraintDistance.h"
26 #include "SketchPlugin_ConstraintRigid.h"
27 #include "SketchPlugin_ConstraintTangent.h"
28 #include "SketchPlugin_Ellipse.h"
29 #include "SketchPlugin_Fillet.h"
30 #include "SketchPlugin_Line.h"
31 #include "SketchPlugin_MacroArc.h"
32 #include "SketchPlugin_MacroCircle.h"
33 #include "SketchPlugin_MultiRotation.h"
34 #include "SketchPlugin_Point.h"
35 #include "SketchPlugin_Sketch.h"
36 #include "SketchPlugin_Trim.h"
37 #include "SketchPlugin_Tools.h"
39 #include "SketcherPrs_Tools.h"
41 #include <Events_InfoMessage.h>
43 #include <ModelAPI_Data.h>
44 #include <ModelAPI_Validator.h>
45 #include <ModelAPI_AttributeDouble.h>
46 #include <ModelAPI_AttributeInteger.h>
47 #include <ModelAPI_AttributeRefAttr.h>
48 #include <ModelAPI_AttributeRefList.h>
49 #include <ModelAPI_AttributeSelectionList.h>
50 #include <ModelAPI_AttributeString.h>
51 #include <ModelAPI_Session.h>
52 #include <ModelAPI_Tools.h>
53 #include <ModelAPI_ResultConstruction.h>
55 #include <ModelGeomAlgo_Point2D.h>
56 #include <ModelGeomAlgo_Shape.h>
58 #include <GeomAlgoAPI_EdgeBuilder.h>
59 #include <GeomAlgoAPI_ShapeTools.h>
61 #include <GeomAPI_Circ.h>
62 #include <GeomAPI_Dir2d.h>
63 #include <GeomAPI_Ellipse.h>
64 #include <GeomAPI_Lin.h>
65 #include <GeomAPI_Edge.h>
66 #include <GeomAPI_Vertex.h>
67 #include <GeomDataAPI_Point2D.h>
72 const double tolerance = 1.e-7;
74 bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute,
75 const std::list<std::string>& theArguments,
76 Events_InfoMessage& theError) const
78 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
79 theError = "The attribute with the %1 type is not processed";
80 theError.arg(theAttribute->attributeType());
84 // there is a check whether the feature contains a point and a linear edge or two point values
85 std::string aParamA = theArguments.front();
86 SessionPtr aMgr = ModelAPI_Session::get();
87 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
89 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
91 bool isObject = aRefAttr->isObject();
93 // an attribute is a point. A point value is valid always for the distance
96 // 1. check whether the references object is a linear
97 ObjectPtr anObject = aRefAttr->object();
99 const ModelAPI_AttributeValidator* aShapeValidator =
100 dynamic_cast<const ModelAPI_AttributeValidator*>(
101 aFactory->validator("GeomValidators_ShapeType"));
102 std::list<std::string> anArguments;
103 anArguments.push_back("circle");
104 Events_InfoMessage aCircleError;
105 bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError);
106 // the circle line is not a valid case
108 theError = "Circle can not be used in distance constraint";
113 anArguments.push_back("line");
114 Events_InfoMessage aLineError;
115 aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError);
116 // if the attribute value is not a line, that means it is a vertex. A vertex is always valid
118 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
119 // If it is a line then we have to check that first attribute id not a line
120 std::shared_ptr<SketchPlugin_Feature> aSFeature =
121 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
122 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
123 std::shared_ptr<GeomAPI_Ax3> aPlane = SketchPlugin_Sketch::plane(aSketch);
124 std::shared_ptr<GeomDataAPI_Point2D> aPoint = SketcherPrs_Tools::getFeaturePoint(
125 aFeature->data(), aParamA, aPlane);
127 theError = "One of parameters of distance constraint should be a point";
135 bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
136 const std::list<std::string>& theArguments,
137 Events_InfoMessage& theError) const
139 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
140 theError = "The attribute with the %1 type is not processed";
141 theError.arg(theAttribute->attributeType());
145 // there is a check whether the feature contains a point and a linear edge or two point values
146 std::string aParamA = theArguments.front();
147 SessionPtr aMgr = ModelAPI_Session::get();
148 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
150 FeaturePtr anAttributeFeature =
151 std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
152 AttributeRefAttrPtr aRefAttr =
153 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
155 bool isObject = aRefAttr->isObject();
156 ObjectPtr anObject = aRefAttr->object();
157 if (isObject && anObject.get()) {
158 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
160 AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
161 ObjectPtr aOtherObject = aOtherAttr->object();
162 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
166 if (aRefFea->getKind() == SketchPlugin_Line::ID() &&
167 aOtherFea->getKind() == SketchPlugin_Line::ID()) {
168 theError = "Two segments cannot be tangent";
174 theError = "It uses an empty object";
181 bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
182 const std::list<std::string>& theArguments,
183 Events_InfoMessage& theError) const
185 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
186 theError = "The attribute with the %1 type is not processed";
187 theError.arg(theAttribute->attributeType());
191 std::string aParamA = theArguments.front();
192 SessionPtr aMgr = ModelAPI_Session::get();
193 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
195 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
196 AttributeRefAttrPtr aRefAttr =
197 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
199 bool isObject = aRefAttr->isObject();
200 ObjectPtr anObject = aRefAttr->object();
201 if (isObject && anObject.get()) {
202 FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
204 AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
205 ObjectPtr aOtherObject = aOtherAttr->object();
206 FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
210 // at least one feature should be a line
211 if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
212 aOtherFea->getKind() != SketchPlugin_Line::ID()) {
213 theError = "At least one feature should be a line";
218 theError = "It uses an empty object";
225 bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
226 const std::list<std::string>& theArguments,
227 Events_InfoMessage& theError) const
229 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
230 theError = "The attribute with the %1 type is not processed";
231 theError.arg(theAttribute->attributeType());
235 std::shared_ptr<SketchPlugin_Feature> aFeature =
236 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
240 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
242 SketchPlugin_Sketch* aSketch = aFeature->sketch();
243 int aNbFeatures = aSketch->numberOfSubs();
244 for (int anInd = 0; anInd < aNbFeatures; anInd++) {
245 FeaturePtr aSubFeature = aSketch->subFeature(anInd);
246 if (aSubFeature->getKind() != SketchPlugin_ConstraintRigid::ID() || aSubFeature == aFeature)
248 AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
249 aSubFeature->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
250 if (aRefAttr->isObject()) {
251 if (aRefAttr->object() == aRAttr->object()) {
252 ObjectPtr anObject = aRefAttr->object();
253 std::string aName = anObject.get() ? anObject->data()->name() : "";
254 theError = "The object %1 has been already fixed.";
259 else if (aRefAttr->attr() == aRAttr->attr()) {
260 AttributePtr anAttribute = aRefAttr->attr();
261 std::string aName = anAttribute.get() ? anAttribute->id() : "";
262 theError = "The attribute %1 has been already fixed.";
270 bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute,
271 const std::list<std::string>& theArguments,
272 Events_InfoMessage& theError) const
274 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
275 theError = "The attribute with the %1 type is not processed";
276 theError.arg(theAttribute->attributeType());
280 std::string aParamA = theArguments.front();
281 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
282 AttributeRefAttrPtr aRefAttr[2];
283 aRefAttr[0] = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
284 aRefAttr[1] = aFeature->data()->refattr(aParamA);
286 if (!aRefAttr[0]->isObject() || !aRefAttr[1]->isObject()) {
287 theError = "Attributes can not be used in equal constraint";
291 std::string aType[2];
292 std::list<std::string> anArguments;
293 for (int i = 0; i < 2; i++) {
294 ObjectPtr anObject = aRefAttr[i]->object();
295 if (!anObject.get()) {
296 theError = "An empty object is used.";
300 aFeature = ModelAPI_Feature::feature(anObject);
301 if (!aFeature.get()) {
302 theError = "An empty feature is used.";
306 aType[i] = aFeature->getKind();
307 if (aFeature->getKind() != SketchPlugin_Line::ID() &&
308 aFeature->getKind() != SketchPlugin_Circle::ID() &&
309 aFeature->getKind() != SketchPlugin_Arc::ID() &&
310 aFeature->getKind() != SketchPlugin_Ellipse::ID()) {
311 theError = "The %1 feature is not supported by the Equal constraint.";
312 theError.arg(aFeature->getKind());
313 // wrong type of attribute
318 bool isOk = aType[0] == aType[1];
320 // circle and arc may be equal
321 isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID())
322 || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID());
325 // ellipse and elliptic arc may be equal
329 theError = "Features with kinds %1 and %2 can not be equal.";
330 theError.arg(aType[0]).arg(aType[1]);
336 bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute,
337 const std::list<std::string>& theArguments,
338 Events_InfoMessage& theError) const
340 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
341 theError = "The attribute with the %1 type is not processed";
342 theError.arg(theAttribute->attributeType());
346 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
347 AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
349 AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
350 aFeature->attribute(SketchPlugin_Constraint::ENTITY_C()));
351 std::list<ObjectPtr> aMirroredObjects = aRefListOfMirrored->list();
353 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
354 ObjectPtr aSelObject = aSelAttr->object(anInd);
355 std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
356 std::list<ObjectPtr>::iterator aMirIter = aMirroredObjects.begin();
357 for (; aMirIter != aMirroredObjects.end(); aMirIter++)
358 if (aSelObject == *aMirIter) {
359 theError = "The object %1 is a result of mirror";
367 bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
368 const std::list<std::string>& theArguments,
369 Events_InfoMessage& theError) const
371 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
372 theError = "The attribute with the %1 type is not processed";
373 theError.arg(theAttribute->attributeType());
377 // there is a check whether the feature contains a point and a linear edge or two point values
378 std::string aParamA = theArguments.front();
379 SessionPtr aMgr = ModelAPI_Session::get();
380 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
382 FeaturePtr aConstraint = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
383 AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA);
385 theError = "The %1 attribute should be %2";
386 theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId());
390 AttributeRefAttrPtr aRefAttrB =
391 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
393 // first attribute is a point, it may coincide with any object
394 if (!aRefAttrA->isObject())
397 ObjectPtr anObject = aRefAttrA->object();
398 if (!anObject.get()) {
399 theError = "%1 attribute has an empty object";
400 theError.arg(aParamA);
403 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object());
404 if (!aFeature.get()) {
405 theError = "%1 attribute has an empty feature";
406 theError.arg(aParamA);
410 if (aFeature->getKind() == SketchPlugin_Point::ID())
414 // second attribute is a point, it may coincide with any object
415 if (!aRefAttrB->isObject())
418 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object());
420 theError = "%1 attribute has an empty object";
421 theError.arg(theAttribute->id());
424 if (aFeature->getKind() == SketchPlugin_Point::ID())
427 theError = "There is no an attribute filled by a point";
432 bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute,
433 const std::list<std::string>& theArguments,
434 Events_InfoMessage& theError) const
436 if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) {
437 theError = "The attribute with the %1 type is not processed";
438 theError.arg(theAttribute->attributeType());
442 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
443 AttributeRefListPtr aSelAttr =
444 std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
446 AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
447 aFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
448 AttributeRefListPtr aRefListOfCopied = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
449 aFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
450 std::list<ObjectPtr> anInitialObjects = aRefListOfInitial->list();
451 std::list<ObjectPtr> aCopiedObjects = aRefListOfCopied->list();
453 std::list<ObjectPtr>::iterator anObjIter;
454 for(int anInd = 0; anInd < aSelAttr->size(); anInd++) {
455 ObjectPtr aSelObject = aSelAttr->object(anInd);
456 anObjIter = anInitialObjects.begin();
457 for (; anObjIter != anInitialObjects.end(); anObjIter++)
458 if (aSelObject == *anObjIter)
460 if (anObjIter != anInitialObjects.end())
462 anObjIter = aCopiedObjects.begin();
463 for (; anObjIter != aCopiedObjects.end(); anObjIter++)
464 if (aSelObject == *anObjIter) {
465 std::string aName = aSelObject.get() ? aSelObject->data()->name() : "";
466 theError = "The object %1 is a result of copy";
474 bool SketchPlugin_SolverErrorValidator::isValid(
475 const std::shared_ptr<ModelAPI_Feature>& theFeature,
476 const std::list<std::string>& theArguments,
477 Events_InfoMessage& theError) const
479 AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR());
481 if (!aAttributeString->value().empty()) {
482 theError = aAttributeString->value();
489 bool SketchPlugin_SolverErrorValidator::isNotObligatory(std::string theFeature,
490 std::string theAttribute)
495 static bool hasSameTangentFeature(const std::set<AttributePtr>& theRefsList,
496 const FeaturePtr theFeature)
498 for(std::set<AttributePtr>::const_iterator
499 anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) {
500 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
501 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
504 if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) {
505 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
506 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A()));
507 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
508 aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_B()));
509 if(anAttrRefA.get()) {
510 ResultPtr aResA = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefA->object());
512 DocumentPtr aDoc = aResA->document();
514 FeaturePtr aFeatureA = aDoc->feature(aResA);
515 if(aFeatureA.get() && aFeatureA == theFeature) {
521 if(anAttrRefB.get()) {
522 ResultPtr aResB = std::dynamic_pointer_cast<ModelAPI_Result>(anAttrRefB->object());
524 DocumentPtr aDoc = aResB->document();
526 FeaturePtr aFeatureB = aDoc->feature(aResB);
527 if(aFeatureB.get() && aFeatureB == theFeature) {
538 static bool isPointPointCoincidence(const FeaturePtr& theCoincidence)
540 AttributeRefAttrPtr aRefAttr[2] = {
541 theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()),
542 theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B())
545 bool arePoints = true;
546 for (int i = 0; i < 2 && arePoints; ++i) {
547 if (aRefAttr[i]->isObject()) {
548 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object());
549 arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID();
551 arePoints = aRefAttr[i]->attr().get() != NULL;
556 bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute,
557 const std::list<std::string>& theArguments,
558 Events_InfoMessage& theError) const
560 AttributeRefAttrPtr aPointRefAttr =
561 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
562 if(!aPointRefAttr.get()) {
563 theError = "Error: Point not selected.";
567 AttributePtr aPointAttribute = aPointRefAttr->attr();
568 if (!aPointAttribute.get()) {
569 theError = "Error: Bad point selected.";
572 std::shared_ptr<GeomAPI_Pnt2d> aSelectedPnt =
573 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aPointAttribute)->pnt();
575 // Obtain constraint coincidence for the fillet point.
576 const std::set<AttributePtr>& aRefsList = aPointAttribute->owner()->data()->refsToMe();
577 FeaturePtr aConstraintCoincidence;
578 for(std::set<AttributePtr>::const_iterator anIt = aRefsList.cbegin();
579 anIt != aRefsList.cend(); ++anIt) {
580 std::shared_ptr<ModelAPI_Attribute> aAttr = (*anIt);
581 FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
582 if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
583 if (!isPointPointCoincidence(aConstrFeature))
586 AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
587 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));
588 AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
589 aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
591 AttributePtr anAttrA = anAttrRefA->attr();
592 if(aPointAttribute == anAttrA) {
593 aConstraintCoincidence = aConstrFeature;
597 AttributePtr anAttrB = anAttrRefB->attr();
598 if(aPointAttribute == anAttrB) {
599 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(),
616 SketchPlugin_Tools::findCoincidences(aConstraintCoincidence,
617 SketchPlugin_ConstraintCoincidence::ENTITY_B(),
621 // Remove points and external lines from set of coincides.
622 std::set<FeaturePtr> aNewSetOfCoincides;
623 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
624 anIt != aCoinsides.end(); ++anIt) {
625 std::shared_ptr<SketchPlugin_SketchEntity> aSketchEntity =
626 std::dynamic_pointer_cast<SketchPlugin_SketchEntity>(*anIt);
627 if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) {
630 if((*anIt)->getKind() != SketchPlugin_Line::ID() &&
631 (*anIt)->getKind() != SketchPlugin_Arc::ID()) {
634 if((*anIt)->getKind() == SketchPlugin_Arc::ID()) {
635 AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID());
636 std::shared_ptr<GeomAPI_Pnt2d> anArcCenterPnt =
637 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anArcCenter)->pnt();
638 double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt);
639 if(aDistSelectedArcCenter < tolerance) {
643 aNewSetOfCoincides.insert(*anIt);
645 aCoinsides = aNewSetOfCoincides;
647 // If we still have more than two coincides remove auxilary entities from set of coincides.
648 if(aCoinsides.size() > 2) {
649 aNewSetOfCoincides.clear();
650 for(std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
651 anIt != aCoinsides.end(); ++anIt) {
652 if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) {
653 aNewSetOfCoincides.insert(*anIt);
656 aCoinsides = aNewSetOfCoincides;
659 if(aCoinsides.size() != 2) {
660 theError = "Error: One of the selected points does not have two suitable edges for fillet.";
664 // Check that selected edges don't have tangent constraint.
665 std::set<FeaturePtr>::iterator anIt = aCoinsides.begin();
666 FeaturePtr aFirstFeature = *anIt++;
667 FeaturePtr aSecondFeature = *anIt;
668 const std::set<AttributePtr>& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe();
669 if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) {
670 theError = "Error: Edges in selected point has tangent constraint.";
674 std::list<ResultPtr> aFirstResults = aFirstFeature->results();
675 for(std::list<ResultPtr>::iterator aResIt = aFirstResults.begin();
676 aResIt != aFirstResults.end(); ++aResIt) {
677 ResultPtr aRes = *aResIt;
678 const std::set<AttributePtr>& aResRefsList = aRes->data()->refsToMe();
679 if(hasSameTangentFeature(aResRefsList, aSecondFeature)) {
680 theError = "Error: Edges in selected point has tangent constraint.";
685 // Check the features are not tangent
686 std::shared_ptr<GeomAPI_Shape> aFirstShape = aFirstFeature->lastResult()->shape();
687 std::shared_ptr<GeomAPI_Shape> aSecondShape = aSecondFeature->lastResult()->shape();
688 if (!aFirstShape || !aFirstShape->isEdge() ||
689 !aSecondShape || !aSecondShape->isEdge()) {
690 theError = "Error: At least on of the features is not an edge";
694 std::shared_ptr<GeomAPI_Edge> anEdge1 = std::dynamic_pointer_cast<GeomAPI_Edge>(aFirstShape);
695 std::shared_ptr<GeomAPI_Edge> anEdge2 = std::dynamic_pointer_cast<GeomAPI_Edge>(aSecondShape);
697 static const double TOL = 1.e-7;
698 if (anEdge1->isLine() && anEdge2->isLine()) {
699 // Check that lines not collinear
700 std::shared_ptr<GeomAPI_Dir> aDir1 = anEdge1->line()->direction();
701 std::shared_ptr<GeomAPI_Dir> aDir2 = anEdge2->line()->direction();
702 double aCross = aDir1->cross(aDir2)->squareModulus();
703 if (aCross < TOL * TOL)
705 } else if (anEdge1->isArc() && anEdge2->isArc()) {
706 // check the circles are not tangent
707 std::shared_ptr<GeomAPI_Circ> aCirc1 = anEdge1->circle();
708 std::shared_ptr<GeomAPI_Circ> aCirc2 = anEdge2->circle();
709 double aDistCC = aCirc1->center()->distance(aCirc2->center());
710 double aRadSum = aCirc1->radius() + aCirc2->radius();
711 double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius());
712 if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL)
715 // check whether line and arc are tangent
716 std::shared_ptr<GeomAPI_Circ> aCirc;
717 std::shared_ptr<GeomAPI_Lin> aLine;
718 if (anEdge1->isLine()) {
719 aLine = anEdge1->line();
720 aCirc = anEdge2->circle();
722 aCirc = anEdge1->circle();
723 aLine = anEdge2->line();
726 double aDistCL = aLine->distance(aCirc->center());
727 if (fabs(aDistCL - aCirc->radius()) < TOL)
734 bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
735 const std::list<std::string>& theArguments,
736 Events_InfoMessage& theError) const
738 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
739 theError = "The attribute with the %1 type is not processed";
740 theError.arg(theAttribute->attributeType());
744 // there is a check whether the feature contains a point and a linear edge or two point values
745 std::string aParamA = theArguments.front();
746 SessionPtr aMgr = ModelAPI_Session::get();
747 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
749 FeaturePtr anAttributeFeature =
750 std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
751 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
752 AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
754 AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
757 for (int i = 0; i < 2; ++i) {
758 if (!aRefAttrs[i]->isObject())
761 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
763 if (aNbPoints + aNbLines != 0)
768 if (aFeature->getKind() == SketchPlugin_Point::ID())
770 else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
771 aFeature->getKind() == SketchPlugin_Arc::ID())
776 if (aNbPoints != 1 || aNbLines != 1) {
777 theError = "Middle point constraint allows points and lines only";
783 bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute,
784 const std::list<std::string>& /*theArguments*/,
785 Events_InfoMessage& theError) const
787 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
788 theError = "The attribute with the %1 type is not processed";
789 theError.arg(theAttribute->attributeType());
792 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
793 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
794 if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE())
795 return true; // not applicable for non-tangent arcs
797 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
798 AttributePtr anAttr = aRefAttr->attr();
800 theError = "The attribute %1 should be a point";
801 theError.arg(theAttribute->id());
805 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
806 const std::string& aFeatureType = anAttrFeature->getKind();
807 if (aFeatureType == SketchPlugin_Arc::ID()) {
808 // selected point should not be a center of arc
809 const std::string& aPntId = anAttr->id();
810 if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) {
811 theError = "The attribute %1 is not supported";
812 theError.arg(aPntId);
816 else if (aFeatureType == SketchPlugin_Line::ID()) {
817 // selected point should be bound point of line
818 const std::string& aPntId = anAttr->id();
819 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
820 theError = "The attribute %1 is not supported";
821 theError.arg(aPntId);
826 theError = "Unable to build tangent arc on %1";
827 theError.arg(anAttrFeature->getKind());
834 bool SketchPlugin_ArcTransversalPointValidator::isValid(
835 const AttributePtr& theAttribute,
836 const std::list<std::string>& /*theArguments*/,
837 Events_InfoMessage& theError) const
839 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
840 theError = "The attribute with the %1 type is not processed";
841 theError.arg(theAttribute->attributeType());
844 FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
845 AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE());
847 anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE())
848 return true; // not applicable for non-transversal arcs
850 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
851 AttributePtr anAttr = aRefAttr->attr();
853 theError = "The attribute %1 should be a point";
854 theError.arg(theAttribute->id());
858 FeaturePtr anAttrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anAttr->owner());
859 const std::string& aFeatureType = anAttrFeature->getKind();
860 if (aFeatureType == SketchPlugin_Line::ID()) {
861 // selected point should be bound point of line
862 const std::string& aPntId = anAttr->id();
863 if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) {
864 theError = "The attribute %1 is not supported";
865 theError.arg(aPntId);
870 theError = "Unable to build transversal arc on %1";
871 theError.arg(anAttrFeature->getKind());
878 bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
879 const std::list<std::string>& theArguments,
880 Events_InfoMessage& theError) const
882 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
883 theError = "The attribute with the %1 type is not processed";
884 theError.arg(theAttribute->attributeType());
887 AttributeSelectionPtr anExternalAttr =
888 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
889 std::shared_ptr<GeomAPI_Edge> anEdge;
890 if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) {
891 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->value()));
892 } else if(anExternalAttr->context() && anExternalAttr->context()->shape() &&
893 anExternalAttr->context()->shape()->isEdge()) {
894 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(anExternalAttr->context()->shape()));
898 theError = "The attribute %1 should be an edge";
899 theError.arg(theAttribute->id());
904 std::shared_ptr<SketchPlugin_Sketch> aSketch;
905 std::set<AttributePtr> aRefs = anExternalAttr->owner()->data()->refsToMe();
906 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
907 for (; anIt != aRefs.end(); ++anIt) {
908 CompositeFeaturePtr aComp =
909 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
910 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
911 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
916 theError = "There is no sketch referring to the current feature";
920 // check the edge is intersected with sketch plane
921 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
923 std::list<GeomPointPtr> anIntersectionsPoints;
924 anEdge->intersectWithPlane(aPlane, anIntersectionsPoints);
925 if (anIntersectionsPoints.empty()) {
926 theError = "The edge is not intersected with sketch plane";
932 bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute,
933 const std::list<std::string>& theArguments,
934 Events_InfoMessage& theError) const
938 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
939 theError = "The attribute with the %1 type is not processed";
940 theError.arg(theAttribute->attributeType());
943 AttributeReferencePtr aFeatureAttr =
944 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
946 ObjectPtr anAttrObject = aFeatureAttr->value();
947 FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject);
951 std::string aKind = anAttrFeature->getKind();
952 if (aKind == SketchPlugin_Line::ID() ||
953 aKind == SketchPlugin_Arc::ID() ||
954 aKind == SketchPlugin_Circle::ID()) {
956 std::set<ResultPtr> anEdgeShapes;
957 ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
958 if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/)
961 // coincidences to the feature
962 std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
963 ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
964 SketchPlugin_ConstraintCoincidence::ID(),
965 aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
967 GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
968 std::shared_ptr<SketchPlugin_Feature> aSFeature =
969 std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
970 SketchPlugin_Sketch* aSketch = aSFeature->sketch();
972 std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
973 std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
974 aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
975 std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
976 aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
977 std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
978 aData->attribute(SketchPlugin_Sketch::NORM_ID()));
979 std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
981 typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
982 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
983 std::list<std::shared_ptr<ModelAPI_Object> > > > PointToRefsMap;
984 PointToRefsMap aPointsInfo;
986 ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(),
987 aX->dir(), aDirY, aPointsInfo);
988 int aCoincidentToFeature = (int)aPointsInfo.size();
989 if (aKind == SketchPlugin_Circle::ID())
990 aValid = aCoincidentToFeature >= 2;
992 aValid = aCoincidentToFeature >= 1;
998 bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute,
999 const std::list<std::string>& theArguments,
1000 Events_InfoMessage& theError) const
1002 bool aValid = false;
1004 if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1005 theError = "The attribute with the %1 type is not processed";
1006 theError.arg(theAttribute->attributeType());
1009 AttributeReferencePtr aBaseObjectAttr =
1010 std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
1012 std::shared_ptr<SketchPlugin_Feature> aTrimFeature =
1013 std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
1015 ObjectPtr aBaseObject = aBaseObjectAttr->value();
1017 AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
1018 aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(aPreviewAttr);
1019 aBaseObject = aBaseObjectAttr->value();
1022 FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1026 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1027 std::dynamic_pointer_cast<SketchPlugin_Feature>(aBaseFeature);
1028 if (!aSketchFeature.get() || aSketchFeature->isCopy())
1031 std::string aKind = aBaseFeature->getKind();
1032 if (aKind != SketchPlugin_Line::ID() &&
1033 aKind != SketchPlugin_Arc::ID() &&
1034 aKind != SketchPlugin_Circle::ID())
1038 AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1039 aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
1041 SketchPlugin_Sketch* aSketch = aTrimFeature->sketch();
1043 std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1044 std::shared_ptr<GeomAPI_Pnt> anAttributePnt = aSketch->to3D(anAttributePnt2d->x(),
1045 anAttributePnt2d->y());
1047 std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
1048 std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
1049 std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
1050 std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
1051 SketchPlugin_Trim::fillObjectShapes(aBaseObject, aSketch->data()->owner(),
1052 aCashedShapes, anObjectToPoints);
1053 const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
1055 return aShapes.size() > 1;
1058 bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute,
1059 const std::list<std::string>& theArguments,
1060 Events_InfoMessage& theError) const
1062 if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) {
1063 theError = "The attribute with the %1 type is not processed";
1064 theError.arg(theAttribute->attributeType());
1068 AttributeSelectionPtr aFeatureAttr =
1069 std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
1070 std::shared_ptr<GeomAPI_Edge> anEdge;
1071 std::shared_ptr<SketchPlugin_Feature> aSketchFeature;
1072 if (aFeatureAttr.get()) {
1073 GeomShapePtr aVal = aFeatureAttr->value();
1074 ResultPtr aRes = aFeatureAttr->context();
1075 if (aVal && aVal->isVertex())
1076 return true; // vertex is always could be projected
1077 if (aVal && aVal->isEdge()) {
1078 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->value()));
1079 } else if(aRes && aRes->shape()) {
1080 if (aRes->shape()->isVertex())
1081 return true; // vertex is always could be projected
1082 else if (aRes->shape()->isEdge())
1083 anEdge = std::shared_ptr<GeomAPI_Edge>(new GeomAPI_Edge(aFeatureAttr->context()->shape()));
1086 // try to convert result to sketch feature
1089 std::dynamic_pointer_cast<SketchPlugin_Feature>(ModelAPI_Feature::feature(aRes));
1093 theError = "The attribute %1 should be an edge or vertex";
1094 theError.arg(theAttribute->id());
1099 std::shared_ptr<SketchPlugin_Sketch> aSketch;
1100 std::set<AttributePtr> aRefs = theAttribute->owner()->data()->refsToMe();
1101 std::set<AttributePtr>::const_iterator anIt = aRefs.begin();
1102 for (; anIt != aRefs.end(); ++anIt) {
1103 CompositeFeaturePtr aComp =
1104 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*anIt)->owner());
1105 if (aComp && aComp->getKind() == SketchPlugin_Sketch::ID()) {
1106 aSketch = std::dynamic_pointer_cast<SketchPlugin_Sketch>(aComp);
1111 theError = "There is no sketch referring to the current feature";
1114 if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) {
1115 theError = "Unable to project feature from the same sketch";
1119 std::shared_ptr<GeomAPI_Pln> aPlane = aSketch->plane();
1120 std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
1121 std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
1123 if (anEdge->isLine()) {
1124 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1125 std::shared_ptr<GeomAPI_Dir> aLineDir = aLine->direction();
1126 double aDot = fabs(aNormal->dot(aLineDir));
1127 bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance;
1129 theError = "Error: Line is orthogonal to the sketch plane.";
1132 else if (anEdge->isCircle() || anEdge->isArc()) {
1133 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1134 std::shared_ptr<GeomAPI_Dir> aCircNormal = aCircle->normal();
1135 double aDot = fabs(aNormal->dot(aCircNormal));
1136 bool aValid = aDot >= tolerance * tolerance;
1138 theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane."
1139 : "Error: Arc is orthogonal to the sketch plane.");
1142 else if (anEdge->isEllipse()) {
1143 std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
1144 std::shared_ptr<GeomAPI_Dir> anEllipseNormal = anEllipse->normal();
1145 double aDot = fabs(aNormal->dot(anEllipseNormal));
1146 bool aValid = aDot >= tolerance * tolerance;
1148 theError.arg(anEdge->isEllipse() ? "Error: Ellipse is orthogonal to the sketch plane."
1149 : "Error: Elliptic Arc is orthogonal to the sketch plane.");
1153 theError = "Error: Selected object is not line, circle or arc.";
1158 static std::set<FeaturePtr> common(const std::set<FeaturePtr>& theSet1,
1159 const std::set<FeaturePtr>& theSet2)
1161 std::set<FeaturePtr> aCommon;
1162 if (theSet1.empty() || theSet2.empty())
1165 std::set<FeaturePtr>::const_iterator anIt2 = theSet2.begin();
1166 for (; anIt2 != theSet2.end(); ++anIt2)
1167 if (theSet1.find(*anIt2) != theSet1.end())
1168 aCommon.insert(*anIt2);
1172 bool SketchPlugin_DifferentReferenceValidator::isValid(
1173 const AttributePtr& theAttribute,
1174 const std::list<std::string>& theArguments,
1175 Events_InfoMessage& theError) const
1177 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1179 int aNbFeaturesReferred = 0;
1180 int aNbAttributesReferred = 0;
1181 std::set<FeaturePtr> aCommonReferredFeatures;
1183 // find all features referred by attributes listed in theArguments
1184 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1185 for (; anArgIt != theArguments.end(); ++anArgIt) {
1186 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1190 std::set<FeaturePtr> aCoincidentFeatures;
1191 if (aRefAttr->isObject()) {
1192 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1194 aCoincidentFeatures.insert(aFeature);
1195 aNbFeaturesReferred += 1;
1198 AttributePoint2DPtr aPoint =
1199 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1201 aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint);
1202 aNbAttributesReferred += 1;
1206 if (aCommonReferredFeatures.empty())
1207 aCommonReferredFeatures = aCoincidentFeatures;
1209 aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures);
1211 if (aCommonReferredFeatures.empty())
1215 bool isOk = aNbFeaturesReferred < 1;
1216 if (aNbFeaturesReferred == 1) {
1217 if (aCommonReferredFeatures.size() == 1) {
1218 FeaturePtr aFeature = *aCommonReferredFeatures.begin();
1219 isOk = aNbAttributesReferred <= 1 ||
1220 aFeature->getKind() == SketchPlugin_Circle::ID() ||
1221 aFeature->getKind() == SketchPlugin_Arc::ID();
1227 theError = "Attributes are referred to the same feature";
1231 bool SketchPlugin_DifferentPointReferenceValidator::isValid(
1232 const AttributePtr& theAttribute,
1233 const std::list<std::string>& theArguments,
1234 Events_InfoMessage& theError) const
1236 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1237 std::set<AttributePoint2DPtr> aReferredCoincidentPoints;
1239 // find all points referred by attributes listed in theArguments
1240 bool hasRefsToPoints = false;
1241 std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1242 for (; anArgIt != theArguments.end(); ++anArgIt) {
1243 AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt);
1247 if (!aRefAttr->isObject()) {
1248 AttributePoint2DPtr aPoint =
1249 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1250 if (aReferredCoincidentPoints.empty())
1251 aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint);
1252 else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end())
1253 return true; // non-coincident point has been found
1255 hasRefsToPoints = true;
1259 if (hasRefsToPoints)
1260 theError = "Attributes are referred to the same point";
1261 return !hasRefsToPoints;
1264 bool SketchPlugin_CirclePassedPointValidator::isValid(
1265 const AttributePtr& theAttribute,
1266 const std::list<std::string>&,
1267 Events_InfoMessage& theError) const
1269 static const std::string aErrorMessage(
1270 "Passed point refers to the same feature as a center point");
1272 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1274 AttributeRefAttrPtr aCenterRef =
1275 anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID());
1276 AttributeRefAttrPtr aPassedRef =
1277 anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID());
1279 if (!aPassedRef->isObject())
1282 FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object());
1283 if (!aPassedFeature)
1286 if (aCenterRef->isObject()) {
1287 if (aCenterRef->object() == aPassedRef->object()) {
1288 theError = aErrorMessage;
1292 AttributePoint2DPtr aCenterPoint =
1293 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aCenterRef->attr());
1295 std::set<FeaturePtr> aCoincidentFeatures =
1296 SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint);
1297 // check one of coincident features is a feature referred by passed point
1298 std::set<FeaturePtr>::const_iterator anIt = aCoincidentFeatures.begin();
1299 for(; anIt != aCoincidentFeatures.end(); ++anIt)
1300 if (*anIt == aPassedFeature) {
1301 theError = aErrorMessage;
1309 bool SketchPlugin_ThirdPointValidator::isValid(
1310 const AttributePtr& theAttribute,
1311 const std::list<std::string>& theArguments,
1312 Events_InfoMessage& theError) const
1314 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
1315 return arePointsNotOnLine(anOwner, theError) &&
1316 arePointsNotSeparated(anOwner, theArguments, theError);
1319 static std::shared_ptr<GeomAPI_Pnt2d> toPoint(const FeaturePtr& theMacroCircle,
1320 const std::string& thePointAttrName,
1321 const std::string& theRefPointAttrName)
1323 AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1324 theMacroCircle->attribute(thePointAttrName));
1325 AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName);
1327 std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
1329 if (aRefAttr->isObject()) {
1330 // project a point onto selected feature
1331 std::shared_ptr<SketchPlugin_Feature> aFeature =
1332 std::dynamic_pointer_cast<SketchPlugin_Feature>(
1333 ModelAPI_Feature::feature(aRefAttr->object()));
1335 SketchPlugin_Sketch* aSketch = aFeature->sketch();
1336 std::shared_ptr<GeomAPI_Edge> anEdge =
1337 std::dynamic_pointer_cast<GeomAPI_Edge>(aFeature->lastResult()->shape());
1339 std::shared_ptr<GeomAPI_Pnt> aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y());
1340 if (anEdge->isLine())
1341 aPoint3D = anEdge->line()->project(aPoint3D);
1342 else if (anEdge->isCircle())
1343 aPoint3D = anEdge->circle()->project(aPoint3D);
1345 aPoint = aSketch->to2D(aPoint3D);
1349 AttributePoint2DPtr anOtherPoint =
1350 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
1352 aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it
1359 static void threePointsOfFeature(const FeaturePtr& theMacroFeature,
1360 std::shared_ptr<GeomAPI_Pnt2d> thePoints[3])
1362 if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) {
1363 thePoints[0] = toPoint(theMacroFeature,
1364 SketchPlugin_MacroCircle::FIRST_POINT_ID(),
1365 SketchPlugin_MacroCircle::FIRST_POINT_REF_ID());
1366 thePoints[1] = toPoint(theMacroFeature,
1367 SketchPlugin_MacroCircle::SECOND_POINT_ID(),
1368 SketchPlugin_MacroCircle::SECOND_POINT_REF_ID());
1369 thePoints[2] = toPoint(theMacroFeature,
1370 SketchPlugin_MacroCircle::THIRD_POINT_ID(),
1371 SketchPlugin_MacroCircle::THIRD_POINT_REF_ID());
1372 } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) {
1373 thePoints[0] = toPoint(theMacroFeature,
1374 SketchPlugin_MacroArc::START_POINT_2_ID(),
1375 SketchPlugin_MacroArc::START_POINT_REF_ID());
1376 thePoints[1] = toPoint(theMacroFeature,
1377 SketchPlugin_MacroArc::END_POINT_2_ID(),
1378 SketchPlugin_MacroArc::END_POINT_REF_ID());
1379 thePoints[2] = toPoint(theMacroFeature,
1380 SketchPlugin_MacroArc::PASSED_POINT_ID(),
1381 SketchPlugin_MacroArc::PASSED_POINT_REF_ID());
1385 static bool isPointsOnLine(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint1,
1386 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint2,
1387 const std::shared_ptr<GeomAPI_Pnt2d>& thePoint3)
1389 static const double aTolerance = 1.e-7;
1390 if (thePoint1->distance(thePoint2) < aTolerance ||
1391 thePoint1->distance(thePoint3) < aTolerance)
1394 std::shared_ptr<GeomAPI_Dir2d> aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(),
1395 thePoint2->y() - thePoint1->y()));
1396 std::shared_ptr<GeomAPI_Dir2d> aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(),
1397 thePoint3->y() - thePoint1->y()));
1398 return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance;
1401 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Lin>& theLine,
1402 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1403 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1405 static const double aTolerance = 1.e-7;
1406 std::shared_ptr<GeomAPI_Dir> aLineDir = theLine->direction();
1407 std::shared_ptr<GeomAPI_XYZ> aLineLoc = theLine->location()->xyz();
1409 std::shared_ptr<GeomAPI_XYZ> aVec1 = thePoint1->xyz()->decreased(aLineLoc);
1410 // the first point is on the line
1411 if (aVec1->squareModulus() < aTolerance * aTolerance)
1413 std::shared_ptr<GeomAPI_Dir> aDirP1L(new GeomAPI_Dir(aVec1));
1414 std::shared_ptr<GeomAPI_XYZ> aVec2 = thePoint2->xyz()->decreased(aLineLoc);
1415 // the second point is on the line
1416 if (aVec2->squareModulus() < aTolerance * aTolerance)
1418 std::shared_ptr<GeomAPI_Dir> aDirP2L(new GeomAPI_Dir(aVec2));
1420 return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance;
1423 static bool isOnSameSide(const std::shared_ptr<GeomAPI_Circ>& theCircle,
1424 const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
1425 const std::shared_ptr<GeomAPI_Pnt>& thePoint2)
1427 static const double aTolerance = 1.e-7;
1428 std::shared_ptr<GeomAPI_Pnt> aCenter = theCircle->center();
1429 double aDistP1C = thePoint1->distance(aCenter);
1430 double aDistP2C = thePoint2->distance(aCenter);
1431 return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance;
1434 bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine(
1435 const FeaturePtr& theMacroFeature,
1436 Events_InfoMessage& theError) const
1438 static const std::string aErrorPointsOnLine(
1439 "Selected points are on the same line");
1441 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1442 threePointsOfFeature(theMacroFeature, aPoints);
1444 if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) {
1445 theError = aErrorPointsOnLine;
1451 bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated(
1452 const FeaturePtr& theMacroFeature,
1453 const std::list<std::string>& theArguments,
1454 Events_InfoMessage& theError) const
1456 static const std::string aErrorPointsApart(
1457 "Selected entity is lying between first two points");
1459 AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front());
1460 FeaturePtr aRefByThird;
1461 if (aThirdPointRef->isObject())
1462 aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object());
1466 std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
1467 threePointsOfFeature(theMacroFeature, aPoints);
1469 std::shared_ptr<GeomAPI_Edge> aThirdShape =
1470 std::dynamic_pointer_cast<GeomAPI_Edge>(aRefByThird->lastResult()->shape());
1474 SketchPlugin_Sketch* aSketch =
1475 std::dynamic_pointer_cast<SketchPlugin_Feature>(theMacroFeature)->sketch();
1476 std::shared_ptr<GeomAPI_Pnt> aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y());
1477 std::shared_ptr<GeomAPI_Pnt> aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y());
1480 if (aThirdShape->isLine())
1481 isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D);
1482 else if (aThirdShape->isCircle() || aThirdShape->isArc())
1483 isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D);
1486 theError = aErrorPointsApart;
1490 bool SketchPlugin_ArcEndPointValidator::isValid(
1491 const AttributePtr& theAttribute,
1492 const std::list<std::string>& theArguments,
1493 Events_InfoMessage& theError) const
1495 FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
1496 AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front());
1498 if(!anEndPointRef.get()) {
1502 ObjectPtr anObject = anEndPointRef->object();
1503 AttributePtr anAttr = anEndPointRef->attr();
1504 if(!anObject.get() && !anAttr.get()) {
1508 if(anEndPointRef->attr().get()) {
1512 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1514 GeomShapePtr aShape = aResult->shape();
1515 if(aShape.get() && aShape->isVertex()) {
1520 aFeature = ModelAPI_Feature::feature(anObject);
1521 if(aFeature.get()) {
1522 if(aFeature->getKind() == SketchPlugin_Point::ID()) {
1530 static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape)
1532 if(!theShape.get()) {
1536 if(!theShape->isEdge()) {
1540 std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(theShape));
1546 if(anEdge->isLine()) {
1547 std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
1548 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine);
1552 if(anEdge->isCircle() || anEdge->isArc()) {
1553 std::shared_ptr<GeomAPI_Circ> aCircle = anEdge->circle();
1554 GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle);
1561 bool SketchPlugin_ArcEndPointIntersectionValidator::isValid(
1562 const AttributePtr& theAttribute,
1563 const std::list<std::string>& theArguments,
1564 Events_InfoMessage& theError) const
1566 std::shared_ptr<SketchPlugin_MacroArc> anArcFeature =
1567 std::dynamic_pointer_cast<SketchPlugin_MacroArc>(theAttribute->owner());
1568 AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front());
1570 if(!anEndPointRef.get()) {
1574 GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false));
1576 if(!anArcShape.get() || anArcShape->isNull()) {
1580 ObjectPtr anObject = anEndPointRef->object();
1581 AttributePtr anAttr = anEndPointRef->attr();
1582 if(!anObject.get() && !anAttr.get()) {
1586 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
1588 GeomShapePtr aShape = aResult->shape();
1589 if (!aShape->isEdge())
1591 aShape = toInfiniteEdge(aShape);
1592 if(aShape.get() && !aShape->isNull()) {
1593 if(anArcShape->isIntersect(aShape)) {
1599 FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject);
1600 if(aSelectedFeature.get()) {
1601 std::list<ResultPtr> aResults = aSelectedFeature->results();
1602 for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin();
1603 anIt != aResults.cend();
1606 GeomShapePtr aShape = (*anIt)->shape();
1607 if (!aShape->isEdge())
1609 aShape = toInfiniteEdge(aShape);
1610 if(aShape.get() && !aShape->isNull()) {
1611 if(anArcShape->isIntersect(aShape)) {
1621 bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute,
1622 const std::list<std::string>& theArguments,
1623 Events_InfoMessage& theError) const
1625 std::set<std::string> aFeatureKinds;
1626 for (std::list<std::string>::const_iterator anArgIt = theArguments.begin();
1627 anArgIt != theArguments.end(); anArgIt++) {
1628 aFeatureKinds.insert(*anArgIt);
1631 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1632 theError = "The attribute with the %1 type is not processed";
1633 theError.arg(theAttribute->attributeType());
1637 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
1639 bool isObject = aRefAttr->isObject();
1641 theError = "It uses an empty object";
1644 ObjectPtr anObject = aRefAttr->object();
1645 FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
1646 if (!aFeature.get()) {
1647 theError = "The feature of the checked attribute is empty";
1651 FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner());
1653 std::set<AttributePtr> aRefsList = anObject->data()->refsToMe();
1654 std::set<AttributePtr>::const_iterator anIt = aRefsList.begin();
1655 for (; anIt != aRefsList.end(); anIt++) {
1656 FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner());
1657 if (aRefFeature.get() && aCurrentFeature != aRefFeature &&
1658 aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end())
1659 return false; // constraint is found, that means that the check is not valid
1664 bool SketchPlugin_ReplicationReferenceValidator::isValid(
1665 const AttributePtr& theAttribute,
1666 const std::list<std::string>& theArguments,
1667 Events_InfoMessage& theError) const
1669 AttributeRefAttrPtr aRefAttr =
1670 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1673 theError = "Incorrect attribute";
1678 if (aRefAttr->isObject())
1679 anOwner = aRefAttr->object();
1682 AttributePtr anAttr = aRefAttr->attr();
1683 anOwner = anAttr->owner();
1685 FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner);
1686 if (!anAttrOwnerFeature)
1688 AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID());
1689 if (!aCopyAttr || !aCopyAttr->value())
1690 return true; // feature is not a copy, thus valid
1692 // check the copy feature is already referred by the "Multi" feature
1693 FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner());
1694 AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front());
1695 for (int i = 0; i < aRefList->size(); ++i)
1697 FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i));
1698 if (aRefOwner == anAttrOwnerFeature)
1700 theError = "Attribute refers to the object generated by this feature";
1708 bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute,
1709 const std::list<std::string>& theArguments,
1710 Events_InfoMessage& theError) const
1712 if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
1713 theError = "The attribute with the %1 type is not processed";
1714 theError.arg(theAttribute->attributeType());
1718 // check the attribute refers to a sketch feature
1719 AttributeRefAttrPtr aRefAttr =
1720 std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
1721 bool isSketchFeature = aRefAttr->isObject();
1722 if (isSketchFeature) {
1723 FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1724 isSketchFeature = aFeature.get() != NULL;
1725 if (isSketchFeature) {
1726 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1727 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
1728 isSketchFeature = aSketchFeature.get() != NULL;
1732 if (isSketchFeature)
1735 theError = "The object selected is not a sketch feature";
1739 bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute,
1740 const std::list<std::string>& theArguments,
1741 Events_InfoMessage& theError) const
1743 if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) {
1744 theError = "The attribute with the %1 type is not processed";
1745 theError.arg(theAttribute->attributeType());
1749 AttributeDoublePtr anAngleAttr =
1750 std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
1752 FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner());
1753 AttributeStringPtr anAngleType =
1754 aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
1755 AttributeIntegerPtr aNbCopies =
1756 aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID());
1758 if (anAngleType->value() != "FullAngle")
1760 double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1);
1761 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999)
1763 theError = "Rotation single angle should produce full angle less than 360 degree";
1769 double aFullAngleValue = anAngleAttr->value();
1770 if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001)
1772 theError = "Rotation full angle should be in range [0, 360]";