aFactory->registerValidator("PartSet_AngleSelection", new PartSet_AngleSelection);
aFactory->registerValidator("PartSet_EqualSelection", new PartSet_EqualSelection);
aFactory->registerValidator("PartSet_CollinearSelection", new PartSet_CollinearSelection);
+ aFactory->registerValidator("PartSet_MiddlePointSelection", new PartSet_MiddlePointSelection);
aFactory->registerValidator("PartSet_DifferentObjects", new PartSet_DifferentObjectsValidator);
aFactory->registerValidator("PartSet_CoincidentAttr", new PartSet_CoincidentAttr);
aFactory->registerValidator("PartSet_SketchEntityValidator", new PartSet_SketchEntityValidator);
}
}
+bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
+{
+ if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
+ return isEmptySelectionValid(theOperation);
+ else
+ return shapesNbLines(theSelection) == 1 && shapesNbPoints(theSelection) == 1;
+}
+
std::string PartSet_DifferentObjectsValidator::errorMessage(
const PartSet_DifferentObjectsValidator::ErrorType& theType,
PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const;
};
+//! \ingroup Validators
+//! A class to validate a selection for Middle point constraints operation
+class PartSet_MiddlePointSelection : public ModuleBase_SelectionValidator
+{
+public:
+ PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const;
+};
+
////////////// Attribute validators ////////////////
<file>icons/bool_common.png</file>
<file>icons/plane_view.png</file>
<file>icons/collinear.png</file>
+ <file>icons/middlepoint.png</file>
</qresource>
</RCC>
SketchPlugin_ConstraintCollinear.h
SketchPlugin_ConstraintDistance.h
SketchPlugin_ConstraintLength.h
+ SketchPlugin_ConstraintMiddle.h
SketchPlugin_ConstraintParallel.h
SketchPlugin_ConstraintPerpendicular.h
SketchPlugin_ConstraintRadius.h
SketchPlugin_ConstraintCollinear.cpp
SketchPlugin_ConstraintDistance.cpp
SketchPlugin_ConstraintLength.cpp
+ SketchPlugin_ConstraintMiddle.cpp
SketchPlugin_ConstraintParallel.cpp
SketchPlugin_ConstraintPerpendicular.cpp
SketchPlugin_ConstraintRadius.cpp
TestConstraintTangent.py
TestConstraintMirror.py
TestConstraintAngle.py
+ TestConstraintMiddlePoint.py
TestMultiRotation.py
TestMultiTranslation.py
TestFillet.py
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintMiddle.cpp
+// Created: 26 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SketchPlugin_ConstraintMiddle.h"
+
+SketchPlugin_ConstraintMiddle::SketchPlugin_ConstraintMiddle()
+{
+}
+
+void SketchPlugin_ConstraintMiddle::initAttributes()
+{
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+void SketchPlugin_ConstraintMiddle::execute()
+{
+}
+
+AISObjectPtr SketchPlugin_ConstraintMiddle::getAISObject(AISObjectPtr thePrevious)
+{
+ if (!sketch())
+ return thePrevious;
+
+ AISObjectPtr anAIS = thePrevious;
+ if (!anAIS) {
+ // TODO
+ //anAIS = SketcherPrs_Factory::collinearConstraint(this, sketch()->coordinatePlane());
+ }
+ return anAIS;
+}
+
+
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintMiddle.h
+// Created: 27 Jan 2016
+// Author: Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintMiddle_H_
+#define SketchPlugin_ConstraintMiddle_H_
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_ConstraintBase.h"
+
+/** \class SketchPlugin_ConstraintMiddle
+ * \ingroup Plugins
+ * \brief Feature for creation of a new constraintwhich places a point in the middle of a line
+ *
+ * This constraint has two attributes:
+ * SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintMiddle : public SketchPlugin_ConstraintBase
+{
+ public:
+ /// Parallel constraint kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_CONSTRAINT_MIDDLE_ID("SketchConstraintMiddle");
+ return MY_CONSTRAINT_MIDDLE_ID;
+ }
+ /// \brief Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_ConstraintMiddle::ID();
+ return MY_KIND;
+ }
+
+ /// \brief Creates a new part document if needed
+ SKETCHPLUGIN_EXPORT virtual void execute();
+
+ /// \brief Request for initialization of data model of the feature: adding all attributes
+ SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Returns the AIS preview
+ SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+ /// \brief Use plugin manager for features creation
+ SketchPlugin_ConstraintMiddle();
+};
+
+#endif
#include <SketchPlugin_ConstraintFillet.h>
#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMiddle.h>
#include <SketchPlugin_ConstraintMirror.h>
#include <SketchPlugin_ConstraintParallel.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
new SketchPlugin_SolverErrorValidator);
aFactory->registerValidator("SketchPlugin_FilletVertexValidator",
new SketchPlugin_FilletVertexValidator);
+ aFactory->registerValidator("SketchPlugin_MiddlePointAttr",
+ new SketchPlugin_MiddlePointAttrValidator);
// register this plugin
ModelAPI_Session::get()->registerPlugin(this);
return FeaturePtr(new SketchPlugin_ConstraintEqual);
} else if (theFeatureID == SketchPlugin_ConstraintTangent::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintTangent);
+ } else if (theFeatureID == SketchPlugin_ConstraintMiddle::ID()) {
+ return FeaturePtr(new SketchPlugin_ConstraintMiddle);
} else if (theFeatureID == SketchPlugin_ConstraintMirror::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintMirror);
} else if (theFeatureID == SketchPlugin_ConstraintFillet::ID()) {
return true;
}
+
+bool SketchPlugin_MiddlePointAttrValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const
+{
+ if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
+ theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
+ 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<ModelAPI_Feature>(theAttribute->owner());
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+ AttributeRefAttrPtr anOtherAttr = anAttributeFeature->data()->refattr(aParamA);
+
+ AttributeRefAttrPtr aRefAttrs[2] = {aRefAttr, anOtherAttr};
+ int aNbPoints = 0;
+ int aNbLines = 0;
+ for (int i = 0; i < 2; ++i) {
+ if (!aRefAttrs[i]->isObject())
+ ++aNbPoints;
+ else {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttrs[i]->object());
+ if (!aFeature) {
+ if (aNbPoints + aNbLines != 0)
+ return true;
+ else continue;
+ }
+
+ if (aFeature->getKind() == SketchPlugin_Point::ID())
+ ++aNbPoints;
+ else if (aFeature->getKind() == SketchPlugin_Line::ID())
+ ++aNbLines;
+ }
+ }
+
+ if (aNbPoints != 1 || aNbLines != 1) {
+ theError = "Middle point constraint allows points and lines only";
+ return false;
+ }
+ return true;
+}
std::string& theError) const;
};
+
+/**\class SketchPlugin_MiddlePointAttrValidator
+ * \ingroup Validators
+ * \brief Validator for the middle point constraint input.
+ *
+ * It checks that attributes of the Middle point constraint are correct.
+ */
+class SketchPlugin_MiddlePointAttrValidator : public ModelAPI_AttributeValidator
+{
+ public:
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute (not used)
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ std::string& theError) const;
+};
+
#endif
--- /dev/null
+"""
+ TestConstraintCoincidence.py
+ Unit test of SketchPlugin_ConstraintCoincidence class
+
+ SketchPlugin_Constraint
+ static const std::string MY_CONSTRAINT_VALUE("ConstraintValue");
+ static const std::string MY_FLYOUT_VALUE_PNT("ConstraintFlyoutValuePnt");
+ static const std::string MY_ENTITY_A("ConstraintEntityA");
+ static const std::string MY_ENTITY_B("ConstraintEntityB");
+ static const std::string MY_ENTITY_C("ConstraintEntityC");
+ static const std::string MY_ENTITY_D("ConstraintEntityD");
+
+ SketchPlugin_ConstraintCoincidence
+ static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidence");
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2016-01-29"
+TOLERANCE = 1.e-7
+
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+def checkMiddlePoint(point, line):
+ aStart = geomDataAPI_Point2D(line.attribute("StartPoint"))
+ aEnd = geomDataAPI_Point2D(line.attribute("EndPoint"))
+ assert math.fabs(aStart.x() + aEnd.x() - 2.0 * point.x()) <= TOLERANCE, "x1={0}, x2={1}, mid={2}".format(aStart.x(), aEnd.x(), point.x())
+ assert math.fabs(aStart.y() + aEnd.y() - 2.0 * point.y()) <= TOLERANCE, "y1={0}, y2={1}, mid={2}".format(aStart.y(), aEnd.y(), point.y())
+
+
+#=========================================================================
+# Start of test
+#=========================================================================
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+# add an origin
+aSession.startOperation()
+aFeature = aDocument.addFeature("Point")
+aFeature.real("x").setValue(0.)
+aFeature.real("y").setValue(0.)
+aFeature.real("z").setValue(0.)
+anOriginName = aFeature.name()
+aSession.finishOperation()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchFeature = featureToCompositeFeature(aDocument.addFeature("Sketch"))
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Create a two lines
+#=========================================================================
+aSession.startOperation()
+aLine1 = aSketchFeature.addFeature("SketchLine")
+aStartPoint1 = geomDataAPI_Point2D(aLine1.attribute("StartPoint"))
+aEndPoint1 = geomDataAPI_Point2D(aLine1.attribute("EndPoint"))
+aStartPoint1.setValue(50., 0.)
+aEndPoint1.setValue(100., 25.)
+aLine2 = aSketchFeature.addFeature("SketchLine")
+aStartPoint2 = geomDataAPI_Point2D(aLine2.attribute("StartPoint"))
+aEndPoint2 = geomDataAPI_Point2D(aLine2.attribute("EndPoint"))
+aStartPoint2.setValue(10., 100.)
+aEndPoint2.setValue(100., 25.)
+aSession.finishOperation()
+#=========================================================================
+# Make end point of second line middle point on first line
+#=========================================================================
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(aEndPoint2)
+reflistB.setObject(aLine1.lastResult())
+aConstraint.execute()
+aSession.finishOperation()
+#=========================================================================
+# Check values and move one constrainted object
+#=========================================================================
+checkMiddlePoint(aEndPoint2, aLine1)
+deltaX, deltaY = -80.0, -40.0
+aSession.startOperation()
+aStartPoint1.setValue(aStartPoint1.x() + deltaX, aStartPoint1.y() + deltaY)
+aSession.finishOperation()
+checkMiddlePoint(aEndPoint2, aLine1)
+#=========================================================================
+# Remove constraint and move the line
+#=========================================================================
+aCurX, aCurY = aEndPoint2.x(), aEndPoint2.y()
+aSession.startOperation()
+aDocument.removeFeature(aConstraint)
+aSession.finishOperation()
+aSession.startOperation()
+aEndPoint1.setValue(90., 0.)
+aSession.finishOperation()
+assert (aEndPoint2.x() == aCurX and aEndPoint2.y() == aCurY)
+
+#=========================================================================
+# Set external point as a middle point
+#=========================================================================
+# create origin
+aSession.startOperation()
+anOrigRes = modelAPI_Result(aDocument.objectByName("Construction", anOriginName))
+assert (anOrigRes)
+anOrigShape = anOrigRes.shape()
+assert (anOrigShape)
+anOrigin = aSketchFeature.addFeature("SketchPoint")
+anOriginCoord = geomDataAPI_Point2D(anOrigin.attribute("PointCoordindates"))
+anOriginCoord.setValue(0., 0.)
+anOrigin.selection("External").setValue(anOrigRes, anOrigShape)
+aSession.finishOperation()
+# middle point constraint
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setObject(aLine2.lastResult())
+reflistB.setObject(anOrigin.lastResult())
+aSession.finishOperation()
+checkMiddlePoint(anOriginCoord, aLine2)
+#=========================================================================
+# Check origin coordinates does not changed
+#=========================================================================
+assert (anOriginCoord.x() == 0. and anOriginCoord.y() == 0.)
+#=========================================================================
+# End of test
+#=========================================================================
<group id="Basic">
<feature
id="Sketch"
- nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear"
+ nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear SketchConstraintMiddle"
when_nested="accept abort"
title="Sketch"
tooltip="Create sketch"
</sketch_shape_selector>
<validator id="PartSet_CollinearSelection"/>
</feature>
+
+ <!-- SketchConstraintMiddle -->
+ <feature id="SketchConstraintMiddle" title="Middle point" tooltip="Create constraint for setting middle point on a line" icon=":icons/middlepoint.png">
+ <sketch_shape_selector id="ConstraintEntityA" label="First object" tooltip="Select a first object" shape_types="vertex edge">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
+ <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityB"/>
+ </sketch_shape_selector>
+ <sketch_shape_selector id="ConstraintEntityB" label="Second object" tooltip="Select a second object" shape_types="vertex edge">
+ <validator id="PartSet_DifferentObjects"/>
+ <validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
+ <validator id="SketchPlugin_MiddlePointAttr" parameters="ConstraintEntityA"/>
+ </sketch_shape_selector>
+ <validator id="PartSet_MiddlePointSelection"/>
+ </feature>
</group>
const GroupID& theGroupID,
std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+ createConstraintMiddlePoint(ConstraintPtr theConstraint,
+ const GroupID& theGroupID,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity);
aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType,
aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
break;
+ case CONSTRAINT_MIDDLE_POINT:
+ aResult = createConstraintMiddlePoint(theConstraint, theGroupID,
+ aPoint1, GCS_ENTITY_WRAPPER(theEntity1));
+ break;
case CONSTRAINT_PT_PT_DISTANCE:
aResult = createConstraintDistancePointPoint(theConstraint, theGroupID,
GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)),
return aResult;
}
+// calculate length of the line
+static inline double lineLength(const GCS::Line& theLine)
+{
+ double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+ return sqrt(aDir[0] * aDir[0] + aDir[1] * aDir[1]);
+}
+
+// check the point is on the line
+static inline bool isPointOnLine(const GCS::Point& thePoint, const GCS::Line& theLine)
+{
+ double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)};
+ double aVec[2] = {*(thePoint.x) - *(theLine.p1.x), *(thePoint.y) - *(theLine.p1.y)};
+ double aCross = aVec[0] * aDir[1] - aVec[1] * aDir[0];
+ return fabs(aCross) < tolerance;
+}
+
+ConstraintWrapperPtr createConstraintMiddlePoint(
+ ConstraintPtr theConstraint,
+ const GroupID& theGroupID,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity)
+{
+ GCSPointPtr aPoint = thePoint->point();
+ std::shared_ptr<GCS::Line> aLine = std::dynamic_pointer_cast<GCS::Line>(theEntity->entity());
+ if (!aLine)
+ return ConstraintWrapperPtr();
+
+ std::list<GCSConstraintPtr> aConstrList;
+ aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+ double aDist = lineLength(*aLine);
+ std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aDistance =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(createParameter(theGroupID, aDist));
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintP2PDistance(*aPoint, aLine->p1, aDistance->parameter())));
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintP2PDistance(*aPoint, aLine->p2, aDistance->parameter())));
+
+ // Workaround to avoid conflicting constraints when the point is already placed on line
+ if (thePoint->group() != GID_UNKNOWN && isPointOnLine(*aPoint, *aLine)) {
+ std::shared_ptr<GeomDataAPI_Point2D> aCoord =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(thePoint->baseAttribute());
+ if (aCoord) {
+ *(aPoint->x) = (*(aLine->p1.x) + *(aLine->p2.x)) * 0.5;
+ *(aPoint->y) = (*(aLine->p1.y) + *(aLine->p2.y)) * 0.5;
+ aCoord->setValue(*(aPoint->x), *(aPoint->y));
+ }
+ }
+
+ std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aResult(new PlaneGCSSolver_ConstraintWrapper(
+ theConstraint, aConstrList, CONSTRAINT_MIDDLE_POINT));
+ aResult->setGroup(theGroupID);
+ std::list<EntityWrapperPtr> aSubs(1, thePoint);
+ aSubs.push_back(theEntity);
+ aResult->setEntities(aSubs);
+ aResult->setValueParameter(aDistance);
+ return aResult;
+}
+
+
ConstraintWrapperPtr createConstraintDistancePointPoint(
ConstraintPtr theConstraint,
const GroupID& theGroupID,
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMiddle.h>
#include <SketchPlugin_ConstraintMirror.h>
#include <SketchPlugin_ConstraintParallel.h>
#include <SketchPlugin_ConstraintPerpendicular.h>
return CONSTRAINT_TANGENT;
else if (aType == SketchPlugin_ConstraintCollinear::ID())
return CONSTRAINT_COLLINEAR;
+ else if (aType == SketchPlugin_ConstraintMiddle::ID())
+ return CONSTRAINT_MIDDLE_POINT;
return CONSTRAINT_UNKNOWN;
}
CONSTRAINT_PT_PT_COINCIDENT,
CONSTRAINT_PT_ON_LINE,
CONSTRAINT_PT_ON_CIRCLE,
+ CONSTRAINT_MIDDLE_POINT,
CONSTRAINT_DISTANCE, // base distance if we don't know the measured objects yet
CONSTRAINT_PT_PT_DISTANCE,
CONSTRAINT_PT_LINE_DISTANCE,
case CONSTRAINT_PT_PT_COINCIDENT: return SLVS_C_POINTS_COINCIDENT;
case CONSTRAINT_PT_ON_LINE: return SLVS_C_PT_ON_LINE;
case CONSTRAINT_PT_ON_CIRCLE: return SLVS_C_PT_ON_CIRCLE;
+ case CONSTRAINT_MIDDLE_POINT: return SLVS_C_AT_MIDPOINT;
case CONSTRAINT_PT_PT_DISTANCE: return SLVS_C_PT_PT_DISTANCE;
case CONSTRAINT_PT_LINE_DISTANCE: return SLVS_C_PT_LINE_DISTANCE;
case CONSTRAINT_ANGLE: return SLVS_C_ANGLE;
case SLVS_C_POINTS_COINCIDENT: return CONSTRAINT_PT_PT_COINCIDENT;
case SLVS_C_PT_ON_LINE: return CONSTRAINT_PT_ON_LINE;
case SLVS_C_PT_ON_CIRCLE: return CONSTRAINT_PT_ON_CIRCLE;
+ case SLVS_C_AT_MIDPOINT: return CONSTRAINT_MIDDLE_POINT;
case SLVS_C_PT_PT_DISTANCE: return CONSTRAINT_PT_PT_DISTANCE;
case SLVS_C_PT_LINE_DISTANCE: return CONSTRAINT_PT_LINE_DISTANCE;
case SLVS_C_EQUAL_LENGTH_LINES: return CONSTRAINT_EQUAL_LINES;