aFactory->registerValidator("PartSet_FilletSelection", new PartSet_FilletSelection);
aFactory->registerValidator("PartSet_AngleSelection", new PartSet_AngleSelection);
aFactory->registerValidator("PartSet_EqualSelection", new PartSet_EqualSelection);
+ aFactory->registerValidator("PartSet_CollinearSelection", new PartSet_CollinearSelection);
aFactory->registerValidator("PartSet_DifferentObjects", new PartSet_DifferentObjectsValidator);
aFactory->registerValidator("PartSet_CoincidentAttr", new PartSet_CoincidentAttr);
aFactory->registerValidator("PartSet_SketchEntityValidator", new PartSet_SketchEntityValidator);
}
}
+bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
+{
+ if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
+ return isEmptySelectionValid(theOperation);
+ } else {
+ int aCount = shapesNbLines(theSelection);
+ return (aCount > 0) && (aCount < 3);
+ }
+}
+
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 Collinear constraints operation
+class PartSet_CollinearSelection : public ModuleBase_SelectionValidator
+{
+public:
+ PARTSET_EXPORT virtual bool isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const;
+};
+
////////////// Attribute validators ////////////////
<file>icons/bool_fuse.png</file>
<file>icons/bool_common.png</file>
<file>icons/plane_view.png</file>
+ <file>icons/collinear.png</file>
</qresource>
</RCC>
SketchPlugin_Constraint.h
SketchPlugin_ConstraintBase.h
SketchPlugin_ConstraintCoincidence.h
+ SketchPlugin_ConstraintCollinear.h
SketchPlugin_ConstraintDistance.h
SketchPlugin_ConstraintLength.h
SketchPlugin_ConstraintParallel.h
SketchPlugin_Constraint.cpp
SketchPlugin_ConstraintBase.cpp
SketchPlugin_ConstraintCoincidence.cpp
+ SketchPlugin_ConstraintCollinear.cpp
SketchPlugin_ConstraintDistance.cpp
SketchPlugin_ConstraintLength.cpp
SketchPlugin_ConstraintParallel.cpp
ADD_UNIT_TESTS(TestSketchPointLine.py
TestSketchArcCircle.py
TestConstraintConcidence.py
+ TestConstraintCollinear.py
TestConstraintLength.py
TestConstraintDistance.py
TestConstraintParallel.py
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File: SketchPlugin_ConstraintCollinear.cpp
+// Created: 26 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SketchPlugin_ConstraintCollinear.h"
+
+SketchPlugin_ConstraintCollinear::SketchPlugin_ConstraintCollinear()
+{
+}
+
+void SketchPlugin_ConstraintCollinear::initAttributes()
+{
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
+ data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
+}
+
+void SketchPlugin_ConstraintCollinear::execute()
+{
+}
+
+AISObjectPtr SketchPlugin_ConstraintCollinear::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_ConstraintCollinear.h
+// Created: 27 Jan 2016
+// Author: Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintCollinear_H_
+#define SketchPlugin_ConstraintCollinear_H_
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_ConstraintBase.h"
+
+/** \class SketchPlugin_ConstraintCollinear
+ * \ingroup Plugins
+ * \brief Feature for creation of a new constraint collinearity of two lines
+ *
+ * This constraint has two attributes:
+ * SketchPlugin_Constraint::ENTITY_A() and SketchPlugin_Constraint::ENTITY_B()
+ */
+class SketchPlugin_ConstraintCollinear : public SketchPlugin_ConstraintBase
+{
+ public:
+ /// Parallel constraint kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_CONSTRAINT_COLLINEAR_ID("SketchConstraintCollinear");
+ return MY_CONSTRAINT_COLLINEAR_ID;
+ }
+ /// \brief Returns the kind of a feature
+ SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ static std::string MY_KIND = SketchPlugin_ConstraintCollinear::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_ConstraintCollinear();
+};
+
+#endif
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintFillet.h>
return FeaturePtr(new SketchPlugin_Arc);
} else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintCoincidence);
+ } else if (theFeatureID == SketchPlugin_ConstraintCollinear::ID()) {
+ return FeaturePtr(new SketchPlugin_ConstraintCollinear);
} else if (theFeatureID == SketchPlugin_ConstraintDistance::ID()) {
return FeaturePtr(new SketchPlugin_ConstraintDistance);
} else if (theFeatureID == SketchPlugin_ConstraintLength::ID()) {
--- /dev/null
+"""
+ TestConstraintCollinear.py
+ Unit test of SketchPlugin_ConstraintCollinear class
+
+ SketchPlugin_ConstraintCollinear
+ static const std::string MY_CONSTRAINT_COLLINEAR_ID("SketchConstraintCollinear");
+ 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-28"
+
+
+def checkCollinearVec(theX1, theY1, theX2, theY2):
+ TOL = 1.e-6
+ aLen1 = math.hypot(theX1, theY1)
+ aLen2 = math.hypot(theX2, theY2)
+ aDot = theX1 * theX2 + theY1 * theY2
+ assert math.fabs(math.fabs(aDot) - aLen1 * aLen2) < TOL**2, "aDot = {0}, aLen1 = {1}, aLen2 = {2}, aDiff = {3}".format(aDot, aLen1, aLen2, math.fabs(aDot) - aLen1 * aLen2)
+
+def checkCollinear(theLine1, theLine2):
+ aStartPoint1 = geomDataAPI_Point2D(theLine1.attribute("StartPoint"))
+ aEndPoint1 = geomDataAPI_Point2D(theLine1.attribute("EndPoint"))
+ aStartPoint2 = geomDataAPI_Point2D(theLine2.attribute("StartPoint"))
+ aEndPoint2 = geomDataAPI_Point2D(theLine2.attribute("EndPoint"))
+
+ aDir1x, aDir1y = aEndPoint1.x() - aStartPoint1.x(), aEndPoint1.y() - aStartPoint1.y()
+ aDir2x, aDir2y = aEndPoint2.x() - aStartPoint1.x(), aEndPoint2.y() - aStartPoint1.y()
+ aDir3x, aDir3y = aStartPoint2.x() - aStartPoint1.x(), aStartPoint2.y() - aStartPoint1.y()
+ checkCollinearVec(aDir1x, aDir1y, aDir2x, aDir2y)
+ checkCollinearVec(aDir1x, aDir1y, aDir3x, aDir3y)
+
+
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = featureToCompositeFeature(aSketchCommonFeature)
+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 two lines
+#=========================================================================
+aSession.startOperation()
+# line A
+aSketchLineA = aSketchFeature.addFeature("SketchLine")
+aLineAStartPoint = geomDataAPI_Point2D(aSketchLineA.attribute("StartPoint"))
+aLineAEndPoint = geomDataAPI_Point2D(aSketchLineA.attribute("EndPoint"))
+aSketchLineB = aSketchFeature.addFeature("SketchLine")
+aLineAStartPoint.setValue(0., 25)
+aLineAEndPoint.setValue(85., 25)
+# line B
+aLineBStartPoint = geomDataAPI_Point2D(aSketchLineB.attribute("StartPoint"))
+aLineBEndPoint = geomDataAPI_Point2D(aSketchLineB.attribute("EndPoint"))
+aLineBStartPoint.setValue(0., 50)
+aLineBEndPoint.setValue(80., 75)
+aSession.finishOperation()
+#=========================================================================
+# Link lines with collinear constraint
+#=========================================================================
+aSession.startOperation()
+aParallelConstraint = aSketchFeature.addFeature("SketchConstraintCollinear")
+refattrA = aParallelConstraint.refattr("ConstraintEntityA")
+refattrB = aParallelConstraint.refattr("ConstraintEntityB")
+refattrA.setObject(aSketchLineA.firstResult())
+refattrB.setObject(aSketchLineB.firstResult())
+aParallelConstraint.execute()
+aSession.finishOperation()
+checkCollinear(aSketchLineA, aSketchLineB)
+#=========================================================================
+# Check values and move one constrainted object
+#=========================================================================
+deltaX = deltaY = 10.
+# rotate line, check that reference's line points are moved also
+aLineBStartPointPrev = (aLineBStartPoint.x(), aLineBStartPoint.y())
+aLineBEndPointPrev = (aLineBEndPoint.x(), aLineBEndPoint.y())
+aSession.startOperation()
+aLineAStartPoint.setValue(aLineAStartPoint.x() + deltaX,
+ aLineAStartPoint.y() + deltaY)
+aLineAEndPoint.setValue(aLineAEndPoint.x() - deltaX,
+ aLineAEndPoint.y() - deltaY)
+aSession.finishOperation()
+checkCollinear(aSketchLineA, aSketchLineB)
+#=========================================================================
+# 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"
+ nested="SketchPoint SketchLine SketchCircle SketchArc SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintParallel SketchConstraintPerpendicular SketchConstraintRigid SketchConstraintHorizontal SketchConstraintVertical SketchConstraintEqual SketchConstraintTangent SketchConstraintFillet SketchConstraintCoincidence SketchConstraintMirror SketchConstraintAngle SketchMultiRotation SketchMultiTranslation SketchConstraintCollinear"
when_nested="accept abort"
title="Sketch"
tooltip="Create sketch"
</sketch_shape_selector>
<validator id="PartSet_TangentSelection"/>
</feature>
+
+ <!-- SketchConstraintCollinear -->
+ <feature id="SketchConstraintCollinear" title="Collinear" tooltip="Create constraint defining collinearity of two lines" icon=":icons/collinear.png">
+ <sketch_shape_selector id="ConstraintEntityA"
+ label="First line" tooltip="Select a line" shape_types="edge">
+ <validator id="GeomValidators_ShapeType" parameters="line"/>
+ <validator id="PartSet_DifferentObjects"/>
+ </sketch_shape_selector>
+
+ <sketch_shape_selector id="ConstraintEntityB"
+ label="Second line" tooltip="Select a line" shape_types="edge">
+ <validator id="GeomValidators_ShapeType" parameters="line"/>
+ <validator id="PartSet_DifferentObjects"/>
+ </sketch_shape_selector>
+ <validator id="PartSet_CollinearSelection"/>
+ </feature>
</group>
const SketchSolver_ConstraintType& theType,
std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
+static ConstraintWrapperPtr
+ createConstraintCollinear(ConstraintPtr theConstraint,
+ const GroupID& theGroupID,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2);
aResult = createConstraintTangent(theConstraint, theGroupID, theType,
GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
break;
+ case CONSTRAINT_COLLINEAR:
+ aResult = createConstraintCollinear(theConstraint, theGroupID,
+ GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2));
+ break;
case CONSTRAINT_MULTI_TRANSLATION:
case CONSTRAINT_MULTI_ROTATION:
break;
return aResult;
}
+ConstraintWrapperPtr createConstraintCollinear(
+ ConstraintPtr theConstraint,
+ const GroupID& theGroupID,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity1,
+ std::shared_ptr<PlaneGCSSolver_EntityWrapper> theEntity2)
+{
+ std::shared_ptr<GCS::Line> aLine1 = std::dynamic_pointer_cast<GCS::Line>(theEntity1->entity());
+ std::shared_ptr<GCS::Line> aLine2 = std::dynamic_pointer_cast<GCS::Line>(theEntity2->entity());
+
+ // create two point-on-line constraints
+ std::list<GCSConstraintPtr> aConstrList;
+ aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p1, *aLine1)) );
+ aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p2, *aLine1)) );
+
+ ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper(
+ theConstraint, aConstrList, CONSTRAINT_COLLINEAR));
+ aResult->setGroup(theGroupID);
+ std::list<EntityWrapperPtr> aSubs(1, theEntity1);
+ aSubs.push_back(theEntity2);
+ aResult->setEntities(aSubs);
+ return aResult;
+}
+
ConstraintWrapperPtr createConstraintParallel(
ConstraintPtr theConstraint,
const GroupID& theGroupID,
theEntity->setGroup(theGroup);
if (theGroup == myGroupID)
makeVariable(theEntity);
- else
+ else {
+ if (theEntity->type() == ENTITY_POINT)
+ update(theEntity);
makeConstant(theEntity);
+ }
}
void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
{
toggleEntity(theEntity, myParameters, myConst);
+ if (theEntity->type() == ENTITY_POINT)
+ updateCoincident(theEntity);
}
void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
}
}
+void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint)
+{
+ CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
+ for (; anIt != myCoincidentPoints.end(); ++anIt) {
+ if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) {
+ std::set<EntityWrapperPtr> aCoincident = anIt->second;
+ aCoincident.insert(anIt->first);
+
+ const std::list<ParameterWrapperPtr>& aBaseParams = thePoint->parameters();
+ std::list<ParameterWrapperPtr> aParams;
+ std::list<ParameterWrapperPtr>::const_iterator aBaseIt, anUpdIt;
+
+ std::set<EntityWrapperPtr>::const_iterator aCoincIt = aCoincident.begin();
+ for (; aCoincIt != aCoincident.end(); ++aCoincIt)
+ if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) {
+ aParams = (*aCoincIt)->parameters();
+ aBaseIt = aBaseParams.begin();
+ for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt)
+ (*anUpdIt)->setValue((*aBaseIt)->value());
+ }
+
+ break;
+ }
+ }
+}
+
void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
{
/// \param theArc [in] updated arc
void processArc(const EntityWrapperPtr& theArc);
+ /// \brief Adjust parameters of points coincident with the given
+ void updateCoincident(const EntityWrapperPtr& thePoint);
+
private:
GCS::VEC_pD myParameters; ///< list of parameters
GCS::VEC_pD myConst; ///< list of constants
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintCollinear.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintEqual.h>
#include <SketchPlugin_ConstraintHorizontal.h>
return CONSTRAINT_RADIUS;
else if (aType == SketchPlugin_ConstraintTangent::ID())
return CONSTRAINT_TANGENT;
+ else if (aType == SketchPlugin_ConstraintCollinear::ID())
+ return CONSTRAINT_COLLINEAR;
return CONSTRAINT_UNKNOWN;
}
CONSTRAINT_TANGENT_ARC_LINE,
CONSTRAINT_TANGENT_CIRCLE_LINE,
CONSTRAINT_TANGENT_ARC_ARC,
+ CONSTRAINT_COLLINEAR,
CONSTRAINT_MULTI_TRANSLATION,
CONSTRAINT_MULTI_ROTATION
};
return createConstraint(theConstraint, theGroupID, theSketchID,
CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2);
}
+ else if (theType == CONSTRAINT_COLLINEAR) {
+ // replace by two constraints point-on-line
+ std::list<ConstraintWrapperPtr> aConstraints;
+ const std::list<EntityWrapperPtr>& aSubs1 = theEntity1->subEntities();
+ const std::list<EntityWrapperPtr>& aSubs2 = theEntity2->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
+ for (anIt2 = aSubs2.begin(); anIt2 != aSubs2.end(); ++anIt2) {
+ for (anIt1 = aSubs1.begin(); anIt1 != aSubs1.end(); ++anIt1)
+ if ((*anIt1)->id() == (*anIt2)->id())
+ break;
+ if (anIt1 != aSubs1.end())
+ continue; // the lines have coincident point
+
+ std::list<ConstraintWrapperPtr> aC = createConstraint(theConstraint, theGroupID,
+ theSketchID, CONSTRAINT_PT_ON_LINE, theValue, *anIt2, EntityWrapperPtr(), theEntity1);
+ aConstraints.insert(aConstraints.end(), aC.begin(), aC.end());
+ }
+ return aConstraints;
+ }
int aType = ConstraintType::toSolveSpace(theType);
if (aType == SLVS_C_UNKNOWN)