X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Validators.cpp;h=cf8d1ca4a65a7b2fc421b5ec8a8955178ed9fca3;hb=7b9662e1e63565ccfb95255f2b154d53357d091e;hp=a2f1f27ca19f965aae074ae9da65c5f2a9f158a6;hpb=687e742a02e9155bb210db40eef61f27da4995db;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp old mode 100755 new mode 100644 index a2f1f27ca..cf8d1ca4a --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1,8 +1,21 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_Validators.cpp -// Created: 01 Aug 2014 -// Author: Vitaly SMETANNIKOV +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include "SketchPlugin_Validators.h" @@ -10,45 +23,64 @@ #include "SketchPlugin_Circle.h" #include "SketchPlugin_ConstraintCoincidence.h" #include "SketchPlugin_ConstraintDistance.h" -#include "SketchPlugin_ConstraintFillet.h" #include "SketchPlugin_ConstraintRigid.h" #include "SketchPlugin_ConstraintTangent.h" +#include "SketchPlugin_Ellipse.h" +#include "SketchPlugin_EllipticArc.h" +#include "SketchPlugin_Fillet.h" #include "SketchPlugin_Line.h" +#include "SketchPlugin_MacroArc.h" +#include "SketchPlugin_MacroCircle.h" +#include "SketchPlugin_MultiRotation.h" #include "SketchPlugin_Point.h" #include "SketchPlugin_Sketch.h" +#include "SketchPlugin_Trim.h" #include "SketchPlugin_Tools.h" #include "SketcherPrs_Tools.h" +#include + #include #include #include +#include #include - -#include #include #include #include #include +#include #include +#include +#include + +#include +#include + #include +#include +#include #include #include #include + #include +#include #include #include const double tolerance = 1.e-7; -bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -57,7 +89,8 @@ bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribut SessionPtr aMgr = ModelAPI_Session::get(); ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast + (theAttribute); bool isObject = aRefAttr->isObject(); if (!isObject) { // an attribute is a point. A point value is valid always for the distance @@ -66,21 +99,22 @@ bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribut // 1. check whether the references object is a linear ObjectPtr anObject = aRefAttr->object(); - const ModelAPI_AttributeValidator* aShapeValidator = - dynamic_cast(aFactory->validator("GeomValidators_ShapeType")); + const ModelAPI_AttributeValidator* aShapeValidator = + dynamic_cast( + aFactory->validator("GeomValidators_ShapeType")); std::list anArguments; anArguments.push_back("circle"); - std::string aCircleError; + Events_InfoMessage aCircleError; bool aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aCircleError); // the circle line is not a valid case if (aShapeValid) { theError = "Circle can not be used in distance constraint"; return false; } - + anArguments.clear(); anArguments.push_back("line"); - std::string aLineError; + Events_InfoMessage aLineError; aShapeValid = aShapeValidator->isValid(aRefAttr, anArguments, aLineError); // if the attribute value is not a line, that means it is a vertex. A vertex is always valid if (aShapeValid) { @@ -101,111 +135,87 @@ bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribut return true; } - -static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2) +bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const { - FeaturePtr aConstrFeature; - std::list anAttrList; - if (theFeature1->getKind() == SketchPlugin_Circle::ID() || - theFeature2->getKind() == SketchPlugin_Circle::ID()) + if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; - if (theFeature2->getKind() == SketchPlugin_Line::ID()) { - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID())); - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID())); - } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) { - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID())); - anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID())); } - const std::set& aRefsList = theFeature1->data()->refsToMe(); - std::set::const_iterator aRefIt = aRefsList.begin(); - for (; aRefIt != aRefsList.end(); ++aRefIt) { - aConstrFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); - if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) - continue; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); - AttributePtr anAttr = aRefAttr->attr(); - if (anAttr->id() == SketchPlugin_Arc::CENTER_ID()) - continue; + // there is a check whether the feature contains a point and a linear edge or two point values + std::string aParamA = theArguments.front(); + SessionPtr aMgr = ModelAPI_Session::get(); + ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()); - if (anAttr == *aRefIt) - anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()); + FeaturePtr anAttributeFeature = + std::dynamic_pointer_cast(theAttribute->owner()); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); - aRefAttr = std::dynamic_pointer_cast(anAttr); - if (!aRefAttr) - continue; - anAttr = aRefAttr->attr(); - for (std::list::const_iterator anIt = anAttrList.begin(); - anIt != anAttrList.end(); ++anIt) - if (*anIt == anAttr) - return true; + bool isObject = aRefAttr->isObject(); + ObjectPtr anObject = aRefAttr->object(); + if (isObject && anObject.get()) { + FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject); + + AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA); + ObjectPtr aOtherObject = aOtherAttr->object(); + FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject); + if (!aOtherFea) + return true; + + if (aRefFea->getKind() == SketchPlugin_Line::ID() && + aOtherFea->getKind() == SketchPlugin_Line::ID()) { + theError = "Two segments cannot be tangent"; + return false; + } + return true; } - return false; + else { + theError = "It uses an empty object"; + return false; + } + + return true; } -bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, - const std::list& theArguments, - std::string& theError) const +bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } - // there is a check whether the feature contains a point and a linear edge or two point values std::string aParamA = theArguments.front(); SessionPtr aMgr = ModelAPI_Session::get(); ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - FeaturePtr anAttributeFeature = std::dynamic_pointer_cast(theAttribute->owner()); - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + FeaturePtr anOwner = std::dynamic_pointer_cast(theAttribute->owner()); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); bool isObject = aRefAttr->isObject(); ObjectPtr anObject = aRefAttr->object(); if (isObject && anObject.get()) { FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject); - AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA); + AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA); ObjectPtr aOtherObject = aOtherAttr->object(); FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject); if (!aOtherFea) return true; - if ((aRefFea->getKind() == SketchPlugin_Arc::ID() || - aOtherFea->getKind() == SketchPlugin_Arc::ID()) && - !hasCoincidentPoint(aRefFea, aOtherFea)) - return false; - - if (aRefFea->getKind() == SketchPlugin_Line::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Arc::ID() && - aOtherFea->getKind() != SketchPlugin_Circle::ID()) { - theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is neither an " - + SketchPlugin_Arc::ID() + " nor " + SketchPlugin_Circle::ID(); - return false; - } - } - else if (aRefFea->getKind() == SketchPlugin_Arc::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Line::ID() && - aOtherFea->getKind() != SketchPlugin_Arc::ID()) { - theError = "It refers to an " + SketchPlugin_Arc::ID() + ", but " + aParamA + " is not a " - + SketchPlugin_Line::ID() + " or an " + SketchPlugin_Arc::ID(); - return false; - } - } - else if (aRefFea->getKind() == SketchPlugin_Circle::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Line::ID()) { - theError = "It refers to an " + SketchPlugin_Circle::ID() + ", but " + aParamA + " is not a " - + SketchPlugin_Line::ID(); - return false; - } - } - else { - theError = "It refers to " + aRefFea->getKind() + ", but should refer to " + SketchPlugin_Line::ID() - + " or " + SketchPlugin_Arc::ID() + " or " + SketchPlugin_Circle::ID(); + // at least one feature should be a line + if (aRefFea->getKind() != SketchPlugin_Line::ID() && + aOtherFea->getKind() != SketchPlugin_Line::ID()) { + theError = "At least one feature should be a line"; return false; } - return true; } else { theError = "It uses an empty object"; @@ -217,10 +227,11 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -243,26 +254,29 @@ bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute, if (aRefAttr->object() == aRAttr->object()) { ObjectPtr anObject = aRefAttr->object(); std::string aName = anObject.get() ? anObject->data()->name() : ""; - theError = "The object " + aName + " has been already fixed."; + theError = "The object %1 has been already fixed."; + theError.arg(aName); return false; } } else if (aRefAttr->attr() == aRAttr->attr()) { AttributePtr anAttribute = aRefAttr->attr(); std::string aName = anAttribute.get() ? anAttribute->id() : ""; - theError = "The attribute " + aName + " has been already fixed."; + theError = "The attribute %1 has been already fixed."; + theError.arg(aName); return false; } } return true; } -bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -295,29 +309,42 @@ bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, aType[i] = aFeature->getKind(); if (aFeature->getKind() != SketchPlugin_Line::ID() && aFeature->getKind() != SketchPlugin_Circle::ID() && - aFeature->getKind() != SketchPlugin_Arc::ID()) { - theError = "The " + aFeature->getKind() + " feature kind of attribute is wrong. It should be " + - SketchPlugin_Line::ID() + " or " + SketchPlugin_Circle::ID() + " or " + - SketchPlugin_Arc::ID(); + aFeature->getKind() != SketchPlugin_Arc::ID() && + aFeature->getKind() != SketchPlugin_Ellipse::ID() && + aFeature->getKind() != SketchPlugin_EllipticArc::ID()) { + theError = "The %1 feature is not supported by the Equal constraint."; + theError.arg(aFeature->getKind()); // wrong type of attribute return false; } } - if ((aType[0] == SketchPlugin_Line::ID() || aType[1] == SketchPlugin_Line::ID()) && - aType[0] != aType[1]) { - theError = "Feature with kinds " + aType[0] + " and " + aType[1] + "can not be equal."; + bool isOk = aType[0] == aType[1]; + if (!isOk) { + // circle and arc may be equal + isOk = (aType[0] == SketchPlugin_Arc::ID() && aType[1] == SketchPlugin_Circle::ID()) + || (aType[0] == SketchPlugin_Circle::ID() && aType[1] == SketchPlugin_Arc::ID()); + } + if (!isOk) { + // ellipse and elliptic arc may be equal + isOk = (aType[0] == SketchPlugin_EllipticArc::ID() && aType[1] == SketchPlugin_Ellipse::ID()) + || (aType[0] == SketchPlugin_Ellipse::ID() && aType[1] == SketchPlugin_EllipticArc::ID()); + } + if (!isOk) { + theError = "Features with kinds %1 and %2 can not be equal."; + theError.arg(aType[0]).arg(aType[1]); return false; } return true; } -bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -334,19 +361,21 @@ bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, std::list::iterator aMirIter = aMirroredObjects.begin(); for (; aMirIter != aMirroredObjects.end(); aMirIter++) if (aSelObject == *aMirIter) { - theError = "The object " + aName + " is a result of mirror"; + theError = "The object %1 is a result of mirror"; + theError.arg(aName); return false; } } return true; } -bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -358,11 +387,13 @@ bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttri FeaturePtr aConstraint = std::dynamic_pointer_cast(theAttribute->owner()); AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA); if (!aRefAttrA) { - theError = "The " + aParamA + " attribute " + " should be " + ModelAPI_AttributeRefAttr::typeId(); + theError = "The %1 attribute should be %2"; + theError.arg(aParamA).arg(ModelAPI_AttributeRefAttr::typeId()); return false; } - AttributeRefAttrPtr aRefAttrB = std::dynamic_pointer_cast(theAttribute); + AttributeRefAttrPtr aRefAttrB = + std::dynamic_pointer_cast(theAttribute); // first attribute is a point, it may coincide with any object if (!aRefAttrA->isObject()) @@ -370,12 +401,14 @@ bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttri else { ObjectPtr anObject = aRefAttrA->object(); if (!anObject.get()) { - theError = aParamA + " attribute has an empty object"; + theError = "%1 attribute has an empty object"; + theError.arg(aParamA); return false; } FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrA->object()); if (!aFeature.get()) { - theError = aParamA + " attribute has an empty feature"; + theError = "%1 attribute has an empty feature"; + theError.arg(aParamA); return false; } @@ -389,7 +422,8 @@ bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttri else { FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrB->object()); if (!aFeature) { - theError = theAttribute->id() + " attribute has an empty object"; + theError = "%1 attribute has an empty object"; + theError.arg(theAttribute->id()); return false; } if (aFeature->getKind() == SketchPlugin_Point::ID()) @@ -400,17 +434,18 @@ bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttri } -bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefList::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } FeaturePtr aFeature = std::dynamic_pointer_cast(theAttribute->owner()); - AttributeRefListPtr aSelAttr = + AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast(theAttribute); AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast( @@ -433,16 +468,18 @@ bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, for (; anObjIter != aCopiedObjects.end(); anObjIter++) if (aSelObject == *anObjIter) { std::string aName = aSelObject.get() ? aSelObject->data()->name() : ""; - theError = "The object " + aName + " is a result of copy"; + theError = "The object %1 is a result of copy"; + theError.arg(aName); return false; } } return true; } -bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr& theFeature, - const std::list& theArguments, - std::string& theError) const +bool SketchPlugin_SolverErrorValidator::isValid( + const std::shared_ptr& theFeature, + const std::list& theArguments, + Events_InfoMessage& theError) const { AttributeStringPtr aAttributeString = theFeature->string(SketchPlugin_Sketch::SOLVER_ERROR()); @@ -454,16 +491,21 @@ bool SketchPlugin_SolverErrorValidator::isValid(const std::shared_ptr& theRefsList, const FeaturePtr theFeature) +static bool hasSameTangentFeature(const std::set& theRefsList, + const FeaturePtr theFeature) { - for(std::set::const_iterator anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) { + for(std::set::const_iterator + anIt = theRefsList.cbegin(); anIt != theRefsList.cend(); ++anIt) { std::shared_ptr aAttr = (*anIt); FeaturePtr aFeature = std::dynamic_pointer_cast(aAttr->owner()); + if (!aFeature) + continue; if (aFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) { AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( aFeature->attribute(SketchPlugin_ConstraintTangent::ENTITY_A())); @@ -498,185 +540,209 @@ static bool hasSameTangentFeature(const std::set& theRefsList, con return false; } +static bool isPointPointCoincidence(const FeaturePtr& theCoincidence) +{ + AttributeRefAttrPtr aRefAttr[2] = { + theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_A()), + theCoincidence->refattr(SketchPlugin_Constraint::ENTITY_B()) + }; + + bool arePoints = true; + for (int i = 0; i < 2 && arePoints; ++i) { + if (aRefAttr[i]->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object()); + arePoints = aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID(); + } else + arePoints = aRefAttr[i]->attr().get() != NULL; + } + return arePoints; +} + bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const -{ - std::shared_ptr aFilletFeature = std::dynamic_pointer_cast(theAttribute->owner()); - AttributeRefAttrListPtr aPointsRefList = std::dynamic_pointer_cast(theAttribute); - if(aPointsRefList->size() == 0) { - theError = "Error: List of points is empty."; - return false; - } - - std::map aPointsFeaturesMap = aFilletFeature->pointsFeaturesMap(); - std::set aSetOfPointsOnResultEdges; - for(std::map::iterator aPointsIter = aPointsFeaturesMap.begin(); - aPointsIter != aPointsFeaturesMap.end(); - ++aPointsIter) { - const SketchPlugin_ConstraintFillet::FilletFeatures& aFeatures = aPointsIter->second; - const std::list& aResultEdges = aFeatures.resultEdges; - for(std::list::const_iterator aResultIter = aResultEdges.cbegin(); - aResultIter != aResultEdges.cend(); - ++aResultIter) { - FeaturePtr aResultFeature = *aResultIter; - if(aResultFeature->getKind() == SketchPlugin_Line::ID()) { - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::START_ID())); - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Line::END_ID())); - } else if(aResultFeature->getKind() == SketchPlugin_Arc::ID()) { - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::START_ID())); - aSetOfPointsOnResultEdges.insert(aResultFeature->attribute(SketchPlugin_Arc::END_ID())); - } - } + Events_InfoMessage& theError) const +{ + AttributeRefAttrPtr aPointRefAttr = + std::dynamic_pointer_cast(theAttribute); + if(!aPointRefAttr.get()) { + theError = "Error: Point not selected."; + return false; } - std::list> aPointsList = aPointsRefList->list(); - for(std::list>::const_iterator aPointsIt = aPointsList.cbegin(); aPointsIt != aPointsList.cend(); aPointsIt++) { - ObjectPtr anObject = (*aPointsIt).first; - AttributePtr aPointAttribute = (*aPointsIt).second; - if (!aPointAttribute.get()) - return false; - std::shared_ptr aSelectedPnt = std::dynamic_pointer_cast(aPointAttribute)->pnt(); - - // If we alredy have some result then: - // - if it is the same point all ok, just skip it - // - if it is point on the fillet result edge then it is not valid - if(!aPointsFeaturesMap.empty()) { - if(aPointsFeaturesMap.find(aPointAttribute) != aPointsFeaturesMap.end()) { + AttributePtr aPointAttribute = aPointRefAttr->attr(); + if (!aPointAttribute.get()) { + theError = "Error: Bad point selected."; + return false; + } + std::shared_ptr aSelectedPnt = + std::dynamic_pointer_cast(aPointAttribute)->pnt(); + + // Obtain constraint coincidence for the fillet point. + const std::set& aRefsList = aPointAttribute->owner()->data()->refsToMe(); + FeaturePtr aConstraintCoincidence; + for(std::set::const_iterator anIt = aRefsList.cbegin(); + anIt != aRefsList.cend(); ++anIt) { + std::shared_ptr aAttr = (*anIt); + FeaturePtr aConstrFeature = std::dynamic_pointer_cast(aAttr->owner()); + if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + if (!isPointPointCoincidence(aConstrFeature)) continue; - } - // Check that selected point not on the one of the fillet result edge. - if(aSetOfPointsOnResultEdges.find(aPointAttribute) != aSetOfPointsOnResultEdges.end()) { - return false; + AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); + AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); + + AttributePtr anAttrA = anAttrRefA->attr(); + if(aPointAttribute == anAttrA) { + aConstraintCoincidence = aConstrFeature; + break; } - } - // Obtain constraint coincidence for the fillet point. - const std::set& aRefsList = aPointAttribute->owner()->data()->refsToMe(); - FeaturePtr aConstraintCoincidence; - for(std::set::const_iterator anIt = aRefsList.cbegin(); anIt != aRefsList.cend(); ++anIt) { - std::shared_ptr aAttr = (*anIt); - FeaturePtr aConstrFeature = std::dynamic_pointer_cast(aAttr->owner()); - if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr anAttrRefA = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A())); - AttributeRefAttrPtr anAttrRefB = std::dynamic_pointer_cast( - aConstrFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B())); - if(anAttrRefA.get() && !anAttrRefA->isObject()) { - AttributePtr anAttrA = anAttrRefA->attr(); - if(aPointAttribute == anAttrA) { - aConstraintCoincidence = aConstrFeature; - break; - } - } - if(anAttrRefB.get() && !anAttrRefB->isObject()) { - AttributePtr anAttrB = anAttrRefB->attr(); - if(aPointAttribute == anAttrB) { - aConstraintCoincidence = aConstrFeature; - break; - } - } + AttributePtr anAttrB = anAttrRefB->attr(); + if(aPointAttribute == anAttrB) { + aConstraintCoincidence = aConstrFeature; + break; } } + } - if(!aConstraintCoincidence.get()) { - theError = "Error: one of the selected point does not have coicidence."; - return false; - } + if(!aConstraintCoincidence.get()) { + theError = "Error: one of the selected point does not have coincidence."; + return false; + } - // Get coincides from constraint. - std::set aCoinsides; - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_A(), - aCoinsides); - SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, - SketchPlugin_ConstraintCoincidence::ENTITY_B(), - aCoinsides); - - // Remove points from set of coincides. - std::set aNewSetOfCoincides; - for(std::set::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) { - if((*anIt)->getKind() != SketchPlugin_Line::ID() && - (*anIt)->getKind() != SketchPlugin_Arc::ID()) { - continue; - } - if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { - AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); - std::shared_ptr anArcCenterPnt = std::dynamic_pointer_cast(anArcCenter)->pnt(); - double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt); - if(aDistSelectedArcCenter < tolerance) { + // Get coincides from constraint. + std::set aCoinsides; + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_A(), + aCoinsides, + true); + SketchPlugin_Tools::findCoincidences(aConstraintCoincidence, + SketchPlugin_ConstraintCoincidence::ENTITY_B(), + aCoinsides, + true); + + // Remove points and external lines from set of coincides. + std::set aNewSetOfCoincides; + for(std::set::iterator anIt = aCoinsides.begin(); + anIt != aCoinsides.end(); ++anIt) { + std::shared_ptr aSketchEntity = + std::dynamic_pointer_cast(*anIt); + if(aSketchEntity.get() && (aSketchEntity->isCopy() || aSketchEntity->isExternal())) { + continue; + } + if((*anIt)->getKind() != SketchPlugin_Line::ID() && + (*anIt)->getKind() != SketchPlugin_Arc::ID()) { continue; - } + } + if((*anIt)->getKind() == SketchPlugin_Arc::ID()) { + AttributePtr anArcCenter = (*anIt)->attribute(SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr anArcCenterPnt = + std::dynamic_pointer_cast(anArcCenter)->pnt(); + double aDistSelectedArcCenter = aSelectedPnt->distance(anArcCenterPnt); + if(aDistSelectedArcCenter < tolerance) { + continue; } - aNewSetOfCoincides.insert(*anIt); } - aCoinsides = aNewSetOfCoincides; - - // If we still have more than two coincides remove auxilary entities from set of coincides. - if(aCoinsides.size() > 2) { - aNewSetOfCoincides.clear(); - for(std::set::iterator anIt = aCoinsides.begin(); anIt != aCoinsides.end(); ++anIt) { - if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { - aNewSetOfCoincides.insert(*anIt); - } + aNewSetOfCoincides.insert(*anIt); + } + aCoinsides = aNewSetOfCoincides; + + // If we still have more than two coincides remove auxilary entities from set of coincides. + if(aCoinsides.size() > 2) { + aNewSetOfCoincides.clear(); + for(std::set::iterator anIt = aCoinsides.begin(); + anIt != aCoinsides.end(); ++anIt) { + if(!(*anIt)->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) { + aNewSetOfCoincides.insert(*anIt); } - aCoinsides = aNewSetOfCoincides; } + aCoinsides = aNewSetOfCoincides; + } - if(aCoinsides.size() != 2) { - theError = "Error: One of the selected points does not have two suitable edges for fillet."; - return false; - } + if(aCoinsides.size() != 2) { + theError = "Error: One of the selected points does not have two suitable edges for fillet."; + return false; + } - // Check that selected edges don't have tangent constraint. - std::set::iterator anIt = aCoinsides.begin(); - FeaturePtr aFirstFeature = *anIt++; - FeaturePtr aSecondFeature = *anIt; - const std::set& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe(); - if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) { + // Check that selected edges don't have tangent constraint. + std::set::iterator anIt = aCoinsides.begin(); + FeaturePtr aFirstFeature = *anIt++; + FeaturePtr aSecondFeature = *anIt; + const std::set& aFirstFeatureRefsList = aFirstFeature->data()->refsToMe(); + if(hasSameTangentFeature(aFirstFeatureRefsList, aSecondFeature)) { + theError = "Error: Edges in selected point has tangent constraint."; + return false; + } + + std::list aFirstResults = aFirstFeature->results(); + for(std::list::iterator aResIt = aFirstResults.begin(); + aResIt != aFirstResults.end(); ++aResIt) { + ResultPtr aRes = *aResIt; + const std::set& aResRefsList = aRes->data()->refsToMe(); + if(hasSameTangentFeature(aResRefsList, aSecondFeature)) { theError = "Error: Edges in selected point has tangent constraint."; return false; } + } - std::list aFirstResults = aFirstFeature->results(); - for(std::list::iterator aResIt = aFirstResults.begin(); aResIt != aFirstResults.end(); ++aResIt) { - ResultPtr aRes = *aResIt; - const std::set& aResRefsList = aRes->data()->refsToMe(); - if(hasSameTangentFeature(aResRefsList, aSecondFeature)) { - theError = "Error: Edges in selected point has tangent constraint."; - return false; - } - } + // Check the features are not tangent + std::shared_ptr aFirstShape = aFirstFeature->lastResult()->shape(); + std::shared_ptr aSecondShape = aSecondFeature->lastResult()->shape(); + if (!aFirstShape || !aFirstShape->isEdge() || + !aSecondShape || !aSecondShape->isEdge()) { + theError = "Error: At least on of the features is not an edge"; + return false; + } + + std::shared_ptr anEdge1 = std::dynamic_pointer_cast(aFirstShape); + std::shared_ptr anEdge2 = std::dynamic_pointer_cast(aSecondShape); + static const double TOL = 1.e-7; + if (anEdge1->isLine() && anEdge2->isLine()) { // Check that lines not collinear - if(aFirstFeature->getKind() == SketchPlugin_Line::ID() && aSecondFeature->getKind() == SketchPlugin_Line::ID()) { - std::string aStartAttr = SketchPlugin_Line::START_ID(); - std::string anEndAttr = SketchPlugin_Line::END_ID(); - std::shared_ptr aFirstStartPnt, aFirstEndPnt, aSecondStartPnt, aSecondEndPnt; - aFirstStartPnt = std::dynamic_pointer_cast(aFirstFeature->attribute(aStartAttr))->pnt(); - aFirstEndPnt = std::dynamic_pointer_cast(aFirstFeature->attribute(anEndAttr))->pnt(); - aSecondStartPnt = std::dynamic_pointer_cast(aSecondFeature->attribute(aStartAttr))->pnt(); - aSecondEndPnt = std::dynamic_pointer_cast(aSecondFeature->attribute(anEndAttr))->pnt(); - double aCheck1 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondStartPnt->y() - aFirstStartPnt->y()) - - (aSecondStartPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); - double aCheck2 = abs((aFirstEndPnt->x() - aFirstStartPnt->x()) * (aSecondEndPnt->y() - aFirstStartPnt->y()) - - (aSecondEndPnt->x() - aFirstStartPnt->x()) * (aFirstEndPnt->y() - aFirstStartPnt->y())); - if(aCheck1 < 1.e-7 && aCheck2 < 1.e-7) { - return false; - } + std::shared_ptr aDir1 = anEdge1->line()->direction(); + std::shared_ptr aDir2 = anEdge2->line()->direction(); + double aCross = aDir1->cross(aDir2)->squareModulus(); + if (aCross < TOL * TOL) + return false; + } else if (anEdge1->isArc() && anEdge2->isArc()) { + // check the circles are not tangent + std::shared_ptr aCirc1 = anEdge1->circle(); + std::shared_ptr aCirc2 = anEdge2->circle(); + double aDistCC = aCirc1->center()->distance(aCirc2->center()); + double aRadSum = aCirc1->radius() + aCirc2->radius(); + double aRadDiff = fabs(aCirc1->radius() - aCirc2->radius()); + if (fabs(aDistCC - aRadSum) < TOL || fabs(aDistCC - aRadDiff) < TOL) + return false; + } else { + // check whether line and arc are tangent + std::shared_ptr aCirc; + std::shared_ptr aLine; + if (anEdge1->isLine()) { + aLine = anEdge1->line(); + aCirc = anEdge2->circle(); + } else { + aCirc = anEdge1->circle(); + aLine = anEdge2->line(); } + + double aDistCL = aLine->distance(aCirc->center()); + if (fabs(aDistCL - aCirc->radius()) < TOL) + return false; } return true; } -bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, +bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } @@ -685,7 +751,8 @@ bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttri SessionPtr aMgr = ModelAPI_Session::get(); ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - FeaturePtr anAttributeFeature = std::dynamic_pointer_cast(theAttribute->owner()); + FeaturePtr anAttributeFeature = + std::dynamic_pointer_cast(theAttribute->owner()); AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA); @@ -705,7 +772,9 @@ bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttri if (aFeature->getKind() == SketchPlugin_Point::ID()) ++aNbPoints; - else if (aFeature->getKind() == SketchPlugin_Line::ID()) + else if (aFeature->getKind() == SketchPlugin_Line::ID() || + aFeature->getKind() == SketchPlugin_Arc::ID() || + aFeature->getKind() == SketchPlugin_EllipticArc::ID()) ++aNbLines; } } @@ -719,16 +788,23 @@ bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttri bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttribute, const std::list& /*theArguments*/, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } + FeaturePtr anOwner = std::dynamic_pointer_cast(theAttribute->owner()); + AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE()); + if (anArcTypeAttr && anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TANGENT_EDGE()) + return true; // not applicable for non-tangent arcs + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); AttributePtr anAttr = aRefAttr->attr(); if (!anAttr) { - theError = "The attribute " + theAttribute->id() + " should be a point"; + theError = "The attribute %1 should be a point"; + theError.arg(theAttribute->id()); return false; } @@ -738,7 +814,8 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri // selected point should not be a center of arc const std::string& aPntId = anAttr->id(); if (aPntId != SketchPlugin_Arc::START_ID() && aPntId != SketchPlugin_Arc::END_ID()) { - theError = "The attribute " + aPntId + " is not supported"; + theError = "The attribute %1 is not supported"; + theError.arg(aPntId); return false; } } @@ -746,58 +823,92 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri // selected point should be bound point of line const std::string& aPntId = anAttr->id(); if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) { - theError = "The attribute " + aPntId + " is not supported"; + theError = "The attribute %1 is not supported"; + theError.arg(aPntId); return false; } } else { - theError = "Unable to build tangent arc on " + anAttrFeature->getKind(); + theError = "Unable to build tangent arc on %1"; + theError.arg(anAttrFeature->getKind()); return false; } - // Check the tangent point is equal to arc end - FeaturePtr anArc = std::dynamic_pointer_cast(aRefAttr->owner()); - std::shared_ptr anEndPoint = std::dynamic_pointer_cast( - anArc->attribute(SketchPlugin_Arc::END_ID())); - if (anEndPoint->isInitialized()) { - std::shared_ptr aTangPt = - std::dynamic_pointer_cast(anAttr); - if (aTangPt->pnt()->distance(anEndPoint->pnt()) < tolerance) { - theError = "Unable to build arc on same points"; + return true; +} + +bool SketchPlugin_ArcTransversalPointValidator::isValid( + const AttributePtr& theAttribute, + const std::list& /*theArguments*/, + Events_InfoMessage& theError) const +{ + if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return false; + } + FeaturePtr anOwner = std::dynamic_pointer_cast(theAttribute->owner()); + AttributeStringPtr anArcTypeAttr = anOwner->string(SketchPlugin_MacroArc::ARC_TYPE()); + if (anArcTypeAttr && + anArcTypeAttr->value() != SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE()) + return true; // not applicable for non-transversal arcs + + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + AttributePtr anAttr = aRefAttr->attr(); + if (!anAttr) { + theError = "The attribute %1 should be a point"; + theError.arg(theAttribute->id()); + return false; + } + + FeaturePtr anAttrFeature = std::dynamic_pointer_cast(anAttr->owner()); + const std::string& aFeatureType = anAttrFeature->getKind(); + if (aFeatureType == SketchPlugin_Line::ID()) { + // selected point should be bound point of line + const std::string& aPntId = anAttr->id(); + if (aPntId != SketchPlugin_Line::START_ID() && aPntId != SketchPlugin_Line::END_ID()) { + theError = "The attribute %1 is not supported"; + theError.arg(aPntId); return false; } } + else { + theError = "Unable to build perpendicular arc on %1"; + theError.arg(anAttrFeature->getKind()); + return false; + } return true; } bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } - AttributeSelectionPtr aLineAttr = - std::dynamic_pointer_cast(theAttribute); + AttributeSelectionPtr anExternalAttr = + std::dynamic_pointer_cast(theAttribute); std::shared_ptr anEdge; - if(aLineAttr && aLineAttr->value() && aLineAttr->value()->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aLineAttr->value())); - } else if(aLineAttr->context() && aLineAttr->context()->shape() && aLineAttr->context()->shape()->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aLineAttr->context()->shape())); + if (anExternalAttr && anExternalAttr->value() && anExternalAttr->value()->isEdge()) { + anEdge = std::shared_ptr(new GeomAPI_Edge(anExternalAttr->value())); + } else if(anExternalAttr->context() && anExternalAttr->context()->shape() && + anExternalAttr->context()->shape()->isEdge()) { + anEdge = std::shared_ptr(new GeomAPI_Edge(anExternalAttr->context()->shape())); } - if (!anEdge || !anEdge->isLine()) { - theError = "The attribute " + theAttribute->id() + " should be a line"; + if (!anEdge) { + theError = "The attribute %1 should be an edge"; + theError.arg(theAttribute->id()); return false; } - std::shared_ptr aLineDir = anEdge->line()->direction(); - // find a sketch std::shared_ptr aSketch; - std::set aRefs = aLineAttr->owner()->data()->refsToMe(); + std::set aRefs = anExternalAttr->owner()->data()->refsToMe(); std::set::const_iterator anIt = aRefs.begin(); for (; anIt != aRefs.end(); ++anIt) { CompositeFeaturePtr aComp = @@ -812,32 +923,180 @@ bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribut return false; } + // check the edge is intersected with sketch plane std::shared_ptr aPlane = aSketch->plane(); - std::shared_ptr aNormal = aPlane->direction(); - return fabs(aNormal->dot(aLineDir)) > tolerance * tolerance; + + std::list anIntersectionsPoints; + anEdge->intersectWithPlane(aPlane, anIntersectionsPoints); + if (anIntersectionsPoints.empty()) { + theError = "The edge is not intersected with sketch plane"; + return false; + } + return true; +} + +bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + bool aValid = false; + + if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return aValid; + } + AttributeReferencePtr aFeatureAttr = + std::dynamic_pointer_cast(theAttribute); + std::shared_ptr aSplitFeature = + std::dynamic_pointer_cast(theAttribute->owner()); + + ObjectPtr anAttrObject = aFeatureAttr->value(); + if (!anAttrObject) { + AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT()); + aFeatureAttr = std::dynamic_pointer_cast(aPreviewAttr); + anAttrObject = aFeatureAttr->value(); + } + + FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttrObject); + if (!anAttrFeature) + return aValid; + + std::set anEdgeShapes; + ModelGeomAlgo_Shape::shapesOfType(anAttrFeature, GeomAPI_Shape::EDGE, anEdgeShapes); + if (anEdgeShapes.empty() || anEdgeShapes.size() > 1 /*there case has not existed yet*/) + return aValid; + + // coincidences to the feature + std::set > aRefAttributes; + ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature, + SketchPlugin_ConstraintCoincidence::ID(), + aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID()); + + GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape(); + std::shared_ptr aSFeature = + std::dynamic_pointer_cast(anAttrFeature); + if (!aSFeature) + return false; + SketchPlugin_Sketch* aSketch = aSFeature->sketch(); + + std::shared_ptr aData = aSketch->data(); + std::shared_ptr aC = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + std::shared_ptr aX = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::DIRX_ID())); + std::shared_ptr aNorm = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir()))); + + typedef std::map, + std::pair >, + std::list > > > PointToRefsMap; + PointToRefsMap aPointsInfo; + + ModelGeomAlgo_Point2D::getPointsInsideShape(anAttrShape, aRefAttributes, aC->pnt(), + aX->dir(), aDirY, aPointsInfo); + int aCoincidentToFeature = (int)aPointsInfo.size(); + if (anAttrFeature->getKind() == SketchPlugin_Circle::ID() || + anAttrFeature->getKind() == SketchPlugin_Ellipse::ID()) + aValid = aCoincidentToFeature >= 2; + else + aValid = aCoincidentToFeature >= 1; + + return aValid; +} + +bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + bool aValid = false; + + if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return aValid; + } + AttributeReferencePtr aBaseObjectAttr = + std::dynamic_pointer_cast(theAttribute); + + std::shared_ptr aTrimFeature = + std::dynamic_pointer_cast(theAttribute->owner()); + + ObjectPtr aBaseObject = aBaseObjectAttr->value(); + if (!aBaseObject) { + AttributePtr aPreviewAttr = aTrimFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT()); + aBaseObjectAttr = std::dynamic_pointer_cast(aPreviewAttr); + aBaseObject = aBaseObjectAttr->value(); + } + + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject); + if (!aBaseFeature) + return aValid; + + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(aBaseFeature); + if (!aSketchFeature.get() || aSketchFeature->isCopy()) + return aValid; + + // point on feature + AttributePoint2DPtr aPoint = std::dynamic_pointer_cast( + aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT())); + + SketchPlugin_Sketch* aSketch = aTrimFeature->sketch(); + + std::shared_ptr anAttributePnt2d = aPoint->pnt(); + std::shared_ptr anAttributePnt = aSketch->to3D(anAttributePnt2d->x(), + anAttributePnt2d->y()); + + std::map > aCashedShapes; + std::map, + std::pair >, + std::list > > > > anObjectToPoints; + SketchPlugin_SegmentationTools::fillObjectShapes( + aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints); + const std::set& aShapes = aCashedShapes[aBaseObject]; + + return aShapes.size() > 1; } bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, - std::string& theError) const + Events_InfoMessage& theError) const { if (theAttribute->attributeType() != ModelAPI_AttributeSelection::typeId()) { - theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed"; + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); return false; } AttributeSelectionPtr aFeatureAttr = std::dynamic_pointer_cast(theAttribute); std::shared_ptr anEdge; - if(aFeatureAttr && aFeatureAttr->value() && aFeatureAttr->value()->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->value())); - } else if(aFeatureAttr->context() && aFeatureAttr->context()->shape() && - aFeatureAttr->context()->shape()->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->context()->shape())); - } + std::shared_ptr aSketchFeature; + if (aFeatureAttr.get()) { + GeomShapePtr aVal = aFeatureAttr->value(); + ResultPtr aRes = aFeatureAttr->context(); + if (aVal && aVal->isVertex()) + return true; // vertex is always could be projected + if (aVal && aVal->isEdge()) { + anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->value())); + } else if(aRes && aRes->shape()) { + if (aRes->shape()->isVertex()) + return true; // vertex is always could be projected + else if (aRes->shape()->isEdge()) + anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->context()->shape())); + } + // try to convert result to sketch feature + if (aRes) { + aSketchFeature = + std::dynamic_pointer_cast(ModelAPI_Feature::feature(aRes)); + } + } if (!anEdge) { - theError = "The attribute " + theAttribute->id() + " should be an edge"; + theError = "The attribute %1 should be an edge or vertex"; + theError.arg(theAttribute->id()); return false; } @@ -857,20 +1116,682 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, theError = "There is no sketch referring to the current feature"; return false; } + if (aSketchFeature && aSketch.get() == aSketchFeature->sketch()) { + theError = "Unable to project feature from the same sketch"; + return false; + } std::shared_ptr aPlane = aSketch->plane(); std::shared_ptr aNormal = aPlane->direction(); + std::shared_ptr anOrigin = aPlane->location(); + bool aValid = true; if (anEdge->isLine()) { - std::shared_ptr aLineDir = anEdge->line()->direction(); - double aDot = aNormal->dot(aLineDir); - return aDot > -1.0 + tolerance && aDot < 1.0 - tolerance; + std::shared_ptr aLine = anEdge->line(); + std::shared_ptr aLineDir = aLine->direction(); + double aDot = fabs(aNormal->dot(aLineDir)); + aValid = fabs(aDot - 1.0) >= tolerance * tolerance; + if (!aValid) + theError = "Error: Line is orthogonal to the sketch plane."; } else if (anEdge->isCircle() || anEdge->isArc()) { - std::shared_ptr aCircNormal = anEdge->circle()->normal(); + std::shared_ptr aCircle = anEdge->circle(); + std::shared_ptr aCircNormal = aCircle->normal(); double aDot = fabs(aNormal->dot(aCircNormal)); - return fabs(aDot - 1.0) < tolerance * tolerance; + aValid = aDot >= tolerance * tolerance; + if (!aValid) + theError.arg(anEdge->isCircle() ? "Error: Circle is orthogonal to the sketch plane." + : "Error: Arc is orthogonal to the sketch plane."); + } + else if (anEdge->isEllipse()) { + std::shared_ptr anEllipse = anEdge->ellipse(); + std::shared_ptr anEllipseNormal = anEllipse->normal(); + double aDot = fabs(aNormal->dot(anEllipseNormal)); + aValid = fabs(aDot - 1.0) <= tolerance * tolerance; + if (!aValid) + theError.arg(anEdge->isClosed() ? "Error: Ellipse is orthogonal to the sketch plane." + : "Error: Elliptic Arc is orthogonal to the sketch plane."); + } + + return aValid; +} + + +static std::set common(const std::set& theSet1, + const std::set& theSet2) +{ + std::set aCommon; + if (theSet1.empty() || theSet2.empty()) + return aCommon; + + std::set::const_iterator anIt2 = theSet2.begin(); + for (; anIt2 != theSet2.end(); ++anIt2) + if (theSet1.find(*anIt2) != theSet1.end()) + aCommon.insert(*anIt2); + return aCommon; +} + +bool SketchPlugin_DifferentReferenceValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + + int aNbFeaturesReferred = 0; + int aNbAttributesReferred = 0; + std::set aCommonReferredFeatures; + + // find all features referred by attributes listed in theArguments + std::list::const_iterator anArgIt = theArguments.begin(); + for (; anArgIt != theArguments.end(); ++anArgIt) { + AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt); + if (!aRefAttr) + continue; + + std::set aCoincidentFeatures; + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + if (aFeature) { + aCoincidentFeatures.insert(aFeature); + aNbFeaturesReferred += 1; + } + } else { + AttributePoint2DPtr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (aPoint) { + aCoincidentFeatures = SketchPlugin_Tools::findFeaturesCoincidentToPoint(aPoint); + aNbAttributesReferred += 1; + } + } + + if (aCommonReferredFeatures.empty()) + aCommonReferredFeatures = aCoincidentFeatures; + else + aCommonReferredFeatures = common(aCommonReferredFeatures, aCoincidentFeatures); + + if (aCommonReferredFeatures.empty()) + return true; + } + + bool isOk = aNbFeaturesReferred < 1; + if (aNbFeaturesReferred == 1) { + if (aCommonReferredFeatures.size() == 1) { + FeaturePtr aFeature = *aCommonReferredFeatures.begin(); + isOk = aNbAttributesReferred <= 1 || + aFeature->getKind() == SketchPlugin_Circle::ID() || + aFeature->getKind() == SketchPlugin_Arc::ID(); + } else + isOk = false; + } + + if (!isOk) + theError = "Attributes are referred to the same feature"; + return isOk; +} + +bool SketchPlugin_DifferentPointReferenceValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + std::set aReferredCoincidentPoints; + + // find all points referred by attributes listed in theArguments + bool hasRefsToPoints = false; + std::list::const_iterator anArgIt = theArguments.begin(); + for (; anArgIt != theArguments.end(); ++anArgIt) { + AttributeRefAttrPtr aRefAttr = anOwner->refattr(*anArgIt); + if (!aRefAttr) + continue; + + if (!aRefAttr->isObject()) { + AttributePoint2DPtr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (aReferredCoincidentPoints.empty()) + aReferredCoincidentPoints = SketchPlugin_Tools::findPointsCoincidentToPoint(aPoint); + else if (aReferredCoincidentPoints.find(aPoint) == aReferredCoincidentPoints.end()) + return true; // non-coincident point has been found + else + hasRefsToPoints = true; + } + } + + if (hasRefsToPoints) + theError = "Attributes are referred to the same point"; + return !hasRefsToPoints; +} + +bool SketchPlugin_CirclePassedPointValidator::isValid( + const AttributePtr& theAttribute, + const std::list&, + Events_InfoMessage& theError) const +{ + static const std::string aErrorMessage( + "Passed point refers to the same feature as a center point"); + + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + + AttributeRefAttrPtr aCenterRef = + anOwner->refattr(SketchPlugin_MacroCircle::CENTER_POINT_REF_ID()); + AttributeRefAttrPtr aPassedRef = + anOwner->refattr(SketchPlugin_MacroCircle::PASSED_POINT_REF_ID()); + + if (!aPassedRef->isObject()) + return true; + + FeaturePtr aPassedFeature = ModelAPI_Feature::feature(aPassedRef->object()); + if (!aPassedFeature) + return true; + + if (aCenterRef->isObject()) { + if (aCenterRef->object() == aPassedRef->object()) { + theError = aErrorMessage; + return false; + } + } else { + AttributePoint2DPtr aCenterPoint = + std::dynamic_pointer_cast(aCenterRef->attr()); + if (aCenterPoint) { + std::set aCoincidentFeatures = + SketchPlugin_Tools::findFeaturesCoincidentToPoint(aCenterPoint); + // check one of coincident features is a feature referred by passed point + std::set::const_iterator anIt = aCoincidentFeatures.begin(); + for(; anIt != aCoincidentFeatures.end(); ++anIt) + if (*anIt == aPassedFeature) { + theError = aErrorMessage; + return false; + } + } + } + return true; +} + +bool SketchPlugin_ThirdPointValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + return arePointsNotOnLine(anOwner, theError) && + arePointsNotSeparated(anOwner, theArguments, theError); +} + +static std::shared_ptr toPoint(const FeaturePtr& theMacroCircle, + const std::string& thePointAttrName, + const std::string& theRefPointAttrName) +{ + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast( + theMacroCircle->attribute(thePointAttrName)); + AttributeRefAttrPtr aRefAttr = theMacroCircle->refattr(theRefPointAttrName); + + std::shared_ptr aPoint = aPointAttr->pnt(); + if (aRefAttr) { + if (aRefAttr->isObject()) { + // project a point onto selected feature + std::shared_ptr aFeature = + std::dynamic_pointer_cast( + ModelAPI_Feature::feature(aRefAttr->object())); + if (aFeature) { + SketchPlugin_Sketch* aSketch = aFeature->sketch(); + std::shared_ptr anEdge = + std::dynamic_pointer_cast(aFeature->lastResult()->shape()); + if (anEdge) { + std::shared_ptr aPoint3D = aSketch->to3D(aPoint->x(), aPoint->y()); + if (anEdge->isLine()) + aPoint3D = anEdge->line()->project(aPoint3D); + else if (anEdge->isCircle()) + aPoint3D = anEdge->circle()->project(aPoint3D); + if(aPoint3D) + aPoint = aSketch->to2D(aPoint3D); + } + } + } else { + AttributePoint2DPtr anOtherPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (anOtherPoint) + aPoint = anOtherPoint->pnt(); // the reference point is much more precise, use it + } + } + + return aPoint; +} + +static void threePointsOfFeature(const FeaturePtr& theMacroFeature, + std::shared_ptr thePoints[3]) +{ + if (theMacroFeature->getKind() == SketchPlugin_MacroCircle::ID()) { + thePoints[0] = toPoint(theMacroFeature, + SketchPlugin_MacroCircle::FIRST_POINT_ID(), + SketchPlugin_MacroCircle::FIRST_POINT_REF_ID()); + thePoints[1] = toPoint(theMacroFeature, + SketchPlugin_MacroCircle::SECOND_POINT_ID(), + SketchPlugin_MacroCircle::SECOND_POINT_REF_ID()); + thePoints[2] = toPoint(theMacroFeature, + SketchPlugin_MacroCircle::THIRD_POINT_ID(), + SketchPlugin_MacroCircle::THIRD_POINT_REF_ID()); + } else if (theMacroFeature->getKind() == SketchPlugin_MacroArc::ID()) { + thePoints[0] = toPoint(theMacroFeature, + SketchPlugin_MacroArc::START_POINT_2_ID(), + SketchPlugin_MacroArc::START_POINT_REF_ID()); + thePoints[1] = toPoint(theMacroFeature, + SketchPlugin_MacroArc::END_POINT_2_ID(), + SketchPlugin_MacroArc::END_POINT_REF_ID()); + thePoints[2] = toPoint(theMacroFeature, + SketchPlugin_MacroArc::PASSED_POINT_ID(), + SketchPlugin_MacroArc::PASSED_POINT_REF_ID()); + } +} + +static bool isPointsOnLine(const std::shared_ptr& thePoint1, + const std::shared_ptr& thePoint2, + const std::shared_ptr& thePoint3) +{ + static const double aTolerance = 1.e-7; + if (thePoint1->distance(thePoint2) < aTolerance || + thePoint1->distance(thePoint3) < aTolerance) + return true; + + std::shared_ptr aDirP1P2(new GeomAPI_Dir2d(thePoint2->x() - thePoint1->x(), + thePoint2->y() - thePoint1->y())); + std::shared_ptr aDirP1P3(new GeomAPI_Dir2d(thePoint3->x() - thePoint1->x(), + thePoint3->y() - thePoint1->y())); + return fabs(aDirP1P2->cross(aDirP1P3)) < aTolerance; +} + +static bool isOnSameSide(const std::shared_ptr& theLine, + const std::shared_ptr& thePoint1, + const std::shared_ptr& thePoint2) +{ + static const double aTolerance = 1.e-7; + std::shared_ptr aLineDir = theLine->direction(); + std::shared_ptr aLineLoc = theLine->location()->xyz(); + + std::shared_ptr aVec1 = thePoint1->xyz()->decreased(aLineLoc); + // the first point is on the line + if (aVec1->squareModulus() < aTolerance * aTolerance) + return false; + std::shared_ptr aDirP1L(new GeomAPI_Dir(aVec1)); + std::shared_ptr aVec2 = thePoint2->xyz()->decreased(aLineLoc); + // the second point is on the line + if (aVec2->squareModulus() < aTolerance * aTolerance) + return false; + std::shared_ptr aDirP2L(new GeomAPI_Dir(aVec2)); + + return aLineDir->cross(aDirP1L)->dot(aLineDir->cross(aDirP2L)) > -aTolerance; +} + +static bool isOnSameSide(const std::shared_ptr& theCircle, + const std::shared_ptr& thePoint1, + const std::shared_ptr& thePoint2) +{ + static const double aTolerance = 1.e-7; + std::shared_ptr aCenter = theCircle->center(); + double aDistP1C = thePoint1->distance(aCenter); + double aDistP2C = thePoint2->distance(aCenter); + return (aDistP1C - theCircle->radius()) * (aDistP2C - theCircle->radius()) > -aTolerance; +} + +bool SketchPlugin_ThirdPointValidator::arePointsNotOnLine( + const FeaturePtr& theMacroFeature, + Events_InfoMessage& theError) const +{ + static const std::string aErrorPointsOnLine( + "Selected points are on the same line"); + + std::shared_ptr aPoints[3]; + threePointsOfFeature(theMacroFeature, aPoints); + + if (isPointsOnLine(aPoints[0], aPoints[1], aPoints[2])) { + theError = aErrorPointsOnLine; + return false; + } + return true; +} + +bool SketchPlugin_ThirdPointValidator::arePointsNotSeparated( + const FeaturePtr& theMacroFeature, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + static const std::string aErrorPointsApart( + "Selected entity is lying between first two points"); + + AttributeRefAttrPtr aThirdPointRef = theMacroFeature->refattr(theArguments.front()); + FeaturePtr aRefByThird; + if (aThirdPointRef->isObject()) + aRefByThird = ModelAPI_Feature::feature(aThirdPointRef->object()); + if (!aRefByThird) + return true; + + std::shared_ptr aPoints[3]; + threePointsOfFeature(theMacroFeature, aPoints); + + std::shared_ptr aThirdShape = + std::dynamic_pointer_cast(aRefByThird->lastResult()->shape()); + if (!aThirdShape) + return true; + + SketchPlugin_Sketch* aSketch = + std::dynamic_pointer_cast(theMacroFeature)->sketch(); + std::shared_ptr aFirstPnt3D = aSketch->to3D(aPoints[0]->x(), aPoints[0]->y()); + std::shared_ptr aSecondPnt3D = aSketch->to3D(aPoints[1]->x(), aPoints[1]->y()); + + bool isOk = true; + if (aThirdShape->isLine()) + isOk = isOnSameSide(aThirdShape->line(), aFirstPnt3D, aSecondPnt3D); + else if (aThirdShape->isCircle() || aThirdShape->isArc()) + isOk = isOnSameSide(aThirdShape->circle(), aFirstPnt3D, aSecondPnt3D); + + if (!isOk) + theError = aErrorPointsApart; + return isOk; +} + +bool SketchPlugin_ArcEndPointValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner()); + AttributeRefAttrPtr anEndPointRef = aFeature->refattr(theArguments.front()); + + if(!anEndPointRef.get()) { + return true; + } + + ObjectPtr anObject = anEndPointRef->object(); + AttributePtr anAttr = anEndPointRef->attr(); + if(!anObject.get() && !anAttr.get()) { + return true; + } + + if(anEndPointRef->attr().get()) { + return false; + } + + ResultPtr aResult = std::dynamic_pointer_cast(anObject); + if(aResult.get()) { + GeomShapePtr aShape = aResult->shape(); + if(aShape.get() && aShape->isVertex()) { + return false; + } + } + + aFeature = ModelAPI_Feature::feature(anObject); + if(aFeature.get()) { + if(aFeature->getKind() == SketchPlugin_Point::ID()) { + return false; + } + } + + return true; +} + +static GeomShapePtr toInfiniteEdge(const GeomShapePtr theShape) +{ + if(!theShape.get()) { + return theShape; + } + + if(!theShape->isEdge()) { + return theShape; + } + + std::shared_ptr anEdge(new GeomAPI_Edge(theShape)); + + if(!anEdge.get()) { + return theShape; + } + + if(anEdge->isLine()) { + std::shared_ptr aLine = anEdge->line(); + GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::line(aLine); + return aShape; + } + + if(anEdge->isCircle() || anEdge->isArc()) { + std::shared_ptr aCircle = anEdge->circle(); + GeomShapePtr aShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCircle); + return aShape; + } + + return theShape; +} + +bool SketchPlugin_ArcEndPointIntersectionValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + std::shared_ptr anArcFeature = + std::dynamic_pointer_cast(theAttribute->owner()); + AttributeRefAttrPtr anEndPointRef = anArcFeature->refattr(theArguments.front()); + + if(!anEndPointRef.get()) { + return true; + } + + GeomShapePtr anArcShape = toInfiniteEdge(anArcFeature->getArcShape(false)); + + if(!anArcShape.get() || anArcShape->isNull()) { + return true; + } + + ObjectPtr anObject = anEndPointRef->object(); + AttributePtr anAttr = anEndPointRef->attr(); + if(!anObject.get() && !anAttr.get()) { + return true; + } + + ResultPtr aResult = std::dynamic_pointer_cast(anObject); + if(aResult.get()) { + GeomShapePtr aShape = aResult->shape(); + if (!aShape->isEdge()) + return true; + aShape = toInfiniteEdge(aShape); + if(aShape.get() && !aShape->isNull()) { + if(anArcShape->isIntersect(aShape)) { + return true; + } + } + } + + FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(anObject); + if(aSelectedFeature.get()) { + std::list aResults = aSelectedFeature->results(); + for(std::list::const_iterator anIt = aResults.cbegin(); + anIt != aResults.cend(); + ++anIt) + { + GeomShapePtr aShape = (*anIt)->shape(); + if (!aShape->isEdge()) + return true; + aShape = toInfiniteEdge(aShape); + if(aShape.get() && !aShape->isNull()) { + if(anArcShape->isIntersect(aShape)) { + return true; + } + } + } } return false; } + +bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + std::set aFeatureKinds; + for (std::list::const_iterator anArgIt = theArguments.begin(); + anArgIt != theArguments.end(); anArgIt++) { + aFeatureKinds.insert(*anArgIt); + } + + if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return false; + } + + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast + (theAttribute); + bool isObject = aRefAttr->isObject(); + if (!isObject) { + theError = "It uses an empty object"; + return false; + } + ObjectPtr anObject = aRefAttr->object(); + FeaturePtr aFeature = ModelAPI_Feature::feature(anObject); + if (!aFeature.get()) { + theError = "The feature of the checked attribute is empty"; + return false; + } + + FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aRefAttr->owner()); + + std::set aRefsList = anObject->data()->refsToMe(); + std::set::const_iterator anIt = aRefsList.begin(); + for (; anIt != aRefsList.end(); anIt++) { + FeaturePtr aRefFeature = ModelAPI_Feature::feature((*anIt)->owner()); + if (aRefFeature.get() && aCurrentFeature != aRefFeature && + aFeatureKinds.find(aRefFeature->getKind()) != aFeatureKinds.end()) + return false; // constraint is found, that means that the check is not valid + } + return true; +} + +bool SketchPlugin_ReplicationReferenceValidator::isValid( + const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + if (!aRefAttr) + { + theError = "Incorrect attribute"; + return false; + } + + ObjectPtr anOwner; + if (aRefAttr->isObject()) + anOwner = aRefAttr->object(); + else + { + AttributePtr anAttr = aRefAttr->attr(); + anOwner = anAttr->owner(); + } + FeaturePtr anAttrOwnerFeature = ModelAPI_Feature::feature(anOwner); + if (!anAttrOwnerFeature) + return true; + AttributeBooleanPtr aCopyAttr = anAttrOwnerFeature->boolean(SketchPlugin_SketchEntity::COPY_ID()); + if (!aCopyAttr || !aCopyAttr->value()) + return true; // feature is not a copy, thus valid + + // check the copy feature is already referred by the "Multi" feature + FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner()); + AttributeRefListPtr aRefList = aMultiFeature->reflist(theArguments.front()); + for (int i = 0; i < aRefList->size(); ++i) + { + FeaturePtr aRefOwner = ModelAPI_Feature::feature(aRefList->object(i)); + if (aRefOwner == anAttrOwnerFeature) + { + theError = "Attribute refers to the object generated by this feature"; + return false; + } + } + + return true; +} + +bool SketchPlugin_SketchFeatureValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return false; + } + + // check the attribute refers to a sketch feature + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + bool isSketchFeature = aRefAttr->isObject(); + if (isSketchFeature) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + isSketchFeature = aFeature.get() != NULL; + if (isSketchFeature) { + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(aFeature); + isSketchFeature = aSketchFeature.get() != NULL; + } + } + + if (isSketchFeature) + return true; + + theError = "The object selected is not a sketch feature"; + return false; +} + +bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + if (theAttribute->attributeType() != ModelAPI_AttributeDouble::typeId()) { + theError = "The attribute with the %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return false; + } + + AttributeDoublePtr anAngleAttr = + std::dynamic_pointer_cast(theAttribute); + + FeaturePtr aMultiRotation = ModelAPI_Feature::feature(theAttribute->owner()); + AttributeStringPtr anAngleType = + aMultiRotation->string(SketchPlugin_MultiRotation::ANGLE_TYPE()); + AttributeIntegerPtr aNbCopies = + aMultiRotation->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID()); + + if (anAngleType->value() != "FullAngle") + { + double aFullAngleValue = anAngleAttr->value() * (aNbCopies->value() - 1); + if (aFullAngleValue < -1.e-7 || aFullAngleValue > 359.9999999) + { + theError = "Rotation single angle should produce full angle less than 360 degree"; + return false; + } + } + else + { + double aFullAngleValue = anAngleAttr->value(); + if (aFullAngleValue < -1.e-7 || aFullAngleValue > 360.0000001) + { + theError = "Rotation full angle should be in range [0, 360]"; + return false; + } + } + + return true; +} + +bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + AttributePoint2DArrayPtr aPolesArray = + std::dynamic_pointer_cast(theAttribute); + if (!aPolesArray) + return false; + + if (aPolesArray->size() < 2) { + theError = "Number of B-spline poles should be 2 and more"; + return false; + } + + return true; +}