X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Validators.cpp;h=e226f229e8a22af9f84b98dc27a5c414fa6adf7f;hb=a0fa395fd2a0ddb16cb9aed4dab180f2681b4447;hp=ed22a6420b086cae59f833b975ccedc47b0d3e5a;hpb=b3695c3af5289903f1c0fa01bbb7c40203c5e544;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 ed22a6420..e226f229e --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2020 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 @@ -12,24 +12,31 @@ // // 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 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "SketchPlugin_Validators.h" #include "SketchPlugin_Arc.h" +#include "SketchPlugin_BSpline.h" +#include "SketchPlugin_BSplinePeriodic.h" #include "SketchPlugin_Circle.h" #include "SketchPlugin_ConstraintCoincidence.h" +#include "SketchPlugin_ConstraintCoincidenceInternal.h" #include "SketchPlugin_ConstraintDistance.h" #include "SketchPlugin_ConstraintRigid.h" #include "SketchPlugin_ConstraintTangent.h" +#include "SketchPlugin_Ellipse.h" +#include "SketchPlugin_EllipticArc.h" #include "SketchPlugin_Fillet.h" +#include "SketchPlugin_CurveFitting.h" #include "SketchPlugin_Line.h" #include "SketchPlugin_MacroArc.h" #include "SketchPlugin_MacroCircle.h" +#include "SketchPlugin_MultiRotation.h" +#include "SketchPlugin_Offset.h" #include "SketchPlugin_Point.h" #include "SketchPlugin_Sketch.h" #include "SketchPlugin_Trim.h" @@ -42,8 +49,8 @@ #include #include #include +#include #include - #include #include #include @@ -58,18 +65,33 @@ #include #include +#include #include #include +#include #include #include #include + #include +#include #include #include +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#endif + const double tolerance = 1.e-7; +static bool isSpline(FeaturePtr theFeature) +{ + return theFeature && (theFeature->getKind() == SketchPlugin_BSpline::ID() || + theFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()); +} + + bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, Events_InfoMessage& theError) const @@ -143,53 +165,132 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute // 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); + bool isObject = aRefAttr->isObject(); + ObjectPtr anObject = aRefAttr->object(); + if (!isObject || !anObject.get()) { + theError = "It uses an empty object"; + return false; + } + + 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; + } + else if (isSpline(aRefFea) && isSpline(aOtherFea)) { + theError = "Two B-splines cannot be tangent"; + return false; + } + + bool isValid = true; + bool hasSpline = isSpline(aRefFea); + if (!hasSpline && isSpline(aOtherFea)) { + hasSpline = true; + std::swap(aRefFea, aOtherFea); + } + if (hasSpline) { + auto isApplicableCoincidence = [](FeaturePtr theFeature, const std::string& theAttrName) { + AttributeRefAttrPtr aRefAttr = theFeature->refattr(theAttrName); + if (aRefAttr->isObject()) + return false; + AttributePtr anAttr = aRefAttr->attr(); + FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner()); + AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast(anAttr); + if (aPointAttr) { + return anOwner->getKind() == SketchPlugin_BSpline::ID() && + (aPointAttr->id() == SketchPlugin_BSpline::START_ID() || + aPointAttr->id() == SketchPlugin_BSpline::END_ID()); + } + + AttributePoint2DArrayPtr aPntArray = + std::dynamic_pointer_cast(anAttr); + if (aPntArray && anOwner->getKind() == SketchPlugin_BSpline::ID()) { + // check index of the pole + AttributeIntegerPtr anIndex = theAttrName == SketchPlugin_Constraint::ENTITY_A() ? + theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A()) : + theFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B()); + return anIndex && (anIndex->value() == 0 || anIndex->value() == aPntArray->size() - 1); + } + return false; + }; + + isValid = false; + AttributePoint2DArrayPtr aBSplinePoles = std::dynamic_pointer_cast( + aRefFea->attribute(SketchPlugin_BSplineBase::POLES_ID())); + // additional check the B-spline edge and the other edge have a coincident boundary point + std::set aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(aRefFea); + for (std::set::iterator anIt = aCoincidences.begin(); + anIt != aCoincidences.end() && !isValid; ++anIt) { + std::set aCoinc; + if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_A())) + SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_B(), + aCoinc, true); + else if (isApplicableCoincidence(*anIt, SketchPlugin_Constraint::ENTITY_B())) + SketchPlugin_Tools::findCoincidences(*anIt, SketchPlugin_Constraint::ENTITY_A(), + aCoinc, true); + + std::set::iterator aFoundCoinc = aCoinc.find(aOtherFea); + if (aFoundCoinc != aCoinc.end()) { + // do not take into account internal constraints + AttributeReferencePtr aParent = + (*aFoundCoinc)->reference(SketchPlugin_SketchEntity::PARENT_ID()); + isValid = !aParent || !aParent->isInitialized() || aParent->value() != aRefFea; + } + } + } + + return isValid; +} + +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 %1 type is not processed"; + theError.arg(theAttribute->attributeType()); + return false; + } + + std::string aParamA = theArguments.front(); + + 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_Line::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Arc::ID() && - aOtherFea->getKind() != SketchPlugin_Circle::ID()) { - theError = "It refers to a %1, but %2 is neither an %3 nor %4"; - theError.arg(SketchPlugin_Line::ID()).arg(aParamA) - .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID()); - return false; - } - } - else if (aRefFea->getKind() == SketchPlugin_Arc::ID() || - aRefFea->getKind() == SketchPlugin_Circle::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Line::ID() && - aOtherFea->getKind() != SketchPlugin_Arc::ID() && - aOtherFea->getKind() != SketchPlugin_Circle::ID()) { - theError = "It refers to an %1, but %2 is not a %3 or an %4 or a %5"; - theError.arg(SketchPlugin_Arc::ID()).arg(aParamA) - .arg(SketchPlugin_Line::ID()).arg(SketchPlugin_Arc::ID()) - .arg(SketchPlugin_Circle::ID()); - return false; - } + // at least one feature should be a line + if (aRefFea->getKind() != SketchPlugin_Line::ID() && + aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) { + theError = "At least one feature should be a line"; + return false; } - else { - theError = "It refers to %1, but should refer to %2 or %3 or %4"; - theError.arg(aRefFea->getKind()).arg(SketchPlugin_Line::ID()) - .arg(SketchPlugin_Arc::ID()).arg(SketchPlugin_Circle::ID()); + else if (isSpline(aRefFea) || isSpline(aOtherFea)) { + theError = "B-spline is not supported"; return false; } - return true; } else { theError = "It uses an empty object"; @@ -268,33 +369,36 @@ bool SketchPlugin_EqualAttrValidator::isValid(const AttributePtr& theAttribute, std::string aType[2]; std::list anArguments; for (int i = 0; i < 2; i++) { - ObjectPtr anObject = aRefAttr[i]->object(); - if (!anObject.get()) { - theError = "An empty object is used."; - return false; - } - - aFeature = ModelAPI_Feature::feature(anObject); - if (!aFeature.get()) { - theError = "An empty feature is used."; - return false; - } + aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object()); + if (!aFeature.get()) + return true; aType[i] = aFeature->getKind(); if (aFeature->getKind() != SketchPlugin_Line::ID() && aFeature->getKind() != SketchPlugin_Circle::ID() && - aFeature->getKind() != SketchPlugin_Arc::ID()) { - theError = "The %1 feature kind of attribute is wrong. It should be %2 or %3 or %4"; - theError.arg(aFeature->getKind()).arg(SketchPlugin_Line::ID()) - .arg(SketchPlugin_Circle::ID()).arg(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 %1 and %2 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; } @@ -320,6 +424,15 @@ bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, for(int anInd = 0; anInd < aSelAttr->size(); anInd++) { ObjectPtr aSelObject = aSelAttr->object(anInd); + + // B-splines are not supported in Mirror yet + FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject); + if (aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() || + aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) { + theError = "Not supported"; + return false; + } + std::string aName = aSelObject.get() ? aSelObject->data()->name() : ""; std::list::iterator aMirIter = aMirroredObjects.begin(); for (; aMirIter != aMirroredObjects.end(); aMirIter++) @@ -344,8 +457,6 @@ bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttri // 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 aConstraint = std::dynamic_pointer_cast(theAttribute->owner()); AttributeRefAttrPtr aRefAttrA = aConstraint->data()->refattr(aParamA); @@ -410,6 +521,7 @@ bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, FeaturePtr aFeature = std::dynamic_pointer_cast(theAttribute->owner()); AttributeRefListPtr aSelAttr = std::dynamic_pointer_cast(theAttribute); + std::set aSelected; AttributeRefListPtr aRefListOfInitial = std::dynamic_pointer_cast( aFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); @@ -421,20 +533,49 @@ bool SketchPlugin_CopyValidator::isValid(const AttributePtr& theAttribute, std::list::iterator anObjIter; for(int anInd = 0; anInd < aSelAttr->size(); anInd++) { ObjectPtr aSelObject = aSelAttr->object(anInd); + if (aSelected.find(aSelObject) != aSelected.end()) { + theError = "Error: An object selected twice"; + return false; + } + aSelected.insert(aSelObject); + anObjIter = anInitialObjects.begin(); for (; anObjIter != anInitialObjects.end(); anObjIter++) if (aSelObject == *anObjIter) break; if (anObjIter != anInitialObjects.end()) continue; + + // B-splines are not supported in Copying features + FeaturePtr aSelFeature = ModelAPI_Feature::feature(aSelObject); + if (aFeature->getKind() != SketchPlugin_Offset::ID() && + aSelFeature && (aSelFeature->getKind() == SketchPlugin_BSpline::ID() || + aSelFeature->getKind() == SketchPlugin_BSplinePeriodic::ID())) { + theError = "Not supported"; + return false; + } + anObjIter = aCopiedObjects.begin(); - for (; anObjIter != aCopiedObjects.end(); anObjIter++) - if (aSelObject == *anObjIter) { + for (; anObjIter != aCopiedObjects.end(); anObjIter++) { + bool isFound = aSelObject == *anObjIter; + if (!isFound) { + // check in the results of the feature + FeaturePtr aFeature = std::dynamic_pointer_cast(*anObjIter); + if (aFeature) { + const std::list& aResults = aFeature->results(); + for (std::list::const_iterator aResIt = aResults.begin(); + aResIt != aResults.end() && !isFound; ++aResIt) { + isFound = aSelObject == *aResIt; + } + } + } + if (isFound) { std::string aName = aSelObject.get() ? aSelObject->data()->name() : ""; theError = "The object %1 is a result of copy"; theError.arg(aName); return false; } + } } return true; } @@ -467,6 +608,8 @@ static bool hasSameTangentFeature(const std::set& theRefsList, 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())); @@ -569,7 +712,7 @@ bool SketchPlugin_FilletVertexValidator::isValid(const AttributePtr& theAttribut } if(!aConstraintCoincidence.get()) { - theError = "Error: one of the selected point does not have coicidence."; + theError = "Error: one of the selected point does not have coincidence."; return false; } @@ -709,8 +852,6 @@ bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttri // 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()); @@ -733,7 +874,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; } } @@ -754,6 +897,11 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri 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) { @@ -791,6 +939,50 @@ bool SketchPlugin_ArcTangentPointValidator::isValid(const AttributePtr& theAttri 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, Events_InfoMessage& theError) const @@ -800,27 +992,25 @@ bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribut 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 %1 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 = @@ -835,9 +1025,16 @@ 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, @@ -853,56 +1050,68 @@ bool SketchPlugin_SplitValidator::isValid(const AttributePtr& theAttribute, } 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::string aKind = anAttrFeature->getKind(); - if (aKind == SketchPlugin_Line::ID() || - aKind == SketchPlugin_Arc::ID() || - aKind == SketchPlugin_Circle::ID()) { - - 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); - 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 (aKind == SketchPlugin_Circle::ID()) - aValid = aCoincidentToFeature >= 2; - else - aValid = aCoincidentToFeature >= 1; + // B-splines are not supported by the Split yet + if (anAttrFeature->getKind() == SketchPlugin_BSpline::ID() || + anAttrFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) { + theError = "Not supported"; + return false; } + 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 || aSFeature->isCopy()) + 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; } @@ -939,11 +1148,12 @@ bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute, if (!aSketchFeature.get() || aSketchFeature->isCopy()) return aValid; - std::string aKind = aBaseFeature->getKind(); - if (aKind != SketchPlugin_Line::ID() && - aKind != SketchPlugin_Arc::ID() && - aKind != SketchPlugin_Circle::ID()) - return aValid; + // B-splines are not supported by the Trim yet + if (aBaseFeature->getKind() == SketchPlugin_BSpline::ID() || + aBaseFeature->getKind() == SketchPlugin_BSplinePeriodic::ID()) { + theError = "Not supported"; + return false; + } // point on feature AttributePoint2DPtr aPoint = std::dynamic_pointer_cast( @@ -959,8 +1169,8 @@ bool SketchPlugin_TrimValidator::isValid(const AttributePtr& theAttribute, std::map, std::pair >, std::list > > > > anObjectToPoints; - SketchPlugin_Trim::fillObjectShapes(aBaseObject, aSketch->data()->owner(), - aCashedShapes, anObjectToPoints); + SketchPlugin_SegmentationTools::fillObjectShapes( + aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints); const std::set& aShapes = aCashedShapes[aBaseObject]; return aShapes.size() > 1; @@ -978,15 +1188,21 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, AttributeSelectionPtr aFeatureAttr = std::dynamic_pointer_cast(theAttribute); + std::shared_ptr aVertex; std::shared_ptr anEdge; std::shared_ptr aSketchFeature; if (aFeatureAttr.get()) { GeomShapePtr aVal = aFeatureAttr->value(); ResultPtr aRes = aFeatureAttr->context(); - if(aVal && aVal->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->value())); - } else if(aRes && aRes->shape() && aRes->shape()->isEdge()) { - anEdge = std::shared_ptr(new GeomAPI_Edge(aFeatureAttr->context()->shape())); + if (aVal && aVal->isVertex()) + aVertex = std::shared_ptr(new GeomAPI_Vertex(aVal)); + else if (aVal && aVal->isEdge()) { + anEdge = std::shared_ptr(new GeomAPI_Edge(aVal)); + } else if(aRes && aRes->shape()) { + if (aRes->shape()->isVertex()) + aVertex = std::shared_ptr(new GeomAPI_Vertex(aRes->shape())); + else if (aRes->shape()->isEdge()) + anEdge = std::shared_ptr(new GeomAPI_Edge(aRes->shape())); } // try to convert result to sketch feature @@ -995,16 +1211,7 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, std::dynamic_pointer_cast(ModelAPI_Feature::feature(aRes)); } } - if (!anEdge) { - // check a vertex has been selected - if (aFeatureAttr->value() && aFeatureAttr->value()->isVertex()) - return true; - else { - ResultPtr aRes = aFeatureAttr->context(); - if (aRes && aRes->shape() && aRes->shape()->isVertex()) - return true; - } - + if (!aVertex && !anEdge) { theError = "The attribute %1 should be an edge or vertex"; theError.arg(theAttribute->id()); return false; @@ -1035,28 +1242,62 @@ bool SketchPlugin_ProjectionValidator::isValid(const AttributePtr& theAttribute, std::shared_ptr aNormal = aPlane->direction(); std::shared_ptr anOrigin = aPlane->location(); - if (anEdge->isLine()) { + bool aValid = true; + if (aVertex) + aValid = true; // vertex is always could be projected + else if (anEdge->isLine()) { std::shared_ptr aLine = anEdge->line(); std::shared_ptr aLineDir = aLine->direction(); double aDot = fabs(aNormal->dot(aLineDir)); - bool aValid = fabs(aDot - 1.0) >= tolerance * tolerance; + aValid = fabs(aDot - 1.0) >= tolerance * tolerance; if (!aValid) - theError = "Error: Edge is already in the sketch plane."; - return aValid; + theError = "Error: Line is orthogonal to the sketch plane."; } else if (anEdge->isCircle() || anEdge->isArc()) { std::shared_ptr aCircle = anEdge->circle(); std::shared_ptr aCircNormal = aCircle->normal(); double aDot = fabs(aNormal->dot(aCircNormal)); - bool aValid = fabs(aDot - 1.0) < tolerance * tolerance; + aValid = aDot >= tolerance * tolerance; if (!aValid) - theError.arg(anEdge->isCircle() ? "Error: Cirlce is already in the sketch plane." - : "Error: Arc is already in the sketch plane."); - return 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 = aDot >= 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."); + } + else if (anEdge->isBSpline()) { + // check B-spline is periodic and planar + std::shared_ptr aCurve(new GeomAPI_Curve(anEdge)); + std::shared_ptr aBSpline(new GeomAPI_BSpline(aCurve)); + if (aBSpline->isPeriodic()) { + GeomPlanePtr aBSplinePlane = GeomAlgoAPI_ShapeTools::findPlane(ListOfShape(1, anEdge)); + if (aBSplinePlane) { + std::shared_ptr aBSplineNormal = aBSplinePlane->direction(); + double aDot = fabs(aNormal->dot(aBSplineNormal)); + aValid = fabs(aDot - 1.0) <= tolerance * tolerance; + if (!aValid) { + // B-spline's plane is orthogonal to the sketch plane, + // thus, need to check whether B-spline is planar. + std::list aPoles = aBSpline->poles(); + for (std::list::iterator it = aPoles.begin(); + it != aPoles.end() && !aValid; ++it) { + if (aBSplinePlane->distance(*it) > tolerance) + aValid = true; // non-planar B-spline curve + } + if (!aValid) + theError = "Error: Periodic B-spline is orthogonal to the sketch plane."; + } + } + } } - theError = "Error: Selected object is not line, circle or arc."; - return false; + return aValid; } @@ -1565,3 +1806,177 @@ bool SketchPlugin_HasNoConstraint::isValid(const AttributePtr& theAttribute, } 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 + + FeaturePtr aMultiFeature = ModelAPI_Feature::feature(theAttribute->owner()); + // Collect original entities + std::set anOriginalFeatures; + if (theArguments.size() > 1) { + AttributeRefListPtr anOrigList = aMultiFeature->reflist(theArguments.back()); + for (int i = 0; i < anOrigList->size(); ++i) + { + FeaturePtr aFeature = ModelAPI_Feature::feature(anOrigList->object(i)); + if (aFeature == anAttrOwnerFeature) + return true; + } + } + + // check the copy feature is already referred by the "Multi" feature + 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() && + theAttribute->attributeType() != ModelAPI_AttributeReference::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 + bool isSketchFeature = false; + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + if (aRefAttr) { + 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; + } + } + } + else { + AttributeReferencePtr aReference = + std::dynamic_pointer_cast(theAttribute); + if (aReference) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aReference->value()); + isSketchFeature = aFeature.get() && aFeature->getKind() == SketchPlugin_Sketch::ID(); + } + } + + if (!isSketchFeature) + theError = "The object selected is not a sketch feature"; + return isSketchFeature; +} + +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 or more"; + return false; + } + + return true; +} + +bool SketchPlugin_CurveFittingValidator::isValid(const FeaturePtr& theFeature, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + AttributeRefAttrListPtr aRefAttrList = + theFeature->refattrlist(SketchPlugin_CurveFitting::POINTS_ID()); + AttributeBooleanPtr aPeriodicAttr = + theFeature->boolean(SketchPlugin_CurveFitting::PERIODIC_ID()); + + // check number of selected entities + int aMinNbPoints = aPeriodicAttr->value() ? 3 : 2; + if (aRefAttrList->size() < aMinNbPoints) { + theError = "Not enough points selected. Need at least %1 points."; + theError.arg(aMinNbPoints); + return false; + } + return true; +}