PLANE_SIZE, "0", "1000");
Config_PropManager::registerProp(SKETCH_TAB_NAME, "planes_thickness", "Thickness",
Config_Prop::IntSpin, SKETCH_WIDTH);
+ Config_PropManager::registerProp(SKETCH_TAB_NAME, "angular_tolerance", "Angular tolerance",
+ Config_Prop::DblSpin, "0.04");
Config_PropManager::registerProp(SKETCH_TAB_NAME, "rotate_to_plane",
"Rotate to plane when selected", Config_Prop::Boolean, "false");
if (fabs(aCoefficient-theDeflection) > Precision::Confusion()) {
isModified = true;
anAISShape->SetOwnDeviationCoefficient(theDeflection);
+ Handle(Prs3d_Drawer) aDrawer = anAISShape->DynamicHilightAttributes();
+ if (!aDrawer.IsNull()) {
+ aDrawer->SetDeviationCoefficient(theDeflection);
+ }
// redisplay is necessary here to update presentation in all modes
// Standard True flag. Displayer uses Standard False flag. If it will be changed in
// displayer, redisplay here will not be necessary. But performance should be checked.
double angle(const std::shared_ptr<GeomAPI_Dir2d>& theArg) const;
};
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Dir2d> GeomDir2dPtr;
+
#endif
std::shared_ptr<GeomAPI_Pnt2d> shiftedLocation(double theShift) const;
};
+
+//! Pointer on the object
+typedef std::shared_ptr<GeomAPI_Lin2d> GeomLine2dPtr;
+
#endif
#include <BRep_Tool.hxx>
#include <ElCLib.hxx>
+#include <GccAna_Circ2d2TanOn.hxx>
#include <GccAna_Circ2d2TanRad.hxx>
#include <GccAna_Circ2d3Tan.hxx>
#include <GccAna_Circ2dTanCen.hxx>
// Provide different mechanisms to create circle:
// * by passing points
// * by tangent edges
+// * by transversal line
// * with specified radius
// * etc.
class CircleBuilder
}
}
+ void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theLine)
+ {
+ if (!theLine)
+ return;
+
+ const TopoDS_Edge& anEdge = TopoDS::Edge(theLine->impl<TopoDS_Shape>());
+
+ double aFirst, aLast;
+ TopLoc_Location aLoc;
+ Handle(Geom2d_Curve) aCurve = BRep_Tool::CurveOnSurface(anEdge, myPlane, aLoc, aFirst, aLast);
+ myTransversalLine = CurveAdaptorPtr(new Geom2dAdaptor_Curve(aCurve, aFirst, aLast));
+ }
+
void setPassingPoints(const std::vector< std::shared_ptr<GeomAPI_Pnt2d> >& thePoints)
{
std::vector< std::shared_ptr<GeomAPI_Pnt2d> >::const_iterator aPIt;
case 1:
aResult = circleByPointAndTwoTangentCurves();
break;
- case 2:
- aResult = circleByTwoPointsAndTangentCurve();
+ case 2: {
+ if (myTransversalLine)
+ aResult = circleByTwoPointsAndTransversalLine();
+ else
+ aResult = circleByTwoPointsAndTangentCurve();
break;
+ }
case 3:
aResult = circleByThreePassingPoints();
break;
}
+ Circ2dPtr circleByTwoPointsAndTransversalLine()
+ {
+ const gp_Pnt2d& aPoint1 = myPassingPoints[0];
+ const gp_Pnt2d& aPoint2 = myPassingPoints[1];
+
+ if (myTransversalLine && myTransversalLine->GetType() == GeomAbs_Line) {
+ GccAna_Circ2d2TanOn aCircleBuilder(aPoint1, aPoint2, myTransversalLine->Line(),
+ Precision::Confusion());
+ if (aCircleBuilder.NbSolutions() > 0)
+ return Circ2dPtr(new gp_Circ2d(aCircleBuilder.ThisSolution(1)));
+ }
+
+ return Circ2dPtr();
+ }
+
+
Circ2dPtr circleByRadiusAndTwoTangentCurves()
{
VectorOfGccCirc aTgCirc;
std::shared_ptr<GeomAPI_Pnt2d> myCenter;
std::vector<gp_Pnt2d> myPassingPoints;
std::vector<CurveAdaptorPtr> myTangentShapes;
+ CurveAdaptorPtr myTransversalLine;
double myRadius;
std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
};
myTangentShapes.push_back(theEdge);
}
+void GeomAlgoAPI_Circ2dBuilder::setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge)
+{
+ if (theEdge->isEdge())
+ myTransversalLine = theEdge;
+}
+
void GeomAlgoAPI_Circ2dBuilder::addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
{
myPassingPoints.push_back(thePoint);
CircleBuilder aCircleBuilder(myPlane);
aCircleBuilder.setCenter(myCenter);
aCircleBuilder.setTangentCurves(myTangentShapes);
+ aCircleBuilder.setTransversalLine(myTransversalLine);
aCircleBuilder.setPassingPoints(myPassingPoints);
aCircleBuilder.setClosestPoint(myClosestPoint);
aCircleBuilder.setRadius(myRadius);
GEOMALGOAPI_EXPORT
void addTangentCurve(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+ /// \brief Constrain circle to be orthogonal to the given edge
+ GEOMALGOAPI_EXPORT
+ void setTransversalLine(const std::shared_ptr<GeomAPI_Shape>& theEdge);
+
/// \brief Constrain circle to pass through the given point
GEOMALGOAPI_EXPORT
void addPassingPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
std::shared_ptr<GeomAPI_Pnt2d> myCenter;
std::vector< std::shared_ptr<GeomAPI_Pnt2d> > myPassingPoints;
std::vector< std::shared_ptr<GeomAPI_Shape> > myTangentShapes;
+ std::shared_ptr<GeomAPI_Shape> myTransversalLine;
std::shared_ptr<GeomAPI_Pnt2d> myClosestPoint;
double myRadius;
};
{
theWidget->setFocus();
// rectangle of focus is not visible on tool button widgets
- theWidget->repaint();
+ theWidget->update();
#ifdef DEBUG_SET_FOCUS
qDebug(QString("setFocus: %1").arg(theInfo).toStdString().c_str());
#endif
}
// We have to call repaint because sometimes the List control is not updated
- myListView->getControl()->repaint();
+ myListView->getControl()->update();
}
//********************************************************************
connect(aLabelWgt, SIGNAL(showConstraintToggled(int, bool)),
mySketchMgr, SLOT(onShowConstraintsToggle(int, bool)));
connect(aLabelWgt, SIGNAL(showFreePoints(bool)), mySketchMgr, SLOT(onShowPoints(bool)));
+ connect(aLabelWgt, SIGNAL(autoConstraints(bool)),
+ sketchReentranceMgr(), SLOT(onAutoConstraints(bool)));
aLabelWgt->setShowPointsState(mySketchMgr->isShowFreePointsShown());
aWgt = aLabelWgt;
} else if (theType == "sketch-2dpoint_selector") {
aDisplayer->updateViewer();
// Update tree items if they are expanded
if (needUpdate) {
- aTreeView->viewport()->repaint(aTreeView->viewport()->rect());
+ aTreeView->viewport()->update(aTreeView->viewport()->rect());
}
} else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)) {
std::shared_ptr<ModelAPI_ObjectUpdatedMessage> aUpdMsg =
// change deviation coefficient to provide more precise circle
// as there is no result, the shape is processed to correct deviation. To be unified
ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, aDrawer);
+ Handle(Prs3d_Drawer) aHighlightDrawer = DynamicHilightAttributes();
+ if (!aHighlightDrawer.IsNull())
+ ModuleBase_Tools::setDefaultDeviationCoefficient(aShape, aHighlightDrawer);
if (myUseAISWidth) {
Handle(AIS_InteractiveObject) anIO = anIter.Value();
: QObject(theModule), myModule(theModule), myIsEditLaunching(false), myIsDragging(false),
myDragDone(false), myIsMouseOverWindow(false),
myIsMouseOverViewProcessed(true), myPreviousUpdateViewerEnabled(true),
- myIsPopupMenuActive(false), myExternalPointsMgr(0)
+ myIsPopupMenuActive(false), myExternalPointsMgr(0), myNoDragMoving(false)
{
ModuleBase_IWorkshop* anIWorkshop = myModule->workshop();
ModuleBase_IViewer* aViewer = anIWorkshop->viewer();
ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
ModuleBase_IViewer* aViewer = aWorkshop->viewer();
- if (!aViewer->canDragByMouse())
- return;
+ //if (!aViewer->canDragByMouse())
+ // return;
ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
(getCurrentOperation());
if (!aFOperation)
return;
- if (aFOperation->isEditOperation()) {
+ bool isEditing = aFOperation->isEditOperation();
+ bool aCanDrag = aViewer->canDragByMouse();
+
+ //if (!aViewer->canDragByMouse() && isEditing) {
+ // // Do not edit by dragging
+ // return;
+ //}
+
+ if (isEditing) {
// If the current widget is a selector, do nothing, it processes the mouse press
ModuleBase_ModelWidget* anActiveWidget = getActiveWidget();
if(anActiveWidget && anActiveWidget->isViewerSelector()) {
if ((!isSketchOpe) && (!isSketcher))
return;
- bool isEditing = aFOperation->isEditOperation();
-
// Ignore creation sketch operation
if ((!isSketcher) && (!isEditing))
return;
- Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
- // Remember highlighted objects for editing
- ModuleBase_ISelection* aSelect = aWorkshop->selection();
-
bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
storeSelection(aHasShift ? ST_SelectAndHighlightType : ST_HighlightType, myCurrentSelection);
get2dPoint(theWnd, theEvent, myCurrentPoint);
if (isSketcher) {
- myIsDragging = true;
- myDragDone = false;
-
+ if (aCanDrag) {
+ myIsDragging = true;
+ myDragDone = false;
+ }
myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
launchEditing();
if (aFeature.get() != NULL) {
myIsEditLaunching = !myModule->sketchReentranceMgr()->isInternalEditActive();
aFOperation->commit();
- myIsDragging = true;
- myDragDone = false;
-
+ if (aCanDrag) {
+ myIsDragging = true;
+ myDragDone = false;
+ }
myPreviousDrawModeEnabled = aViewer->enableDrawMode(false);
launchEditing();
myIsEditLaunching = aPrevLaunchingState;
bool aWasDragging = myIsDragging;
myIsDragging = false;
- if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent))
+ if (myModule->sketchReentranceMgr()->processMouseReleased(theWnd, theEvent)) {
return;
-
+ }
// if mouse is pressed when it was over view and at release the mouse is out of view, do nothing
- if (!myIsMouseOverViewProcessed)
+ if (!myIsMouseOverViewProcessed) {
return;
-
+ }
ModuleBase_IViewer* aViewer = aWorkshop->viewer();
- if (!aViewer->canDragByMouse())
- return;
- ModuleBase_Operation* aOp = getCurrentOperation();
+ //if (!aViewer->canDragByMouse())
+ // return;
+ ModuleBase_OperationFeature* aOp =
+ dynamic_cast<ModuleBase_OperationFeature*>(getCurrentOperation());
if (aOp) {
- if (isNestedSketchOperation(aOp)) {
- // Only for sketcher operations
- if (aWasDragging) {
- if (myDragDone) {
- /// the previous selection is lost by mouse release in the viewer(Select method), but
- /// it is still stored in myCurrentSelection. So, it is possible to restore selection
- /// It is important for drag(edit with mouse) of sketch entities.
- restoreSelection(myCurrentSelection);
- myCurrentSelection.clear();
+ bool aStartNoDragOperation = !aViewer->canDragByMouse() && aOp->isEditOperation();
+ if (aStartNoDragOperation || myNoDragMoving) {
+ // Process edit operation without dragging
+ if (myCurrentSelection.size() > 0)
+ myNoDragMoving = !myNoDragMoving;
+ else
+ myNoDragMoving = false;
+ if (myNoDragMoving)
+ return;
+ else {
+ restoreSelection(myCurrentSelection);
+ myCurrentSelection.clear();
+ }
+ }
+ else {
+ if (isNestedSketchOperation(aOp)) {
+ // Only for sketcher operations
+ if (aWasDragging) {
+ if (myDragDone) {
+ /// the previous selection is lost by mouse release in the viewer(Select method), but
+ /// it is still stored in myCurrentSelection. So, it is possible to restore selection
+ /// It is important for drag(edit with mouse) of sketch entities.
+ restoreSelection(myCurrentSelection);
+ myCurrentSelection.clear();
+ }
}
}
}
qDebug(QString("%1").arg(anInfo.size()).arg(anInfoStr).toStdString().c_str());
}
#endif
-
if (myModule->sketchReentranceMgr()->processMouseMoved(theWnd, theEvent))
return;
// the feature is to be erased here, but it is correct to call canDisplayObject because
// there can be additional check (e.g. editor widget in distance constraint)
ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
- (getCurrentOperation());
+ (getCurrentOperation());
if (aFOperation) {
FeaturePtr aFeature = aFOperation->feature();
visualizeFeature(aFeature, aFOperation->isEditOperation(), canDisplayObject(aFeature));
}
//myClickedPoint.clear();
- if (myIsDragging) {
+ if (myIsDragging || myNoDragMoving) {
// 1. the current selection is saved in the mouse press method in order to restore it after
// moving
// 2. the enable selection in the viewer should be temporary switched off in order to ignore
// mouse press signal in the viewer(it call Select for AIS context and the dragged objects are
// deselected). This flag should be restored in the slot, processed the mouse release signal.
-
ModuleBase_Operation* aCurrentOperation = getCurrentOperation();
if (!aCurrentOperation)
return;
if (isSketchOperation(aCurrentOperation))
return; // No edit operation activated
+#ifdef DRAGGING_DEBUG
+ QTime t;
+ t.start();
+#endif
+
Handle(V3d_View) aView = theWnd->v3dView();
gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
Point aMousePnt;
get2dPoint(theWnd, theEvent, aMousePnt);
std::shared_ptr<GeomAPI_Pnt2d> anOriginalPosition = std::shared_ptr<GeomAPI_Pnt2d>(
- new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
+ new GeomAPI_Pnt2d(myCurrentPoint.myCurX, myCurrentPoint.myCurY));
std::shared_ptr<GeomAPI_Pnt2d> aCurrentPosition = std::shared_ptr<GeomAPI_Pnt2d>(
- new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
+ new GeomAPI_Pnt2d(aMousePnt.myCurX, aMousePnt.myCurY));
ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
static Events_ID aMoveEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
//static Events_ID aUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
FeatureToSelectionMap::const_iterator anIt = myCurrentSelection.begin(),
- aLast = myCurrentSelection.end();
+ aLast = myCurrentSelection.end();
// 4. the features and attributes modification(move)
bool isModified = false;
for (; anIt != aLast; anIt++) {
// Process selection by attribute: the priority to the attribute
if (!anAttributes.empty()) {
std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
- anAttLast = anAttributes.end();
+ anAttLast = anAttributes.end();
for (; anAttIt != anAttLast; anAttIt++) {
AttributePtr anAttr = *anAttIt;
if (anAttr.get() == NULL)
bool isImmutable = aPoint->setImmutable(true);
std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
- <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+ <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
aMessage->setMovedAttribute(aPoint);
aMessage->setOriginalPosition(anOriginalPosition);
aMessage->setCurrentPosition(aCurrentPosition);
}
}
}
- } else {
+ }
+ else {
// Process selection by feature
std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
if (aSketchFeature) {
std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
- <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
+ <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
aMessage->setMovedObject(aFeature);
aMessage->setOriginalPosition(anOriginalPosition);
aMessage->setCurrentPosition(aCurrentPosition);
aDisplayer->enableUpdateViewer(isEnableUpdateViewer);
aDisplayer->updateViewer();
+#ifdef DRAGGING_DEBUG
+ cout << "Mouse move processing " << t.elapsed() << endl;
+#endif
+
myDragDone = true;
myCurrentPoint = aMousePnt;
}
/// Process sketch plane selected event
void onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln);
+ /// The slot is called when user checks "Show free points" button
+ /// \param toShow a state of the check box
void onShowPoints(bool toShow);
private slots:
PartSet_ExternalPointsMgr* myExternalPointsMgr;
QMap<ResultPtr, Handle(AIS_Shape)> myPointsHighlight;
+
+ bool myNoDragMoving;
};
#include "GeomDataAPI_Point2D.h"
+#include "GeomAPI_Lin2d.h"
+#include "GeomAPI_Dir2d.h"
+
#include <ModuleBase_IPropertyPanel.h>
#include <ModuleBase_ISelectionActivate.h>
#include <ModuleBase_OperationFeature.h>
#include <SketchPlugin_Point.h>
#include <SketchPlugin_Trim.h>
#include <SketchPlugin_Split.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintVertical.h>
#include <XGUI_Workshop.h>
#include <XGUI_ModuleConnector.h>
myRestartingMode(RM_None),
myIsFlagsBlocked(false),
myIsInternalEditOperation(false),
- myNoMoreWidgetsAttribute("")
+ myNoMoreWidgetsAttribute(""),
+ myIsAutoConstraints(true)
{
}
workshop()->selector()->clearSelection();
myPreviousFeature = aFOperation->feature();
+ if (myIsAutoConstraints)
+ addConstraints(myPreviousFeature);
restartOperation();
myPreviousFeature = FeaturePtr();
aPropertyPanel->setInternalActiveWidget(theWidget);
}
}
+
+void PartSet_SketcherReentrantMgr::onAutoConstraints(bool isOn)
+{
+ myIsAutoConstraints = isOn;
+}
+
+void PartSet_SketcherReentrantMgr::addConstraints(const FeaturePtr& theFeature)
+{
+ static GeomDir2dPtr myHorDir(new GeomAPI_Dir2d(1, 0));
+ static GeomDir2dPtr myVertDir(new GeomAPI_Dir2d(0, 1));
+
+ if (theFeature->getKind() == SketchPlugin_Line::ID()) {
+ std::shared_ptr<ModelAPI_Data> aData = theFeature->data();
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aData->attribute(SketchPlugin_Line::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aData->attribute(SketchPlugin_Line::END_ID()));
+ if (aPoint1.get() && aPoint2.get()) {
+ GeomLine2dPtr aLine(new GeomAPI_Lin2d(aPoint1->pnt(), aPoint2->pnt()));
+ GeomDir2dPtr aDir = aLine->direction();
+ double aHorAngle = fabs(myHorDir->angle(aDir));
+ double aVertAngle = fabs(myVertDir->angle(aDir));
+ if (aHorAngle > M_PI/2.)
+ aHorAngle = M_PI - aHorAngle;
+ if (aVertAngle > M_PI/2.)
+ aVertAngle = M_PI - aVertAngle;
+
+ double aTolerance = Config_PropManager::real(SKETCH_TAB_NAME, "angular_tolerance");
+ CompositeFeaturePtr aSketch = module()->sketchMgr()->activeSketch();
+ FeaturePtr aFeature;
+ if (aHorAngle < aTolerance)
+ // Add horizontal constraint
+ aFeature = aSketch->addFeature(SketchPlugin_ConstraintHorizontal::ID());
+ else if (aVertAngle < aTolerance)
+ // Add vertical constraint
+ aFeature = aSketch->addFeature(SketchPlugin_ConstraintVertical::ID());
+
+ if (aFeature.get()) {
+ aFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(
+ theFeature->firstResult());
+ }
+ }
+ }
+}
/// \param theMessage a message of reentrant operation
void setReentrantPreSelection(const std::shared_ptr<Events_Message>& theMessage);
+ bool isAutoConstraints() const { return myIsAutoConstraints; }
+
+
+public slots:
+ /// The slot is called when user checks "Automatic constraints" button
+ /// \param isOn a state of the check box
+ void onAutoConstraints(bool isOn);
+
+
private slots:
/// SLOT, that is called by a widget activating in the property panel
/// If the 'internal' edit operation is started, it activates the first widget selection
void setInternalActiveWidget(ModuleBase_ModelWidget* theWidget);
+ void addConstraints(const FeaturePtr& theFeature);
+
private:
ModuleBase_IWorkshop* myWorkshop; /// the workshop
ObjectPtr mySelectedObject; /// cashed selected object
std::shared_ptr<ModelAPI_Attribute> mySelectedAttribute; /// cashed selected attribute
std::shared_ptr<GeomAPI_Pnt2d> myClickedSketchPoint; /// cashed clicked point
+
+ bool myIsAutoConstraints;
};
#endif
#include "PartSet_Tools.h"
#include "PartSet_Module.h"
#include "PartSet_PreviewPlanes.h"
+#include "PartSet_SketcherReentrantMgr.h"
#include "SketchPlugin_SketchEntity.h"
connect(myShowPoints, SIGNAL(toggled(bool)), this, SIGNAL(showFreePoints(bool)));
aLayout->addWidget(myShowPoints);
+ myAutoConstraints = new QCheckBox(tr("Automatic constraints"), this);
+ connect(myAutoConstraints, SIGNAL(toggled(bool)), this, SIGNAL(autoConstraints(bool)));
+ aLayout->addWidget(myAutoConstraints);
+
QPushButton* aPlaneBtn = new QPushButton(tr("Change sketch plane"), aSecondWgt);
connect(aPlaneBtn, SIGNAL(clicked(bool)), SLOT(onChangePlane()));
aLayout->addWidget(aPlaneBtn);
void PartSet_WidgetSketchLabel::activateCustom()
{
+ PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+ if (aModule) {
+ bool isBlocked = myAutoConstraints->blockSignals(true);
+ myAutoConstraints->setChecked(aModule->sketchReentranceMgr()->isAutoConstraints());
+ myAutoConstraints->blockSignals(isBlocked);
+ }
+
std::shared_ptr<GeomAPI_Pln> aPlane = plane();
if (aPlane.get()) {
myStackWidget->setCurrentIndex(1);
/// \param theState a state of the check box
void showConstraintToggled(int theType, bool theState);
+ /// The signal is emitted when user checks "Show free points" button
+ /// \param toShow a state of the check box
void showFreePoints(bool toShow);
+ /// The signal is emitted when user checks "Automatic constraints" button
+ /// \param isOn a state of the check box
+ void autoConstraints(bool isOn);
+
protected:
/// Creates a backup of the current values of the attribute
/// It should be realized in the specific widget because of different
QCheckBox* myViewInverted;
QCheckBox* myRemoveExternal;
QCheckBox* myShowPoints;
+ QCheckBox* myAutoConstraints;
QMap<PartSet_Tools::ConstraintVisibleState, QCheckBox*> myShowConstraints;
execute();
}
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+ double theEndX, double theEndY,
+ bool theInversed)
+{
+ fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+ fillAttribute(theTransversalPoint, mytangentPoint);
+ fillAttribute(endPoint3(), theEndX, theEndY);
+ fillAttribute(theInversed, myreversed);
+
+ execute();
+}
+
+//================================================================================================
+void SketchAPI_MacroArc::setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+ bool theInversed)
+{
+ fillAttribute(SketchPlugin_MacroArc::ARC_TYPE_BY_TRANSVERSAL_LINE(), myarcType);
+ fillAttribute(theTransversalPoint, mytangentPoint);
+ fillAttribute(theEnd, myendPoint3);
+ fillAttribute(theInversed, myreversed);
+
+ execute();
+}
angle, SketchPlugin_MacroArc::ANGLE_ID(),
ModelAPI_AttributeDouble, /** Angle */)
-private:
-
/// Set by center and start, end point.
SKETCHAPI_EXPORT
void setByCenterStartEnd(double theCenterX, double theCenterY,
void setByTangent(const ModelHighAPI_RefAttr& theTangentPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
bool theInversed);
+
+ /// Set by tangent and end point.
+ SKETCHAPI_EXPORT
+ void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+ double theEndX, double theEndY,
+ bool theInversed);
+
+ /// Set by tangent and end point.
+ SKETCHAPI_EXPORT
+ void setByTransversal(const ModelHighAPI_RefAttr& theTransversalPoint,
+ const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
+ bool theInversed);
};
/// Pointer on Arc object.
std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
const ModelHighAPI_RefAttr& theTangentPoint,
double theEndX, double theEndY,
- bool theInversed)
+ bool theInversed,
+ bool theTransversal)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
- return MacroArcPtr(new SketchAPI_MacroArc(
- aFeature, theTangentPoint, theEndX, theEndY, theInversed));
+ MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+ if (theTransversal)
+ aMacroArc->setByTransversal(theTangentPoint, theEndX, theEndY, theInversed);
+ else
+ aMacroArc->setByTangent(theTangentPoint, theEndX, theEndY, theInversed);
+ return aMacroArc;
}
std::shared_ptr<SketchAPI_MacroArc> SketchAPI_Sketch::addArc(
const ModelHighAPI_RefAttr& theTangentPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
- bool theInversed)
+ bool theInversed,
+ bool theTransversal)
{
std::shared_ptr<ModelAPI_Feature> aFeature =
compositeFeature()->addFeature(SketchPlugin_MacroArc::ID());
- return MacroArcPtr(new SketchAPI_MacroArc(aFeature, theTangentPoint, theEnd, theInversed));
+ MacroArcPtr aMacroArc(new SketchAPI_MacroArc(aFeature));
+ if (theTransversal)
+ aMacroArc->setByTransversal(theTangentPoint, theEnd, theInversed);
+ else
+ aMacroArc->setByTangent(theTangentPoint, theEnd, theInversed);
+ return aMacroArc;
}
std::shared_ptr<SketchAPI_Arc> SketchAPI_Sketch::addArc(const ModelHighAPI_Selection & theExternal)
const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
const std::shared_ptr<GeomAPI_Pnt2d>& thePassed);
- /// Add arc
+ /// Add transversal/tangent arc
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_MacroArc> addArc(
- const ModelHighAPI_RefAttr& theTangentPoint,
+ const ModelHighAPI_RefAttr& theConnectedPoint,
double theEndX, double theEndY,
- bool theInversed);
+ bool theInversed,
+ bool theTransversal = false);
- /// Add arc
+ /// Add transversal/tangent arc
SKETCHAPI_EXPORT
std::shared_ptr<SketchAPI_MacroArc> addArc(
- const ModelHighAPI_RefAttr& theTangentPoint,
+ const ModelHighAPI_RefAttr& theConnectedPoint,
const std::shared_ptr<GeomAPI_Pnt2d>& theEnd,
- bool theInversed);
+ bool theInversed,
+ bool theTransversal = false);
/// Add arc
SKETCHAPI_EXPORT
TestConstraintHorizontalValidator.py
TestConstraintLength.py
TestConstraintMiddlePoint.py
+ TestConstraintMiddlePointOnArc.py
TestConstraintParallel.py
TestConstraintPerpendicular.py
+ TestConstraintPerpendicularArcLine.py
TestConstraintRadius.py
TestConstraintRadiusFailure.py
TestConstraintTangent.py
TestCreateArcByCenterStartEnd.py
TestCreateArcByTangentEdge.py
TestCreateArcByThreePoints.py
+ TestCreateArcByTransversalLine.py
TestCreateArcChangeType.py
TestCreateCircleByCenterAndPassed.py
TestCreateCircleByThreePoints.py
#include "SketchPlugin_MacroArc.h"
#include "SketchPlugin_Arc.h"
+#include "SketchPlugin_ConstraintPerpendicular.h"
#include "SketchPlugin_ConstraintTangent.h"
#include "SketchPlugin_Sketch.h"
#include "SketchPlugin_Tools.h"
else if(anArcType == ARC_TYPE_BY_THREE_POINTS())
fillByThreePassedPoints();
else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE())
- fillByTangentEdge();
+ fillByEdge(false);
+ else if (anArcType == ARC_TYPE_BY_TRANSVERSAL_LINE())
+ fillByEdge(true);
double aRadius = 0;
double anAngle = 0;
AttributePtr(),
anArcFeature->lastResult(),
true);
- } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
- // constraints for tangent arc
+ } else {
+ // coincident with connection point
SketchPlugin_Tools::createCoincidenceOrTangency(this,
TANGENT_POINT_ID(),
anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
ObjectPtr(),
false);
- FeaturePtr aTangent = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
- AttributeRefAttrPtr aRefAttrA = aTangent->refattr(SketchPlugin_Constraint::ENTITY_A());
+ // tangent or perpendicular constraint
+ FeaturePtr aStartPointConstraint;
+ if (anArcType == ARC_TYPE_BY_TANGENT_EDGE())
+ aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
+ else
+ aStartPointConstraint = sketch()->addFeature(SketchPlugin_ConstraintPerpendicular::ID());
+ // setting attributes of the start point constraint
+ AttributeRefAttrPtr aRefAttrA =
+ aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
AttributeRefAttrPtr aTgPntRefAttr = refattr(TANGENT_POINT_ID());
FeaturePtr aTgFeature = ModelAPI_Feature::feature(aTgPntRefAttr->attr()->owner());
aRefAttrA->setObject(aTgFeature->lastResult());
- AttributeRefAttrPtr aRefAttrB = aTangent->refattr(SketchPlugin_Constraint::ENTITY_B());
+ AttributeRefAttrPtr aRefAttrB =
+ aStartPointConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
aRefAttrB->setObject(anArcFeature->lastResult());
// constraint for end point
SketchPlugin_Tools::createCoincidenceOrTangency(this,
myParamBefore = aEndParam;
}
-void SketchPlugin_MacroArc::fillByTangentEdge()
+void SketchPlugin_MacroArc::fillByEdge(bool theTransversal)
{
AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
if (!aTangentAttr->isInitialized())
return;
- AttributePoint2DPtr aTangentPointAttr =
+ AttributePoint2DPtr aConnectionPointAttr =
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
- if (!aTangentPointAttr->isInitialized())
+ if (!aConnectionPointAttr->isInitialized())
return;
AttributePoint2DPtr anEndPointAttr =
if (!anEndPointAttr->isInitialized())
return;
- myStart = aTangentPointAttr->pnt();
+ myStart = aConnectionPointAttr->pnt();
myEnd = anEndPointAttr->pnt();
if (myStart->isEqual(myEnd))
return;
// obtain a shape the tangent point belongs to
- FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
- std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
+ FeaturePtr aConnectedFeature = ModelAPI_Feature::feature(aConnectionPointAttr->owner());
+ std::shared_ptr<GeomAPI_Shape> aTangentShape = aConnectedFeature->lastResult()->shape();
GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
aCircBuilder.addPassingPoint(myStart);
aCircBuilder.addPassingPoint(myEnd);
- aCircBuilder.addTangentCurve(aTangentShape);
+ if (theTransversal)
+ aCircBuilder.setTransversalLine(aTangentShape);
+ else
+ aCircBuilder.addTangentCurve(aTangentShape);
std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
if (!aCircle)
return ID;
}
+ inline static const std::string& ARC_TYPE_BY_TRANSVERSAL_LINE()
+ {
+ static const std::string ID("by_transversal_line");
+ return ID;
+ }
+
/// Central 2D point of the circle which contains the arc
inline static const std::string& CENTER_POINT_ID()
{
void fillByCenterAndTwoPassed();
/// Set fields for center, start and end points by selected passed points
void fillByThreePassedPoints();
- /// Set fields for center, start and end points by selected tangent edge
- void fillByTangentEdge();
+ /// Set fields for center, start and end points by selected tangent or transversal edge
+ /// \param theTransversal if \c true, builds transversal arc, otherwise builds tangential arc.
+ void fillByEdge(bool theTransversal);
FeaturePtr createArcFeature();
new SketchPlugin_ExternalValidator);
aFactory->registerValidator("SketchPlugin_TangentAttr",
new SketchPlugin_TangentAttrValidator);
+ aFactory->registerValidator("SketchPlugin_PerpendicularAttr",
+ new SketchPlugin_PerpendicularAttrValidator);
aFactory->registerValidator("SketchPlugin_NotFixed",
new SketchPlugin_NotFixedValidator);
aFactory->registerValidator("SketchPlugin_EqualAttr",
new SketchPlugin_MiddlePointAttrValidator);
aFactory->registerValidator("SketchPlugin_ArcTangentPoint",
new SketchPlugin_ArcTangentPointValidator);
+ aFactory->registerValidator("SketchPlugin_ArcTransversalPoint",
+ new SketchPlugin_ArcTransversalPointValidator);
aFactory->registerValidator("SketchPlugin_IntersectionValidator",
new SketchPlugin_IntersectionValidator);
aFactory->registerValidator("SketchPlugin_ProjectionValidator",
return true;
}
+bool SketchPlugin_PerpendicularAttrValidator::isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& 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();
+ SessionPtr aMgr = ModelAPI_Session::get();
+ ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+
+ FeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+
+ bool isObject = aRefAttr->isObject();
+ ObjectPtr anObject = aRefAttr->object();
+ if (isObject && anObject.get()) {
+ FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
+
+ 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()) {
+ theError = "At least one feature should be a line";
+ return false;
+ }
+ }
+ else {
+ theError = "It uses an empty object";
+ return false;
+ }
+
+ return true;
+}
+
bool SketchPlugin_NotFixedValidator::isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments,
Events_InfoMessage& theError) const
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())
++aNbLines;
}
}
return true;
}
+bool SketchPlugin_ArcTransversalPointValidator::isValid(
+ const AttributePtr& theAttribute,
+ const std::list<std::string>& /*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;
+ }
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(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<ModelAPI_Feature>(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 transversal arc on %1";
+ theError.arg(anAttrFeature->getKind());
+ return false;
+ }
+
+ return true;
+}
+
bool SketchPlugin_IntersectionValidator::isValid(const AttributePtr& theAttribute,
const std::list<std::string>& theArguments,
Events_InfoMessage& theError) const
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_PerpendicularAttrValidator
+ * \ingroup Validators
+ * \brief Validator for the perpendicular constraint input.
+ *
+ * Checks that two arcs are not selected for perpendicular.
+ */
+class SketchPlugin_PerpendicularAttrValidator : public ModelAPI_AttributeValidator
+{
+ public:
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
/**\class SketchPlugin_NotFixedValidator
* \ingroup Validators
Events_InfoMessage& theError) const;
};
+/**\class SketchPlugin_ArcTransversalPointValidator
+ * \ingroup Validators
+ * \brief Validator for the point where the transversal arc is building.
+ *
+ * Checks that the point is a start or end point just on line or arc.
+ */
+class SketchPlugin_ArcTransversalPointValidator : public ModelAPI_AttributeValidator
+{
+ public:
+ //! returns true if attribute is valid
+ //! \param theAttribute the checked attribute
+ //! \param theArguments arguments of the attribute
+ //! \param theError error message
+ virtual bool isValid(const AttributePtr& theAttribute,
+ const std::list<std::string>& theArguments,
+ Events_InfoMessage& theError) const;
+};
+
+
/**\class SketchPlugin_SplitValidator
* \ingroup Validators
* \brief Validator for the entity of the following type:
--- /dev/null
+# Copyright (C) 2017-2019 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+"""
+ Test middle point on an arc
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from GeomAPI import GeomAPI_Dir2d
+
+__updated__ = "2019-09-03"
+
+class TestMiddlePointOnArc(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myTestPassed = True
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myArc = self.mySketch.addArc(50, 50, 70, 50, 50, 70, False)
+ self.myLine = self.mySketch.addLine(55, 60, 50, 0)
+ self.myDOF = 9
+ model.do()
+ self.checkDOF()
+
+ def tearDown(self):
+ if self.myTestPassed:
+ model.assertArcValidity(self.myArc)
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.checkDOF()
+ model.end()
+ assert(model.checkPythonDump())
+
+ def checkDOF(self):
+ self.assertEqual(model.dof(self.mySketch), self.myDOF)
+
+ def checkMiddlePoint(self, thePoint, theArc):
+ self.myTestPassed = False
+ # check point on arc
+ dist = thePoint.pnt().distance(theArc.center().pnt())
+ NB_DIGITS = 7 - math.floor(math.log10(theArc.radius().value()))
+ self.assertAlmostEqual(dist, theArc.radius().value(), NB_DIGITS)
+ # check middle point
+ dirPC = GeomAPI_Dir2d(thePoint.x() - theArc.center().x(),
+ thePoint.y() - theArc.center().y())
+ dirSC = GeomAPI_Dir2d(theArc.startPoint().x() - theArc.center().x(),
+ theArc.startPoint().y() - theArc.center().y())
+ dirEC = GeomAPI_Dir2d(theArc.endPoint().x() - theArc.center().x(),
+ theArc.endPoint().y() - theArc.center().y())
+ angleSP = dirSC.angle(dirPC)
+ anglePE = dirPC.angle(dirEC)
+ self.assertAlmostEqual(angleSP, anglePE)
+ self.assertEqual(angleSP < 0, theArc.reversed().value())
+ self.myTestPassed = True
+
+ def rotatePoint(self, thePoint, theCenter, theAngle):
+ dirX = thePoint.x() - theCenter.x()
+ dirY = thePoint.y() - theCenter.y()
+ newX = theCenter.x() + dirX * math.cos(theAngle) - dirY * math.sin(theAngle)
+ newY = theCenter.y() + dirX * math.sin(theAngle) + dirY * math.cos(theAngle)
+ self.mySketch.move(thePoint, newX, newY)
+
+ def moveArc(self):
+ ANGLE_STEP = math.pi * 5.0 / 180.0
+ ANGLE_THRESHOLD = math.pi
+ # move start point of the arc clockwise
+ fullAngle = 0.0
+ while fullAngle < ANGLE_THRESHOLD:
+ self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), -ANGLE_STEP)
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ fullAngle += ANGLE_STEP
+ # move start point of the arc conterclockwise
+ fullAngle = 0.0
+ while fullAngle < ANGLE_THRESHOLD:
+ self.rotatePoint(self.myArc.startPoint(), self.myArc.center(), ANGLE_STEP)
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ fullAngle += ANGLE_STEP
+
+ # move end point of the arc clockwise
+ fullAngle = 0.0
+ while fullAngle < ANGLE_THRESHOLD:
+ self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), -ANGLE_STEP)
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ fullAngle += ANGLE_STEP
+ # move end point of the arc conterclockwise
+ fullAngle = 0.0
+ while fullAngle < ANGLE_THRESHOLD:
+ self.rotatePoint(self.myArc.endPoint(), self.myArc.center(), ANGLE_STEP)
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ fullAngle += ANGLE_STEP
+
+ # move center of the arc
+ DELTA = [1.0, 1.0]
+ for i in range(0, 40):
+ if i == 10 or i == 30:
+ DELTA = [-DELTA[0], -DELTA[1]]
+ self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ DELTA = [-1.0, 1.0]
+ for i in range(0, 40):
+ if i == 10 or i == 30:
+ DELTA = [-DELTA[0], -DELTA[1]]
+ self.mySketch.move(self.myArc.center(), self.myArc.center().x() + DELTA[0], self.myArc.center().y() + DELTA[1])
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+ def moveLine(self):
+ DELTA = [1.0, 0.0]
+ for i in range(0, 40):
+ if i == 10 or i == 30:
+ DELTA = [-DELTA[0], -DELTA[1]]
+ self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ DELTA = [0.0, 1.0]
+ for i in range(0, 40):
+ if i == 10 or i == 30:
+ DELTA = [-DELTA[0], -DELTA[1]]
+ self.mySketch.move(self.myLine.startPoint(), self.myLine.startPoint().x() + DELTA[0], self.myLine.startPoint().y() + DELTA[1])
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+
+ def test_middle_point_PA(self):
+ """ Test 1. Set middle point constraint (point is the first argument)
+ """
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+
+ def test_middle_point_AP(self):
+ """ Test 2. Set middle point constraint (point is the second argument)
+ """
+ self.mySketch.setMiddlePoint(self.myArc.results()[1], self.myLine.startPoint())
+ self.myDOF -= 2
+ model.do()
+
+ def test_coincident_middle_point(self):
+ """ Test 3. Set middle point constraint for the point already coincident with the arc
+ """
+ self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+ model.do()
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+
+ def test_middle_point_coincident(self):
+ """ Test 4. Set concidence of the point and the arc which are already constrained with middle point
+ """
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ model.do()
+ self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+
+ @unittest.expectedFailure
+ def test_middle_point_limitation(self):
+ """ Test 5. Check middle point fails if the point's coordinates are equal to the arc boundary point
+ """
+ self.myLine.startPoint().setValue(self.myArc.endPoint().pnt())
+ model.do()
+ coincidence = self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ # this check will fail due to the limitation of PlanGCS
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+
+ def test_middle_point_move_arc(self):
+ """ Test 6. Set middle point constraint and move arc
+ """
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.moveArc()
+
+ def test_middle_point_coincidence_move_arc(self):
+ """ Test 7. Set coincidence and middle point constraint and move arc
+ """
+ self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+ model.do()
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.moveArc()
+
+ def test_middle_point_move_line(self):
+ """ Test 8. Set middle point constraint and move line
+ """
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.moveLine()
+
+ def test_middle_point_coincidence_move_line(self):
+ """ Test 9. Set coincidence and middle point constraint and move line
+ """
+ self.mySketch.setCoincident(self.myLine.startPoint(), self.myArc.results()[1])
+ model.do()
+ self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.moveLine()
+
+ def test_remove_middle_point(self):
+ """ Test 10. Set and then remove middle point constraint
+ """
+ mp = self.mySketch.setMiddlePoint(self.myLine.startPoint(), self.myArc.results()[1])
+ self.myDOF -= 2
+ model.do()
+ model.assertArcValidity(self.myArc)
+ self.checkMiddlePoint(self.myLine.startPoint(), self.myArc)
+ self.checkDOF()
+ # remove middle point
+ self.myDocument.removeFeature(mp.feature())
+ self.myDOF += 2
+ model.do()
+ self.checkDOF()
+ # set flag False to avoid checking middle point constraint in tearDown() method
+ self.myTestPassed = False
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
--- /dev/null
+# Copyright (C) 2019 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(-35, -10, 20)
+SketchLine_1 = Sketch_1.addLine(-21, 2, 24, 21)
+SketchLine_2 = Sketch_1.addLine(24, 21, 20, -30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchArc_1 = Sketch_1.addArc(25, -30, 42, -34, 13, -17.31142245955048, False)
+model.do()
+
+# check error on perpendicularity of circle and arc
+SketchConstraintPerpendicular_1 = Sketch_1.setPerpendicular(SketchCircle_1.results()[1], SketchArc_1.results()[1])
+model.do()
+assert(SketchConstraintPerpendicular_1.feature().error() != "")
+
+# avoid the failure
+Part_1_doc.removeFeature(SketchConstraintPerpendicular_1.feature())
+model.do()
+assert(Sketch_1.feature().error() == "")
+
+# set correct constraints
+SketchConstraintPerpendicular_2 = Sketch_1.setPerpendicular(SketchCircle_1.results()[1], SketchLine_1.result())
+SketchConstraintPerpendicular_3 = Sketch_1.setPerpendicular(SketchLine_2.result(), SketchArc_1.results()[1])
+model.do()
+
+TOLERANCE = 1.e-7
+assert(model.distancePointLine(SketchCircle_1.center(), SketchLine_1) < TOLERANCE)
+assert(model.distancePointLine(SketchArc_1.center(), SketchLine_2) < TOLERANCE)
+model.end()
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2014-2019 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
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# 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
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+from GeomDataAPI import *
+from ModelAPI import *
+from SketchAPI import SketchAPI_Sketch
+import math
+from salome.shaper import model
+
+__updated__ = "2019-08-16"
+
+TOLERANCE = 1.e-7
+
+#=========================================================================
+# Auxiliary functions
+#=========================================================================
+
+def verifyLastArc(theSketch, theCenter, theStart, theEnd):
+ """
+ subroutine to verify position of last arc in the sketch
+ """
+ aLastArc = model.lastSubFeature(theSketch, "SketchArc")
+ model.assertArc(aLastArc, theCenter, theStart, theEnd)
+
+def verifyArcLineTransversal(theArc, theLine):
+ aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+ aDistCL = model.distancePointLine(aCenter, theLine)
+ assert aDistCL < TOLERANCE, "Arc and line are not orthogonal"
+
+def verifyPointOnArc(thePoint, theArc):
+ aCenter = geomDataAPI_Point2D(theArc.attribute("center_point"))
+ aStart = geomDataAPI_Point2D(theArc.attribute("start_point"))
+ aRadius = model.distancePointPoint(aStart, aCenter)
+
+ aDistPP = model.distancePointPoint(aCenter, thePoint)
+ assert math.fabs(aRadius - aDistPP) < TOLERANCE, "Point is not on Circle, distance: {0}".format(aDistPP)
+
+
+
+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()
+aSketch = SketchAPI_Sketch(aSketchFeature)
+
+# auxiliary line
+aLineStartPnt = [0., 0.]
+aLineEndPnt = [50., 0.]
+aSession.startOperation()
+aSketchLine = aSketchFeature.addFeature("SketchLine")
+aLineStart = geomDataAPI_Point2D(aSketchLine.attribute("StartPoint"))
+aLineEnd = geomDataAPI_Point2D(aSketchLine.attribute("EndPoint"))
+aLineStart.setValue(aLineStartPnt[0], aLineStartPnt[1])
+aLineEnd.setValue(aLineEndPnt[0], aLineEndPnt[1])
+aSession.finishOperation()
+
+#=========================================================================
+# Test 1. Create an arc, orthogonal to the line
+#=========================================================================
+anArcEndPnt = [80., 20.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+assert (anArc.getKind() == "SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+assert (not anArcTgPnt.isInitialized())
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+assert (not anArcEnd.isInitialized())
+anArcType = anArc.string("arc_type")
+assert (not anArcType.isInitialized())
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], aLineEndPnt, anArcEndPnt)
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 1)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 1)
+
+#=========================================================================
+# Test 2. Create an arc, orthogonal to the previous arc (expect an error)
+#=========================================================================
+aPrevArc = aLastArc
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+anArcEndPnt = [50., 100.]
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aPrevArcEnd)
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+assert(anArc.error() != "")
+# remove failed feature
+aSession.startOperation()
+aDocument.removeFeature(anArc)
+aSession.finishOperation()
+
+#=========================================================================
+# Test 3. Create an arc, orthogonal to the line with end point on the arc
+#=========================================================================
+aPrevArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+aPrevArcEnd = geomDataAPI_Point2D(aPrevArc.attribute("end_point"))
+aSession.startOperation()
+anArc = aSketchFeature.addFeature("SketchMacroArc")
+anArcTgPnt = anArc.refattr("tangent_point")
+anArcEnd = geomDataAPI_Point2D(anArc.attribute("end_point_3"))
+anArcEndRef = anArc.refattr("end_point_ref")
+anArcType = anArc.string("arc_type")
+# initialize attributes
+anArcType.setValue("by_transversal_line")
+anArcTgPnt.setAttr(aLineStart)
+anArcEndRef.setObject(aPrevArc.lastResult())
+anArcEnd.setValue(anArcEndPnt[0], anArcEndPnt[1])
+aSession.finishOperation()
+verifyLastArc(aSketchFeature, [], [aLineStart.x(), aLineStart.y()], [])
+aLastArc = model.lastSubFeature(aSketchFeature, "SketchArc")
+verifyArcLineTransversal(aLastArc, aSketchLine)
+aLastArcEnd = geomDataAPI_Point2D(aLastArc.attribute("end_point"))
+verifyPointOnArc(aLastArcEnd, aPrevArc)
+model.testNbSubFeatures(aSketch, "SketchConstraintCoincidence", 3)
+model.testNbSubFeatures(aSketch, "SketchConstraintPerpendicular", 2)
+
+#=========================================================================
+# End of test
+#=========================================================================
+
+assert(model.checkPythonDump())
#. select in the Main Menu *Sketch - > Arc* item or
#. click |arc.icon| **Arc** button in Sketch toolbar:
-There are 3 algorithms for creation of an Arc:
+There are 4 algorithms for creation of an Arc:
.. image:: images/arc_base_32x32.png
:align: left
:align: left
**By tangent point and end point** creates an arc segment with the tangent point and the end point.
+.. image:: images/arc_perp_32x32.png
+ :align: left
+**By transversal point and end point** creates an arc segment perpendicular to a straight line with the start point, connected with boundary of this line, and the end point.
+
By center and two points
""""""""""""""""""""""""
**TUI Command**:
-.. py:function:: Sketch_1.addArc(TangetPoint, EndX, EndY, Inversed)
+.. py:function:: Sketch_1.addArc(TangentPoint, EndX, EndY, Inversed)
+
+ :param object: Tangent Point.
+ :param real: End X.
+ :param real: End Y.
+ :param boolean: Is inversed.
+ :return: Result object.
+
+By transveral point and point
+"""""""""""""""""""""""""""""
+
+.. image:: images/Arc_panel_perp.png
+ :align: center
+
+Select a point on a straight segment in the view to set the transversal point, then move the mouse and click to set the end point.
+The transversal point by itself is a start point. The edge on which it lies will be perpendicular to the arc (the center of the arc is lying on the edge).
+
+- When entering a transversal point by selecting a point on segment, a Perpendicular constraint is created.
+- When entering an end point by selecting a segment, a Coincident constraint is created.
+- When entering an end point, only segments are selectable.
+
+**TUI Command**:
+
+.. py:function:: Sketch_1.addArc(TransversalPoint, EndX, EndY, Inversed, True)
- :param object: Tanget Point.
+ :param object: Transversal Point.
:param real: End X.
:param real: End Y.
:param boolean: Is inversed.
+ :param boolean: Arc is transversal (always True).
:return: Result object.
Result
SketchLine_3 = Sketch_1.addLine(25.0, 109.4, 68.1, 153.6)
SketchLine_3.setAuxiliary(True)
SketchArc_3 = Sketch_1.addArc(SketchLine_3.startPoint(), 92.1, 34.0, True)
+SketchArc_4 = Sketch_1.addArc(SketchLine_3.endPoint(), 150.0, 10.0, True, True)
model.do()
model.end()
.. _sketchPerpendicular:
-.. |perpendicular.icon| image:: images/perpendicular.png
+.. |Perpendicular.icon| image:: images/Perpendicular.png
Perpendicular constraint
========================
Perpendicular constraint fixes two lines at 90 degrees to one another.
+For a line and a circle/arc the perpendicular constraint fixes the center of circle/arc to be on a line.
To create a Perpendicular constraint in the active Sketch:
#. select in the Main Menu *Sketch - > Perpendicular* item or
-#. click |perpendicular.icon| **Perpendicular** button in Sketch toolbar:
+#. click |Perpendicular.icon| **Perpendicular** button in Sketch toolbar:
Property panel:
Input fields:
-- **First line** is the first line selected in the view.
-- **Second line** is the second line selected in the view.
+- **First object** is the first line, circle or arc selected in the view.
+- **Second object** is the second line, circle or arc selected in the view.
-After the lines are selected, a special sign will be added to each of them in the view.
+After the objects are selected, a special sign will be added to each of them in the view.
+
+If one of selected objects is circular, then another has to be a straight line.
**TUI Command**:
Created Perpendicular constraint appears in the view.
.. image:: images/Perpendicular_res.png
- :align: center
+ :align: center
.. centered::
Created perpendicular constraint
<validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
</sketch-2dpoint_selector>
</box>
+ <box id="by_transversal_line"
+ icon="icons/Sketch/arc_perp_32x32.png"
+ title="Perpendicular to line">
+ <sketch_shape_selector id="tangent_point"
+ label="Transversal point"
+ tooltip="Select point on line"
+ shape_types="vertex">
+ <validator id="SketchPlugin_ArcTransversalPoint"/>
+ </sketch_shape_selector>
+ <sketch-2dpoint_selector id="end_point_3"
+ reference_attribute="end_point_ref"
+ title="End point"
+ tooltip="End point"
+ accept_expressions="0"
+ enable_value="enable_by_preferences">
+ <validator id="SketchPlugin_ArcEndPointValidator" parameters="end_point_ref"/>
+ </sketch-2dpoint_selector>
+ </box>
</toolbox>
<labelvalue id="radius"
icon="icons/Sketch/radius.png"
</group>
<group id="Dimensional constraints">
- <!-- SketchConstraintDistance -->
+ <!-- SketchConstraintDistance -->
<feature
id="SketchConstraintDistance"
title="Distance"
<validator id="PartSet_ParallelSelection"/>
</feature>
- <!-- SketchConstraintPerpendicular -->
+ <!-- SketchConstraintPerpendicular -->
<feature id="SketchConstraintPerpendicular" title="Perpendicular"
- tooltip="Create constraint defining two perpendicular lines"
+ tooltip="Create constraint defining two orthogonal objects"
icon="icons/Sketch/perpendicular.png"
helpfile="perpendicularFeature.html">
<sketch_shape_selector id="ConstraintEntityA"
- label="First line" tooltip="Select a line"
+ label="First object" tooltip="Select line or arc"
shape_types="edge">
<validator id="PartSet_DifferentObjects"/>
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
- <validator id="GeomValidators_ShapeType" parameters="line"/>
+ <validator id="SketchPlugin_PerpendicularAttr" parameters="ConstraintEntityB"/>
+ <validator id="GeomValidators_ShapeType" parameters="line,circle"/>
</sketch_shape_selector>
<sketch_shape_selector id="ConstraintEntityB"
- label="Second line" tooltip="Select a line"
+ label="Second object" tooltip="Select line or arc"
shape_types="edge">
- <validator id="PartSet_DifferentObjects"/>
+ <validator id="PartSet_DifferentObjects"/>
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
- <validator id="GeomValidators_ShapeType" parameters="line"/>
+ <validator id="SketchPlugin_PerpendicularAttr" parameters="ConstraintEntityA"/>
+ <validator id="GeomValidators_ShapeType" parameters="line,circle"/>
</sketch_shape_selector>
<validator id="PartSet_PerpendicularSelection"/>
</feature>
<validator id="PartSet_EqualSelection"/>
</feature>
- <!-- SketchConstraintCollinear -->
+ <!-- SketchConstraintCollinear -->
<feature id="SketchConstraintCollinear" title="Collinear" tooltip="Create constraint defining collinearity of two lines"
icon="icons/Sketch/collinear.png"
helpfile="collinearFeature.html">
PlaneGCSSolver_PointWrapper.h
PlaneGCSSolver_ScalarWrapper.h
PlaneGCSSolver_AngleWrapper.h
+ PlaneGCSSolver_BooleanWrapper.h
PlaneGCSSolver_Tools.h
)
PlaneGCSSolver_PointWrapper.cpp
PlaneGCSSolver_ScalarWrapper.cpp
PlaneGCSSolver_AngleWrapper.cpp
+ PlaneGCSSolver_BooleanWrapper.cpp
PlaneGCSSolver_Tools.cpp
)
#include <PlaneGCSSolver_AttributeBuilder.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeDouble.h>
return theStorage ? theStorage->createParameter() : (new double(0));
}
+static EntityWrapperPtr createBoolean(const AttributePtr& theAttribute)
+{
+ BooleanWrapperPtr aWrapper;
+ AttributeBooleanPtr aBoolean =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+ if (aBoolean)
+ aWrapper = BooleanWrapperPtr(new PlaneGCSSolver_BooleanWrapper(aBoolean->value()));
+ return aWrapper;
+}
+
static EntityWrapperPtr createScalar(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
aResult = createPoint(theAttribute, myStorage);
if (!aResult)
aResult = createScalar(theAttribute, myStorage);
+ if (!aResult)
+ aResult = createBoolean(theAttribute);
if (aResult && !myStorage)
aResult->setExternal(true);
return aResult;
--- /dev/null
+// Copyright (C) 2014-2019 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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include <PlaneGCSSolver_BooleanWrapper.h>
+
+PlaneGCSSolver_BooleanWrapper::PlaneGCSSolver_BooleanWrapper(bool theParam)
+ : myValue(theParam)
+{
+}
--- /dev/null
+// Copyright (C) 2014-2019 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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// 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
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef PlaneGCSSolver_BooleanWrapper_H_
+#define PlaneGCSSolver_BooleanWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ * Wrapper providing storage for boolean values.
+ */
+class PlaneGCSSolver_BooleanWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+ PlaneGCSSolver_BooleanWrapper(bool theValue);
+
+ /// \brief Change value of parameter
+ void setValue(bool theValue)
+ { myValue = theValue; }
+ /// \brief Return value of parameter
+ bool value() const
+ { return myValue; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const
+ { return ENTITY_BOOLEAN; }
+
+protected:
+ bool myValue;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_BooleanWrapper> BooleanWrapperPtr;
+
+#endif
/// Types of entities
enum SketchSolver_EntityType {
ENTITY_UNKNOWN = 0,
+ ENTITY_BOOLEAN,
ENTITY_SCALAR,
ENTITY_ANGLE,
ENTITY_POINT,
#define PlaneGCSSolver_EdgeWrapper_H_
#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_EntityWrapper.h>
/**
bool isDegenerated() const;
+ void setReversed(BooleanWrapperPtr theReversed)
+ { myReversed = theReversed; }
+
+ bool isReversed() const
+ { return myReversed ? myReversed->value() : false; }
+
private:
SketchSolver_EntityType myType;
GCSCurvePtr myEntity;
+ BooleanWrapperPtr myReversed; // preferably used to control arc orientation
};
typedef std::shared_ptr<PlaneGCSSolver_EdgeWrapper> EdgeWrapperPtr;
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
PlaneGCSSolver_Storage* theStorage)
{
std::shared_ptr<GCS::Arc> aNewArc(new GCS::Arc);
+ BooleanWrapperPtr isReversed;
// Base attributes of arc (center, start and end points)
AttributeEntityMap::const_iterator anIt = theAttributes.begin();
for (; anIt != theAttributes.end(); ++anIt) {
std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
- if (!aPoint)
- continue;
-
- if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID())
- aNewArc->center = *(aPoint->point());
- else if (anIt->first->id() == SketchPlugin_Arc::START_ID())
- aNewArc->start = *(aPoint->point());
- else if (anIt->first->id() == SketchPlugin_Arc::END_ID())
- aNewArc->end = *(aPoint->point());
+ if (aPoint) {
+ if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID())
+ aNewArc->center = *(aPoint->point());
+ else if (anIt->first->id() == SketchPlugin_Arc::START_ID())
+ aNewArc->start = *(aPoint->point());
+ else if (anIt->first->id() == SketchPlugin_Arc::END_ID())
+ aNewArc->end = *(aPoint->point());
+ }
+ else {
+ // reversed flag
+ isReversed = std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(anIt->second);
+ }
}
// Additional atrtributes of arc necessary for PlaneGCS solver
new GeomAPI_Dir2d((*aNewArc->end.x) - aCenter->x(), (*aNewArc->end.y) - aCenter->y()));
*aNewArc->endAngle = OX->angle(aDir);
- return EntityWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+ EdgeWrapperPtr anArcWrapper(new PlaneGCSSolver_EdgeWrapper(aNewArc));
+ anArcWrapper->setReversed(isReversed);
+ return anArcWrapper;
}
bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
if (theOwnerName == SketchPlugin_Arc::ID()) {
return theAttrName == SketchPlugin_Arc::CENTER_ID() ||
theAttrName == SketchPlugin_Arc::START_ID() ||
- theAttrName == SketchPlugin_Arc::END_ID();
+ theAttrName == SketchPlugin_Arc::END_ID() ||
+ theAttrName == SketchPlugin_Arc::REVERSED_ID();
}
else if (theOwnerName == SketchPlugin_Circle::ID()) {
return theAttrName == SketchPlugin_Circle::CENTER_ID() ||
#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
isUpdated = updateValue(aScalar->value(), aValue);
if (isUpdated)
aWrapper->setValue(aValue);
+ } else {
+ AttributeBooleanPtr aBoolean =
+ std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(theAttribute);
+ if (aBoolean) {
+ BooleanWrapperPtr aWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_BooleanWrapper>(theEntity);
+ isUpdated = aWrapper->value() != aBoolean->value();
+ aWrapper->setValue(aBoolean->value());
+ }
}
}
std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
for (; anAttrIt != anAttributes.end(); ++anAttrIt)
if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
+ (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() ||
+ (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId())
isUpdated = update(*anAttrIt) || isUpdated;
// check external attribute is changed
if (sendNotify && isUpdated)
notify(theFeature);
- // update arc
- if (aRelated && aRelated->type() == ENTITY_ARC) {
- /// TODO: this code should be shared with FeatureBuilder somehow
-
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
- std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
- std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
-
- static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
- std::shared_ptr<GeomAPI_Pnt2d> aCenter(
- new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
- std::shared_ptr<GeomAPI_Pnt2d> aStart(
- new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
-
- *anArc->rad = aStart->distance(aCenter);
-
- std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
- *anArc->startAngle = OX->angle(aDir);
-
- aDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
- *anArc->endAngle = OX->angle(aDir);
- }
-
return isUpdated;
}
// Additional constaints to fix arc's extra DoF (if the arc is not external):
std::list<GCSConstraintPtr> anArcConstraints;
- // 1. distances from center till start and end points are equal to radius
- anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
- anArc->center, anArc->start, anArc->rad)));
- anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
- anArc->center, anArc->end, anArc->rad)));
- // 2. angles of start and end points should be equal to the arc angles
- anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
- anArc->center, anArc->start, anArc->startAngle)));
- anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
- anArc->center, anArc->end, anArc->endAngle)));
+ // constrain the start point on the arc
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+ // constrain the end point on the arc
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintCurveValue(
+ anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
ConstraintWrapperPtr aWrapper(
new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
}
}
+void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
+{
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myArcConstraintMap.begin();
+ for (; anIt != myArcConstraintMap.end(); ++anIt) {
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+ // tune start angle of the arc to be in [0, 2PI]
+ while (*anArc->startAngle < -PI)
+ *anArc->startAngle += 2.0 * PI;
+ while (*anArc->startAngle >= PI)
+ *anArc->startAngle -= 2.0 * PI;
+ // adjust end angle of the arc
+ if (anEdge->isReversed()) {
+ while (*anArc->endAngle > *anArc->startAngle)
+ *anArc->endAngle -= 2.0 * PI;
+ while (*anArc->endAngle + 2 * PI < *anArc->startAngle)
+ *anArc->endAngle += 2.0 * PI;
+ } else {
+ while (*anArc->endAngle < *anArc->startAngle)
+ *anArc->endAngle += 2.0 * PI;
+ while (*anArc->endAngle > *anArc->startAngle + 2 * PI)
+ *anArc->endAngle -= 2.0 * PI;
+ }
+ }
+
+ // update parameters of Middle point constraint for point on arc
+ std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
+ for (; aCIt != myConstraintMap.end(); ++aCIt)
+ if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
+ notify(aCIt->first);
+ }
+}
+
bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
{
virtual bool isEmpty() const
{ return SketchSolver_Storage::isEmpty() && myArcConstraintMap.empty(); }
+ /// \brief Make parametrization of arcs consistent.
+ /// Forward arcs should have the last parameter greater than the first parameter.
+ /// Reversed arcs should have the last parameter lesser than the first parameter.
+ virtual void adjustParametrizationOfArcs();
+
private:
/// \brief Convert feature using specified builder.
EntityWrapperPtr createFeature(const FeaturePtr& theFeature,
std::shared_ptr<PlaneGCSSolver_ScalarWrapper> theIntermed);
static ConstraintWrapperPtr
createConstraintMiddlePoint(std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity);
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> theAuxParameters);
static GCS::SET_pD scalarParameters(const ScalarWrapperPtr& theScalar);
static GCS::SET_pD pointParameters(const PointWrapperPtr& thePoint);
aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_EDGE_WRAPPER(theEntity1));
break;
case CONSTRAINT_MIDDLE_POINT:
- aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1));
+ aResult = createConstraintMiddlePoint(aPoint1, GCS_EDGE_WRAPPER(theEntity1), aPoint2);
break;
case CONSTRAINT_PT_PT_DISTANCE:
aResult = createConstraintDistancePointPoint(GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2);
ConstraintWrapperPtr createConstraintMiddlePoint(
std::shared_ptr<PlaneGCSSolver_PointWrapper> thePoint,
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity)
+ std::shared_ptr<PlaneGCSSolver_EdgeWrapper> theEntity,
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> theAuxParameters)
{
+ std::list<GCSConstraintPtr> aConstrList;
+
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::ConstraintPointOnPerpBisector(*aPoint, aLine->p1, aLine->p2)));
- aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+ if (aLine) {
+ aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine)));
+ aConstrList.push_back(
+ GCSConstraintPtr(new GCS::ConstraintPointOnPerpBisector(*aPoint, aLine->p1, aLine->p2)));
+ }
+ else {
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(theEntity->entity());
+ if (anArc) {
+ double* u = theAuxParameters->point()->x;
+ double* diff = theAuxParameters->point()->y;
+ *u = (*anArc->startAngle + *anArc->endAngle) * 0.5;
+ *diff = (*anArc->endAngle - *anArc->startAngle) * 0.5;
+
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(*aPoint, aPoint->x, *anArc, u)));
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(*aPoint, aPoint->y, *anArc, u)));
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintDifference(anArc->startAngle, u, diff)));
+ aConstrList.push_back(GCSConstraintPtr(
+ new GCS::ConstraintDifference(u, anArc->endAngle, diff)));
+ }
+ }
- return ConstraintWrapperPtr(
+ return aConstrList.empty() ? ConstraintWrapperPtr() : ConstraintWrapperPtr(
new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_MIDDLE_POINT));
}
{
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());
- GCSConstraintPtr aNewConstr(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
+
+ std::shared_ptr<GCS::Circle> aCirc1 =
+ std::dynamic_pointer_cast<GCS::Circle>(theEntity1->entity());
+ std::shared_ptr<GCS::Circle> aCirc2 =
+ std::dynamic_pointer_cast<GCS::Circle>(theEntity2->entity());
+
+ GCSConstraintPtr aNewConstr;
+ if (aLine1 && aLine2)
+ aNewConstr.reset(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2)));
+ else {
+ if (aLine1 && aCirc2)
+ aCirc1 = aCirc2;
+ else if (aLine2 && aCirc1)
+ aLine1 = aLine2;
+
+ aNewConstr.reset(new GCS::ConstraintPointOnLine(aCirc1->center, *aLine1));
+ }
return ConstraintWrapperPtr(
new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PERPENDICULAR));
#include <SketchSolver_ConstraintMiddle.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_Storage.h>
+#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_UpdateCoincidence.h>
void SketchSolver_ConstraintMiddle::getAttributes(
std::vector<EntityWrapperPtr>& theAttributes)
{
SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+
+ // create auxiliary point if middle point on arc is specified
+ if (theAttributes[2]->type() == ENTITY_ARC) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+ myOddPoint = GCSPointPtr(new GCS::Point);
+ myOddPoint->x = aStorage->createParameter();
+ myOddPoint->y = aStorage->createParameter();
+ theAttributes[1] = PointWrapperPtr(new PlaneGCSSolver_PointWrapper(myOddPoint));
+ }
+}
+
+bool SketchSolver_ConstraintMiddle::remove()
+{
+ if (myOddPoint) {
+ std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
+ std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
+
+ GCS::SET_pD aParams;
+ aParams.insert(myOddPoint->x);
+ aParams.insert(myOddPoint->y);
+ aStorage->removeParameters(aParams);
+ }
+ return SketchSolver_ConstraintCoincidence::remove();
}
void SketchSolver_ConstraintMiddle::notify(const FeaturePtr& theFeature,
PlaneGCSSolver_Update* theUpdater)
{
- if (theFeature == myBaseConstraint && myInSolver)
- return; // the constraint is already being updated
+ if (theFeature == myBaseConstraint && myInSolver) {
+ // the constraint is already being updated,
+ // update the middle point parameter if the constraint is "point-on-arc".
+ if (myOddPoint) {
+ EntityWrapperPtr anArcEntity =
+ myAttributes.front()->type() == ENTITY_ARC ? myAttributes.front() : myAttributes.back();
+ EdgeWrapperPtr anArcEdge =
+ std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anArcEntity);
+ std::shared_ptr<GCS::Arc> anArc;
+ if (anArcEdge)
+ anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEdge->entity());
+ if (anArc) {
+ // recalculate parameters of middle point according to arc
+ *myOddPoint->x = (*anArc->startAngle + *anArc->endAngle) * 0.5;
+ *myOddPoint->y = (*anArc->endAngle - *anArc->startAngle) * 0.5;
+ }
+ }
+ return;
+ }
PlaneGCSSolver_UpdateCoincidence* anUpdater =
static_cast<PlaneGCSSolver_UpdateCoincidence*>(theUpdater);
// remove previously adde constraint
myStorage->removeConstraint(myBaseConstraint);
// merge divided constraints into single object
- std::list<GCSConstraintPtr> aGCSConstraints;
- std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
- std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(myMiddle);
- aGCSConstraints.push_back(aConstraint->constraints().front());
- aConstraint =
- std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(mySolverConstraint);
- aGCSConstraints.push_back(aConstraint->constraints().front());
+ std::list<GCSConstraintPtr> aGCSConstraints = myMiddle->constraints();
+ aGCSConstraints.push_front(mySolverConstraint->constraints().front());
myMiddle = ConstraintWrapperPtr();
mySolverConstraint = ConstraintWrapperPtr(
std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(mySolverConstraint);
std::list<GCSConstraintPtr> aGCSConstraints = aConstraint->constraints();
- myMiddle = ConstraintWrapperPtr(
- new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.front(), CONSTRAINT_MIDDLE_POINT));
mySolverConstraint = ConstraintWrapperPtr(
- new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.back(), CONSTRAINT_MIDDLE_POINT));
+ new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.front(), CONSTRAINT_MIDDLE_POINT));
+ aGCSConstraints.pop_front();
+ myMiddle = ConstraintWrapperPtr(
+ new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints, CONSTRAINT_MIDDLE_POINT));
// send middle constraint only
myStorage->addConstraint(myBaseConstraint, myMiddle);
virtual void notify(const FeaturePtr& theFeature,
PlaneGCSSolver_Update* theUpdater);
+ /// \brief Remove constraint
+ virtual bool remove();
+
protected:
/// \brief Generate list of attributes of constraint in order useful for constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
private:
ConstraintWrapperPtr myMiddle;
+ GCSPointPtr myOddPoint; ///< auxiliary point to adjust midpoint-on-arc
};
#endif
SolverConstraintPtr(aConstraint)->process(theStorage, theEventsBlocked);
if (aConstraint->error().empty()) {
aConstraint->startPoint(theFrom);
+ theStorage->adjustParametrizationOfArcs();
theSketchSolver->initialize();
aConstraint->moveTo(theTo);
theStorage->setNeedToResolve(true);
PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
try {
- if (!isGroupEmpty)
+ if (!isGroupEmpty) {
+ myStorage->adjustParametrizationOfArcs();
aResult = mySketchSolver->solve();
+ }
if (aResult == PlaneGCSSolver_Solver::STATUS_FAILED &&
!myTempConstraints.empty()) {
mySketchSolver->undo();
/// \brief Notify all subscribers about update of the feature
void notify(const FeaturePtr& theFeature) const;
+ /// \brief Make parametrization of arcs consistent.
+ /// Forward arcs should have the last parameter greater than the first parameter.
+ /// Reversed arcs should have the last parameter lesser than the first parameter.
+ virtual void adjustParametrizationOfArcs() = 0;
+
protected:
/// \brief Convert result to feature or attribute if theResult is linked to center of circle/arc
static void resultToFeatureOrAttribute(const ObjectPtr& theResult,
#include <GeomAPI_Curve.h>
#include <GeomAPI_Edge.h>
#include <GeomAPI_Lin.h>
+#include <GeomAPI_Vertex.h>
IMPLEMENT_STANDARD_RTTIEXT(SketcherPrs_Perpendicular, SketcherPrs_SymbolPrs);
GeomEdgePtr aEdge1(new GeomAPI_Edge(aShp1));
GeomEdgePtr aEdge2(new GeomAPI_Edge(aShp2));
- std::shared_ptr<GeomAPI_Lin> aLin1 = aEdge1->line();
- std::shared_ptr<GeomAPI_Lin> aLin2 = aEdge2->line();
-
- std::shared_ptr<GeomAPI_Pnt> aPnt = aLin1->intersect(aLin2);
- double aParam1 = aLin1->projParam(aPnt);
- double aParam2 = aLin2->projParam(aPnt);
-
- GeomAPI_Curve aCurve1(aShp1);
- GeomAPI_Curve aCurve2(aShp2);
- bool isInside1 = (aParam1 >= (aCurve1.startParam() - Precision::Confusion())) &&
- (aParam1 <= (aCurve1.endParam() + Precision::Confusion()));
- bool isInside2 = (aParam2 >= (aCurve2.startParam() - Precision::Confusion())) &&
- (aParam2 <= (aCurve2.endParam() + Precision::Confusion()));
-
- if (!(isInside1 && isInside2))
- aPnt = std::shared_ptr<GeomAPI_Pnt>();
+ GeomShapePtr anInter = aEdge1->intersect(aEdge2);
+ std::shared_ptr<GeomAPI_Pnt> aPnt;
+ if (anInter && anInter->isVertex())
+ aPnt = anInter->vertex()->point();
// Compute position of symbols
SketcherPrs_PositionMgr* aMgr = SketcherPrs_PositionMgr::get();
void SketcherPrs_Perpendicular::drawLines(const Handle(Prs3d_Presentation)& thePrs,
Quantity_Color theColor) const
{
- Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup(thePrs);
-
- Handle(Graphic3d_AspectLine3d) aLineAspect =
- new Graphic3d_AspectLine3d(theColor, Aspect_TOL_SOLID, 2);
- aGroup->SetPrimitivesAspect(aLineAspect);
-
// Draw constrained lines
- addLine(aGroup, SketchPlugin_Constraint::ENTITY_A());
- addLine(aGroup, SketchPlugin_Constraint::ENTITY_B());
+ for (int i = 0; i < 2; ++i) {
+ ObjectPtr anObj =
+ SketcherPrs_Tools::getResult(myConstraint, SketchPlugin_Constraint::ATTRIBUTE(i));
+ GeomShapePtr aShape = SketcherPrs_Tools::getShape(anObj);
+ if (!aShape)
+ return;
+ drawShape(aShape, thePrs, theColor);
+ }
}
-
}
action("DELETE_CMD")->setEnabled(canBeDeleted);
}
+ if (hasFeature && myWorkshop->canMoveFeature())
+ action("MOVE_CMD")->setEnabled(true);
} // end multi-selection
// Check folder management commands state if only features are selected
aActions.append(action("ADD_OUT_FOLDER_BEFORE_CMD"));
aActions.append(action("ADD_OUT_FOLDER_AFTER_CMD"));
aActions.append(mySeparator3);
- //aActions.append(action("MOVE_CMD"));
+ aActions.append(action("MOVE_CMD"));
aActions.append(action("COLOR_CMD"));
aActions.append(action("DEFLECTION_CMD"));
aActions.append(action("TRANSPARENCY_CMD"));
eachWidget->restoreValue();
}
// the repaint is used here to immediately react in GUI to the values change.
- repaint();
+ update();
}
void XGUI_PropertyPanel::createContentPanel(FeaturePtr theFeature)
}
//**************************************************************
+bool compareFeature(const FeaturePtr& theF1, const FeaturePtr& theF2) {
+ DocumentPtr aDoc = theF1->document();
+ return aDoc->index(theF1) < aDoc->index(theF2);
+}
void XGUI_Workshop::moveObjects()
{
if (!abortAllOperations())
if (!XGUI_Tools::canRemoveOrRename(desktop(), aFeatures))
return;
+ // Sort features by index in document
+ std::list<FeaturePtr> aFList(aFeatures.begin(), aFeatures.end());
+ aFList.sort(compareFeature);
+
DocumentPtr anActiveDocument = aMgr->activeDocument();
FeaturePtr aCurrentFeature = anActiveDocument->currentFeature(true);
- std::set<FeaturePtr>::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end();
+ std::list<FeaturePtr>::const_iterator anIt = aFList.begin(), aLast = aFList.end();
for (; anIt != aLast; anIt++) {
FeaturePtr aFeature = *anIt;
if (!aFeature.get() || !myModule->canApplyAction(aFeature, anActionId))