#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_Line.h"
#include "SketchPlugin_MacroArc.h"
#include <GeomAPI_Circ.h>
#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Ellipse.h>
#include <GeomAPI_Lin.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Vertex.h>
+
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <algorithm>
#include <cmath>
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<std::string>& theArguments,
Events_InfoMessage& theError) const
bool isObject = aRefAttr->isObject();
ObjectPtr anObject = aRefAttr->object();
- if (isObject && anObject.get()) {
- FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
+ if (!isObject || !anObject.get()) {
+ theError = "It uses an empty object";
+ return false;
+ }
- AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA);
- ObjectPtr aOtherObject = aOtherAttr->object();
- FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
- if (!aOtherFea)
- return true;
+ FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
- 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());
+ 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<GeomDataAPI_Point2D>(anAttr);
+ if (aPointAttr) {
+ return anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+ (aPointAttr->id() == SketchPlugin_BSpline::START_ID() ||
+ aPointAttr->id() == SketchPlugin_BSpline::END_ID());
}
- }
- 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;
+
+ AttributePoint2DArrayPtr aPntArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(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);
}
- }
- 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());
return false;
+ };
+
+ isValid = false;
+ AttributePoint2DArrayPtr aBSplinePoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+ aRefFea->attribute(SketchPlugin_BSplineBase::POLES_ID()));
+ // additional check the B-spline edge and the other edge have a coincident boundary point
+ std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(aRefFea);
+ for (std::set<FeaturePtr>::iterator anIt = aCoincidences.begin();
+ anIt != aCoincidences.end() && !isValid; ++anIt) {
+ std::set<FeaturePtr> 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);
+
+ isValid = aCoinc.find(aOtherFea) != aCoinc.end();
}
- return true;
- }
- else {
- theError = "It uses an empty object";
- return false;
}
- return true;
+ return isValid;
}
bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
AttributeRefAttrPtr aOtherAttr = anOwner->refattr(aParamA);
ObjectPtr aOtherObject = aOtherAttr->object();
FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
- if (!aOtherFea)
- return true;
// at least one feature should be a line
if (aRefFea->getKind() != SketchPlugin_Line::ID() &&
- aOtherFea->getKind() != SketchPlugin_Line::ID()) {
+ aOtherFea && aOtherFea->getKind() != SketchPlugin_Line::ID()) {
theError = "At least one feature should be a line";
return false;
}
+ else if (isSpline(aRefFea) || isSpline(aOtherFea)) {
+ theError = "B-spline is not supported";
+ return false;
+ }
}
else {
theError = "It uses an empty object";
std::string aType[2];
std::list<std::string> 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;
}
}
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;
}
if (aFeature->getKind() == SketchPlugin_Point::ID())
++aNbPoints;
else if (aFeature->getKind() == SketchPlugin_Line::ID() ||
- aFeature->getKind() == SketchPlugin_Arc::ID())
+ aFeature->getKind() == SketchPlugin_Arc::ID() ||
+ aFeature->getKind() == SketchPlugin_EllipticArc::ID())
++aNbLines;
}
}
}
}
else {
- theError = "Unable to build transversal arc on %1";
+ theError = "Unable to build perpendicular arc on %1";
theError.arg(anAttrFeature->getKind());
return false;
}
}
AttributeReferencePtr aFeatureAttr =
std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
+ std::shared_ptr<SketchPlugin_Feature> aSplitFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
ObjectPtr anAttrObject = aFeatureAttr->value();
+ if (!anAttrObject) {
+ AttributePtr aPreviewAttr = aSplitFeature->attribute(SketchPlugin_Trim::PREVIEW_OBJECT());
+ aFeatureAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(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<ResultPtr> 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<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
- ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
- SketchPlugin_ConstraintCoincidence::ID(),
- aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
-
- GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
- std::shared_ptr<SketchPlugin_Feature> aSFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
- SketchPlugin_Sketch* aSketch = aSFeature->sketch();
-
- std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
- std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
- aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
- std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
- aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
- std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
- aData->attribute(SketchPlugin_Sketch::NORM_ID()));
- std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
-
- typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
- std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
- std::list<std::shared_ptr<ModelAPI_Object> > > > 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;
- }
+ std::set<ResultPtr> 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<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
+ ModelGeomAlgo_Point2D::getPointsOfReference(anAttrFeature,
+ SketchPlugin_ConstraintCoincidence::ID(),
+ aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
+
+ GeomShapePtr anAttrShape = (*anEdgeShapes.begin())->shape();
+ std::shared_ptr<SketchPlugin_Feature> aSFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(anAttrFeature);
+ if (!aSFeature || aSFeature->isCopy())
+ return false;
+ SketchPlugin_Sketch* aSketch = aSFeature->sketch();
+
+ std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
+ std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
+ aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
+ std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
+ std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ aData->attribute(SketchPlugin_Sketch::NORM_ID()));
+ std::shared_ptr<GeomAPI_Dir> aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
+
+ typedef std::map<std::shared_ptr<GeomAPI_Pnt>,
+ std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
+ std::list<std::shared_ptr<ModelAPI_Object> > > > 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;
}
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;
-
// point on feature
AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aTrimFeature->data()->attribute(SketchPlugin_Trim::PREVIEW_POINT()));
std::map<ObjectPtr, std::map<std::shared_ptr<GeomAPI_Pnt>,
std::pair<std::list<std::shared_ptr<GeomDataAPI_Point2D> >,
std::list<std::shared_ptr<ModelAPI_Object> > > > > anObjectToPoints;
- SketchPlugin_Trim::fillObjectShapes(aBaseObject, aSketch->data()->owner(),
- aCashedShapes, anObjectToPoints);
+ SketchPlugin_SegmentationTools::fillObjectShapes(
+ aTrimFeature.get(), aBaseObject, aCashedShapes, anObjectToPoints);
const std::set<GeomShapePtr>& aShapes = aCashedShapes[aBaseObject];
return aShapes.size() > 1;
std::shared_ptr<GeomAPI_Dir> aNormal = aPlane->direction();
std::shared_ptr<GeomAPI_Pnt> anOrigin = aPlane->location();
+ bool aValid = true;
if (anEdge->isLine()) {
std::shared_ptr<GeomAPI_Lin> aLine = anEdge->line();
std::shared_ptr<GeomAPI_Dir> 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<GeomAPI_Circ> aCircle = anEdge->circle();
std::shared_ptr<GeomAPI_Dir> 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<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+ std::shared_ptr<GeomAPI_Dir> 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.");
}
- theError = "Error: Selected object is not line, circle or arc.";
- return false;
+ return aValid;
}
return true;
}
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const
+{
+ AttributePoint2DArrayPtr aPolesArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+ if (!aPolesArray)
+ return false;
+
+ if (aPolesArray->size() < 2) {
+ theError = "Number of B-spline poles should be 2 or more";
+ return false;
+ }
+
+ return true;
+}