return true;
}
+
+static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+ FeaturePtr aConstrFeature;
+ std::list<AttributePtr> anAttrList;
+ if (theFeature1->getKind() == SketchPlugin_Circle::ID() ||
+ theFeature2->getKind() == SketchPlugin_Circle::ID())
+ 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<AttributePtr>& aRefsList = theFeature1->data()->refsToMe();
+ std::set<AttributePtr>::const_iterator aRefIt = aRefsList.begin();
+ for (; aRefIt != aRefsList.end(); ++aRefIt) {
+ aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefIt)->owner());
+ if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
+ continue;
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
+ AttributePtr anAttr = aRefAttr->attr();
+ if (anAttr->id() == SketchPlugin_Arc::CENTER_ID())
+ continue;
+
+ anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
+ if (anAttr == *aRefIt)
+ anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
+
+ aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
+ anAttr = aRefAttr->attr();
+ for (std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+ anIt != anAttrList.end(); ++anIt)
+ if (*anIt == anAttr)
+ return true;
+ }
+ return false;
+}
+
bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments,
std::string& theError) const
AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->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()) {
- theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is not an "
- + SketchPlugin_Arc::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;
}
}
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();
+ theError = "It refers to " + aRefFea->getKind() + ", but should refer to " + SketchPlugin_Line::ID()
+ + " or " + SketchPlugin_Arc::ID() + " or " + SketchPlugin_Circle::ID();
return false;
}
return true;
return true;
}
-
bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments,
std::string& theError) const
<feature id="SketchConstraintTangent" title="Tangent" tooltip="Create constraint defining tangency of two objects with common coincident point" icon=":icons/tangent.png">
<sketch_shape_selector id="ConstraintEntityA"
label="First object" tooltip="Select line or arc" shape_types="edge">
- <validator id="PartSet_CoincidentAttr" parameters="ConstraintEntityB"/>
+ <validator id="SketchPlugin_TangentAttr" parameters="ConstraintEntityB"/>
<validator id="PartSet_DifferentObjects"/>
</sketch_shape_selector>
<sketch_shape_selector id="ConstraintEntityB"
label="Second object" tooltip="Select line or arc" shape_types="edge">
- <validator id="PartSet_CoincidentAttr" parameters="ConstraintEntityA"/>
<validator id="SketchPlugin_TangentAttr" parameters="ConstraintEntityA"/>
<validator id="PartSet_DifferentObjects"/>
</sketch_shape_selector>
static void adjustAngle(ConstraintWrapperPtr theConstraint);
/// \brief Update mirror points
static void adjustMirror(ConstraintWrapperPtr theConstraint);
+/// \brief Update a sign of the point-line distance constraint
+static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
/// \brief Transform points to be symmetric regarding to the mirror line
static void makeMirrorPoints(EntityWrapperPtr theOriginal,
GCS_PARAMETER_WRAPPER(anIntermediate));
break;
case CONSTRAINT_TANGENT_ARC_LINE:
+ case CONSTRAINT_TANGENT_CIRCLE_LINE:
case CONSTRAINT_TANGENT_ARC_ARC:
aResult = createConstraintTangent(theConstraint, theGroupID, theType,
GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
// Update flags and parameters in constraints
if (aType == CONSTRAINT_ANGLE)
adjustAngle(theConstraint);
+ else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
+ adjustPtLineDistance(theConstraint);
}
EntityWrapperPtr PlaneGCSSolver_Builder::createFeature(
std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
{
GCSConstraintPtr aNewConstr;
- if (theType == CONSTRAINT_TANGENT_ARC_LINE) {
+ if (theType == CONSTRAINT_TANGENT_ARC_LINE || theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
std::shared_ptr<GCS::Circle> aCirc = std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
}
}
+void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
+{
+ BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+ std::shared_ptr<GeomAPI_Lin2d> aLine;
+ std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt) {
+ if ((*aSIt)->type() == ENTITY_POINT)
+ aPoint = aBuilder->point(*aSIt);
+ else if ((*aSIt)->type() == ENTITY_LINE)
+ aLine = aBuilder->line(*aSIt);
+ }
+
+ std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+ std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+ if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
+ theConstraint->setValue(theConstraint->value() * (-1.0));
+}
+
return;
}
- // Get constraint parameters and check the sign of constraint value
+ // Adjust the sign of constraint value
BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
- std::shared_ptr<GeomAPI_Pnt2d> aPoint;
- std::shared_ptr<GeomAPI_Lin2d> aLine;
- std::list<EntityWrapperPtr> aSubs = aConstraint->entities();
- std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
- for (; aSIt != aSubs.end(); ++aSIt) {
- if ((*aSIt)->type() == ENTITY_POINT)
- aPoint = aBuilder->point(*aSIt);
- else if ((*aSIt)->type() == ENTITY_LINE)
- aLine = aBuilder->line(*aSIt);
- }
-
- std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
- std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
- if (aPtLineVec->cross(aLineVec) * aConstraint->value() < 0.0 || myIsNegative) {
- aConstraint->setValue(aConstraint->value() * (-1.0));
- myStorage->addConstraint(myBaseConstraint, aConstraint);
- myIsNegative = true;
- }
+ aBuilder->adjustConstraint(aConstraint);
+ myStorage->addConstraint(myBaseConstraint, aConstraint);
}
void SketchSolver_ConstraintDistance::update()
#include <SketchSolver_Manager.h>
#include <GeomAPI_Pnt2d.h>
+#include <SketchPlugin_Circle.h>
+
+#include <cmath>
/// \brief Check whether the entities has only one shared point
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbArcs = 0;
+ int aNbCircles = 0;
bool isSwap = false; // whether need to swap arguments (arc goes before line)
std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
for (; anEntIt != theAttributes.end(); ++anEntIt) {
++aNbArcs;
isSwap = aNbLines > 0;
}
+ else if ((*anEntIt)->type() == ENTITY_CIRCLE) {
+ ++aNbCircles;
+ isSwap = aNbLines > 0;
+ }
}
- if (aNbArcs < 1) {
+ if (aNbArcs < 1 && aNbCircles < 1) {
myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
return;
}
- if (aNbLines == 1 && aNbArcs == 1)
- myType = CONSTRAINT_TANGENT_ARC_LINE;
+ if (aNbLines == 1) {
+ if (aNbArcs == 1)
+ myType = CONSTRAINT_TANGENT_ARC_LINE;
+ else if (aNbCircles == 1)
+ myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
+ }
else if (aNbArcs == 2)
myType = CONSTRAINT_TANGENT_ARC_ARC;
else {
return;
}
- if (!hasSingleCoincidence(theAttributes[2], theAttributes[3]))
+ if (myType != CONSTRAINT_TANGENT_CIRCLE_LINE &&
+ !hasSingleCoincidence(theAttributes[2], theAttributes[3]))
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
if (isSwap) {
theAttributes[3] = aTemp;
}
}
+
+void SketchSolver_ConstraintTangent::adjustConstraint()
+{
+ if (myType != CONSTRAINT_TANGENT_CIRCLE_LINE)
+ return;
+
+ ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+ AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute();
+ if (!aCircleCenter)
+ return;
+ FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner());
+ AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
+
+ if (fabs(aRadius->value()) == fabs(aConstraint->value()))
+ return;
+
+ aConstraint->setValue(aRadius->value());
+
+ // Adjust the sign of constraint value
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ aBuilder->adjustConstraint(aConstraint);
+ myStorage->addConstraint(myBaseConstraint, aConstraint);
+}
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
+
+ /// \brief This method is used in derived objects to check consistency of constraint.
+ /// E.g. the distance between line and point may be signed.
+ virtual void adjustConstraint();
};
#endif
aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
&& aCIt->second->isUsed(theFeature))
std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
+ else if (aCIt->second->getType() == CONSTRAINT_TANGENT_CIRCLE_LINE
+ && aCIt->second->isUsed(theFeature))
+ aCIt->second->update();
}
}
CONSTRAINT_EQUAL_RADIUS,
CONSTRAINT_TANGENT, // base tangency if we don't know the measured objects yet
CONSTRAINT_TANGENT_ARC_LINE,
+ CONSTRAINT_TANGENT_CIRCLE_LINE,
CONSTRAINT_TANGENT_ARC_ARC,
CONSTRAINT_MULTI_TRANSLATION,
CONSTRAINT_MULTI_ROTATION
static void adjustAngle(ConstraintWrapperPtr theConstraint);
/// \brief Update mirror points
static void adjustMirror(ConstraintWrapperPtr theConstraint);
+/// \brief Update a sign of the point-line distance constraint
+static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint);
/// \brief Transform points to be symmetric regarding to the mirror line
static void makeMirrorPoints(EntityWrapperPtr theOriginal,
if (theType == CONSTRAINT_SYMMETRIC)
return createMirror(theConstraint, theGroupID, theSketchID,
thePoint1, thePoint2, theEntity1);
+ else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
+ // replace by distance from center of circle to the line
+ const std::list<EntityWrapperPtr>& aSubs = theEntity1->subEntities();
+ EntityWrapperPtr aCenter = aSubs.front();
+ AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+ aSubs.back()->baseAttribute());
+ return createConstraint(theConstraint, theGroupID, theSketchID,
+ CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
+ }
int aType = ConstraintType::toSolveSpace(theType);
if (aType == SLVS_C_UNKNOWN)
adjustAngle(theConstraint);
else if (aType == CONSTRAINT_SYMMETRIC)
adjustMirror(theConstraint);
+ else if (aType == CONSTRAINT_PT_LINE_DISTANCE)
+ adjustPtLineDistance(theConstraint);
}
EntityWrapperPtr SolveSpaceSolver_Builder::createFeature(
return createLine(theFeature, theAttributes, theGroupID, theSketchID);
// Circle
else if (aFeatureKind == SketchPlugin_Circle::ID())
- return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
+ return createCircle(theFeature, theAttributes, theGroupID, theSketchID);
// Arc
else if (aFeatureKind == SketchPlugin_Arc::ID())
- return createArc(theFeature, theAttributes,theGroupID, theSketchID);
+ return createArc(theFeature, theAttributes, theGroupID, theSketchID);
// Point (it has low probability to be an attribute of constraint, so it is checked at the end)
else if (aFeatureKind == SketchPlugin_Point::ID()) {
AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID());
aMirroredPnt->setValue(aCoord[0], aCoord[1]);
}
}
+
+void adjustPtLineDistance(ConstraintWrapperPtr theConstraint)
+{
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+ std::shared_ptr<GeomAPI_Lin2d> aLine;
+ std::list<EntityWrapperPtr> aSubs = theConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt) {
+ if ((*aSIt)->type() == ENTITY_POINT)
+ aPoint = aBuilder->point(*aSIt);
+ else if ((*aSIt)->type() == ENTITY_LINE)
+ aLine = aBuilder->line(*aSIt);
+ }
+
+ std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+ std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+ if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0)
+ theConstraint->setValue(theConstraint->value() * (-1.0));
+}