| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #ifndef SKETCHERGUI_DrawSketchHandlerLineSet_H
|
| | #define SKETCHERGUI_DrawSketchHandlerLineSet_H
|
| |
|
| | #include <QApplication>
|
| |
|
| | #include <Inventor/events/SoKeyboardEvent.h>
|
| | #include <boost/math/special_functions/fpclassify.hpp>
|
| |
|
| | #include <Gui/Notifications.h>
|
| | #include <Gui/Command.h>
|
| | #include <Gui/CommandT.h>
|
| | #include <Gui/InputHint.h>
|
| |
|
| | #include <Mod/Sketcher/App/SketchObject.h>
|
| |
|
| | #include "DrawSketchHandler.h"
|
| | #include "GeometryCreationMode.h"
|
| | #include "Utils.h"
|
| | #include "ViewProviderSketch.h"
|
| | #include "SnapManager.h"
|
| |
|
| |
|
| | namespace SketcherGui
|
| | {
|
| |
|
| | extern GeometryCreationMode geometryCreationMode;
|
| |
|
| | class DrawSketchHandlerLineSet: public DrawSketchHandler
|
| | {
|
| | Q_DECLARE_TR_FUNCTIONS(SketcherGui::DrawSketchHandlerLineSet)
|
| |
|
| | public:
|
| | DrawSketchHandlerLineSet()
|
| | : Mode(STATUS_SEEK_First)
|
| | , SegmentMode(SEGMENT_MODE_Line)
|
| | , TransitionMode(TRANSITION_MODE_Free)
|
| | , SnapMode(SNAP_MODE_Free)
|
| | , suppressTransition(false)
|
| | , EditCurve(2)
|
| | , firstCurve(-1)
|
| | , previousCurve(-1)
|
| | , firstPosId(Sketcher::PointPos::none)
|
| | , previousPosId(Sketcher::PointPos::none)
|
| | , startAngle(0)
|
| | , endAngle(0)
|
| | , arcRadius(0)
|
| | , firstsegment(true)
|
| | {}
|
| |
|
| | ~DrawSketchHandlerLineSet() override = default;
|
| |
|
| |
|
| | enum SELECT_MODE
|
| | {
|
| | STATUS_SEEK_First,
|
| | STATUS_SEEK_Second,
|
| | STATUS_Do,
|
| | STATUS_Close
|
| | };
|
| |
|
| | enum SEGMENT_MODE
|
| | {
|
| | SEGMENT_MODE_Arc,
|
| | SEGMENT_MODE_Line
|
| | };
|
| |
|
| | enum TRANSITION_MODE
|
| | {
|
| | TRANSITION_MODE_Free,
|
| | TRANSITION_MODE_Tangent,
|
| | TRANSITION_MODE_Perpendicular_L,
|
| | TRANSITION_MODE_Perpendicular_R
|
| | };
|
| |
|
| | enum SNAP_MODE
|
| | {
|
| | SNAP_MODE_Free,
|
| | SNAP_MODE_45Degree
|
| | };
|
| |
|
| |
|
| | void registerPressedKey(bool pressed, int key) override
|
| | {
|
| | if (Mode == STATUS_SEEK_Second && key == SoKeyboardEvent::M && pressed
|
| | && previousCurve != -1) {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | SnapMode = SNAP_MODE_Free;
|
| |
|
| | Base::Vector2d onSketchPos;
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | onSketchPos = EditCurve[EditCurve.size() - 1];
|
| | }
|
| | else {
|
| | onSketchPos = EditCurve[29];
|
| | }
|
| |
|
| | const Part::Geometry* geom = sketchgui->getSketchObject()->getGeometry(previousCurve);
|
| |
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | switch (TransitionMode) {
|
| | case TRANSITION_MODE_Free:
|
| | if (geom->is<Part::GeomArcOfCircle>()) {
|
| | SegmentMode = SEGMENT_MODE_Arc;
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | }
|
| | else {
|
| | TransitionMode = TRANSITION_MODE_Perpendicular_L;
|
| | }
|
| | break;
|
| | case TRANSITION_MODE_Perpendicular_L:
|
| | if (geom->is<Part::GeomArcOfCircle>()) {
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | }
|
| | else {
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | }
|
| | break;
|
| | case TRANSITION_MODE_Tangent:
|
| | if (geom->is<Part::GeomArcOfCircle>()) {
|
| | TransitionMode = TRANSITION_MODE_Perpendicular_L;
|
| | }
|
| | else {
|
| | SegmentMode = SEGMENT_MODE_Arc;
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | }
|
| | break;
|
| | default:
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | break;
|
| | }
|
| | }
|
| | else {
|
| | switch (TransitionMode) {
|
| | case TRANSITION_MODE_Tangent:
|
| | TransitionMode = TRANSITION_MODE_Perpendicular_L;
|
| | break;
|
| | case TRANSITION_MODE_Perpendicular_L:
|
| | TransitionMode = TRANSITION_MODE_Perpendicular_R;
|
| | break;
|
| | default:
|
| | SegmentMode = SEGMENT_MODE_Line;
|
| | if (geom->is<Part::GeomArcOfCircle>()) {
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | }
|
| | else {
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | }
|
| | break;
|
| | }
|
| | }
|
| |
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3);
|
| | }
|
| | else {
|
| | EditCurve.resize(32);
|
| | }
|
| | auto snapHandle = std::make_unique<SnapManager::SnapHandle>(nullptr, onSketchPos);
|
| | mouseMove(*snapHandle);
|
| | }
|
| | else {
|
| | DrawSketchHandler::registerPressedKey(pressed, key);
|
| | }
|
| | }
|
| |
|
| | void mouseMove(SnapManager::SnapHandle snapHandle) override
|
| | {
|
| | using std::numbers::pi;
|
| | Base::Vector2d onSketchPos = snapHandle.compute();
|
| |
|
| | suppressTransition = false;
|
| | if (Mode == STATUS_SEEK_First) {
|
| | setPositionText(onSketchPos);
|
| | seekAndRenderAutoConstraint(sugConstr1, onSketchPos, Base::Vector2d(0.f, 0.f));
|
| | }
|
| | else if (Mode == STATUS_SEEK_Second) {
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | EditCurve[EditCurve.size() - 1] = onSketchPos;
|
| | if (TransitionMode == TRANSITION_MODE_Tangent) {
|
| | Base::Vector2d Tangent(dirVec.x, dirVec.y);
|
| | EditCurve[1].ProjectToLine(EditCurve[2] - EditCurve[0], Tangent);
|
| | if (EditCurve[1] * Tangent < 0) {
|
| | EditCurve[1] = EditCurve[2];
|
| | suppressTransition = true;
|
| | }
|
| | else {
|
| | EditCurve[1] = EditCurve[0] + EditCurve[1];
|
| | }
|
| | }
|
| | else if (TransitionMode == TRANSITION_MODE_Perpendicular_L
|
| | || TransitionMode == TRANSITION_MODE_Perpendicular_R) {
|
| | Base::Vector2d Perpendicular(-dirVec.y, dirVec.x);
|
| | EditCurve[1].ProjectToLine(EditCurve[2] - EditCurve[0], Perpendicular);
|
| | EditCurve[1] = EditCurve[0] + EditCurve[1];
|
| | }
|
| |
|
| | drawEdit(EditCurve);
|
| |
|
| | float length = (EditCurve[1] - EditCurve[0]).Length();
|
| | float angle = (EditCurve[1] - EditCurve[0]).GetAngle(Base::Vector2d(1.f, 0.f));
|
| |
|
| | if (showCursorCoords()) {
|
| | SbString text;
|
| | std::string lengthString = lengthToDisplayFormat(length, 1);
|
| | std::string angleString = angleToDisplayFormat(angle * 180.0 / pi, 1);
|
| | text.sprintf(" (%s, %s)", lengthString.c_str(), angleString.c_str());
|
| | setPositionText(EditCurve[1], text);
|
| | }
|
| |
|
| | if (TransitionMode == TRANSITION_MODE_Free) {
|
| | seekAndRenderAutoConstraint(sugConstr2, onSketchPos, onSketchPos - EditCurve[0]);
|
| | }
|
| | }
|
| | else if (SegmentMode == SEGMENT_MODE_Arc) {
|
| |
|
| | if (QApplication::keyboardModifiers() == Qt::ControlModifier) {
|
| | SnapMode = SNAP_MODE_45Degree;
|
| | }
|
| | else {
|
| | SnapMode = SNAP_MODE_Free;
|
| | }
|
| |
|
| | Base::Vector2d Tangent;
|
| | if (TransitionMode == TRANSITION_MODE_Tangent) {
|
| | Tangent = Base::Vector2d(dirVec.x, dirVec.y);
|
| | }
|
| | else if (TransitionMode == TRANSITION_MODE_Perpendicular_L) {
|
| | Tangent = Base::Vector2d(-dirVec.y, dirVec.x);
|
| | }
|
| | else if (TransitionMode == TRANSITION_MODE_Perpendicular_R) {
|
| | Tangent = Base::Vector2d(dirVec.y, -dirVec.x);
|
| | }
|
| |
|
| | double theta = Tangent.GetAngle(onSketchPos - EditCurve[0]);
|
| |
|
| | arcRadius = (onSketchPos - EditCurve[0]).Length() / (2.0 * sin(theta));
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | double x1 = EditCurve[0].x;
|
| | double y1 = EditCurve[0].y;
|
| | double x2 = x1 + Tangent.x;
|
| | double y2 = y1 + Tangent.y;
|
| | double x3 = onSketchPos.x;
|
| | double y3 = onSketchPos.y;
|
| | if ((x2 * y3 - x3 * y2) - (x1 * y3 - x3 * y1) + (x1 * y2 - x2 * y1) > 0) {
|
| | arcRadius *= -1;
|
| | }
|
| | if (boost::math::isnan(arcRadius) || boost::math::isinf(arcRadius)) {
|
| | arcRadius = 0.f;
|
| | }
|
| |
|
| | CenterPoint = EditCurve[0]
|
| | + Base::Vector2d(arcRadius * Tangent.y, -arcRadius * Tangent.x);
|
| |
|
| | double rx = EditCurve[0].x - CenterPoint.x;
|
| | double ry = EditCurve[0].y - CenterPoint.y;
|
| |
|
| | startAngle = atan2(ry, rx);
|
| |
|
| | double rxe = onSketchPos.x - CenterPoint.x;
|
| | double rye = onSketchPos.y - CenterPoint.y;
|
| | double arcAngle = atan2(-rxe * ry + rye * rx, rxe * rx + rye * ry);
|
| | if (boost::math::isnan(arcAngle) || boost::math::isinf(arcAngle)) {
|
| | arcAngle = 0.f;
|
| | }
|
| | if (arcRadius >= 0 && arcAngle > 0) {
|
| | arcAngle -= 2 * pi;
|
| | }
|
| | if (arcRadius < 0 && arcAngle < 0) {
|
| | arcAngle += 2 * pi;
|
| | }
|
| |
|
| | if (SnapMode == SNAP_MODE_45Degree) {
|
| | arcAngle = round(arcAngle / (pi / 4)) * pi / 4;
|
| | }
|
| |
|
| | endAngle = startAngle + arcAngle;
|
| |
|
| | for (int i = 1; i <= 29; i++) {
|
| | double angle = i * arcAngle / 29.0;
|
| | double dx = rx * cos(angle) - ry * sin(angle);
|
| | double dy = rx * sin(angle) + ry * cos(angle);
|
| | EditCurve[i] = Base::Vector2d(CenterPoint.x + dx, CenterPoint.y + dy);
|
| | }
|
| |
|
| | EditCurve[30] = CenterPoint;
|
| | EditCurve[31] = EditCurve[0];
|
| |
|
| | drawEdit(EditCurve);
|
| |
|
| | if (showCursorCoords()) {
|
| | SbString text;
|
| | std::string radiusString = lengthToDisplayFormat(std::abs(arcRadius), 1);
|
| | std::string angleString = angleToDisplayFormat(arcAngle * 180.0 / pi, 1);
|
| | text.sprintf(" (R%s, %s)", radiusString.c_str(), angleString.c_str());
|
| | setPositionText(onSketchPos, text);
|
| | }
|
| |
|
| | seekAndRenderAutoConstraint(sugConstr2, onSketchPos, Base::Vector2d(0.f, 0.f));
|
| | }
|
| | }
|
| | }
|
| |
|
| | bool pressButton(Base::Vector2d onSketchPos) override
|
| | {
|
| |
|
| | if (Mode == STATUS_SEEK_First) {
|
| |
|
| | EditCurve[0] = onSketchPos;
|
| |
|
| | virtualsugConstr1 = sugConstr1;
|
| |
|
| |
|
| |
|
| |
|
| | for (unsigned int i = 0; i < sugConstr1.size(); i++) {
|
| | if (sugConstr1[i].Type == Sketcher::Coincident) {
|
| | const Part::Geometry* geom = sketchgui->getSketchObject()->getGeometry(
|
| | sugConstr1[i].GeoId
|
| | );
|
| | if ((geom->is<Part::GeomLineSegment>() || geom->is<Part::GeomArcOfCircle>())
|
| | && (sugConstr1[i].PosId == Sketcher::PointPos::start
|
| | || sugConstr1[i].PosId == Sketcher::PointPos::end)) {
|
| | previousCurve = sugConstr1[i].GeoId;
|
| | previousPosId = sugConstr1[i].PosId;
|
| | updateTransitionData(
|
| | previousCurve,
|
| | previousPosId
|
| | );
|
| | if (geom->is<Part::GeomArcOfCircle>()) {
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | SnapMode = SNAP_MODE_Free;
|
| | }
|
| | sugConstr1.erase(sugConstr1.begin() + i);
|
| |
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | firstCurve = getHighestCurveIndex() + 1;
|
| | firstPosId = Sketcher::PointPos::start;
|
| |
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | EditCurve.resize(TransitionMode == TRANSITION_MODE_Free ? 2 : 3);
|
| | }
|
| | else if (SegmentMode == SEGMENT_MODE_Arc) {
|
| | EditCurve.resize(32);
|
| | }
|
| | Mode = STATUS_SEEK_Second;
|
| | }
|
| | else if (Mode == STATUS_SEEK_Second) {
|
| |
|
| | if (onSketchPos == EditCurve[0]) {
|
| | unsetCursor();
|
| | resetPositionText();
|
| | EditCurve.clear();
|
| | drawEdit(EditCurve);
|
| |
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/Mod/Sketcher"
|
| | );
|
| | bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true);
|
| |
|
| | if (continuousMode) {
|
| |
|
| | Mode = STATUS_SEEK_First;
|
| | SegmentMode = SEGMENT_MODE_Line;
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | SnapMode = SNAP_MODE_Free;
|
| | suppressTransition = false;
|
| | firstCurve = -1;
|
| | previousCurve = -1;
|
| | firstPosId = Sketcher::PointPos::none;
|
| | previousPosId = Sketcher::PointPos::none;
|
| | EditCurve.clear();
|
| | drawEdit(EditCurve);
|
| | EditCurve.resize(2);
|
| | applyCursor();
|
| | |
| | |
| | |
| |
|
| | return true;
|
| | }
|
| | else {
|
| | sketchgui->purgeHandler();
|
| |
|
| | return true;
|
| | }
|
| | }
|
| |
|
| | Mode = STATUS_Do;
|
| |
|
| | if (getPreselectPoint() != -1 && firstPosId != Sketcher::PointPos::none) {
|
| | int GeoId;
|
| | Sketcher::PointPos PosId;
|
| | sketchgui->getSketchObject()->getGeoVertexIndex(getPreselectPoint(), GeoId, PosId);
|
| | if (sketchgui->getSketchObject()
|
| | ->arePointsCoincident(GeoId, PosId, firstCurve, firstPosId)) {
|
| | Mode = STATUS_Close;
|
| | }
|
| | }
|
| | else if (getPreselectCross() == 0 && firstPosId != Sketcher::PointPos::none) {
|
| |
|
| | if (sketchgui->getSketchObject()
|
| | ->arePointsCoincident(-1, Sketcher::PointPos::start, firstCurve, firstPosId)) {
|
| | Mode = STATUS_Close;
|
| | }
|
| | }
|
| | }
|
| |
|
| | updateHint();
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool releaseButton(Base::Vector2d onSketchPos) override
|
| | {
|
| | if (Mode == STATUS_Do || Mode == STATUS_Close) {
|
| | bool addedGeometry = true;
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| |
|
| | try {
|
| |
|
| | Gui::Command::openCommand(
|
| | QT_TRANSLATE_NOOP("Command", "Add line to sketch polyline")
|
| | );
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addGeometry(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)),%s)",
|
| | EditCurve[0].x,
|
| | EditCurve[0].y,
|
| | EditCurve[1].x,
|
| | EditCurve[1].y,
|
| | constructionModeAsBooleanText()
|
| | );
|
| | }
|
| | catch (const Base::Exception&) {
|
| | addedGeometry = false;
|
| | Gui::NotifyError(
|
| | sketchgui,
|
| | QT_TRANSLATE_NOOP("Notifications", "Error"),
|
| | QT_TRANSLATE_NOOP("Notifications", "Failed to add line")
|
| | );
|
| | Gui::Command::abortCommand();
|
| | }
|
| |
|
| | firstsegment = false;
|
| | }
|
| | else if (SegmentMode == SEGMENT_MODE_Arc) {
|
| | if (!boost::math::isnormal(arcRadius)) {
|
| | Mode = STATUS_SEEK_Second;
|
| | return true;
|
| | }
|
| |
|
| | try {
|
| | Gui::Command::openCommand(
|
| | QT_TRANSLATE_NOOP("Command", "Add arc to sketch polyline")
|
| | );
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addGeometry(Part.ArcOfCircle"
|
| | "(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),%f),%f,%f),%s)",
|
| | CenterPoint.x,
|
| | CenterPoint.y,
|
| | std::abs(arcRadius),
|
| | std::min(startAngle, endAngle),
|
| | std::max(startAngle, endAngle),
|
| | constructionModeAsBooleanText()
|
| | );
|
| | }
|
| | catch (const Base::Exception&) {
|
| | addedGeometry = false;
|
| | Gui::NotifyError(
|
| | sketchgui,
|
| | QT_TRANSLATE_NOOP("Notifications", "Error"),
|
| | QT_TRANSLATE_NOOP("Notifications", "Failed to add arc")
|
| | );
|
| |
|
| | Gui::Command::abortCommand();
|
| | }
|
| |
|
| | firstsegment = false;
|
| | }
|
| |
|
| | int lastCurve = getHighestCurveIndex();
|
| |
|
| | if (addedGeometry && (previousPosId != Sketcher::PointPos::none)) {
|
| | Sketcher::PointPos lastStartPosId = (SegmentMode == SEGMENT_MODE_Arc
|
| | && startAngle > endAngle)
|
| | ? Sketcher::PointPos::end
|
| | : Sketcher::PointPos::start;
|
| | Sketcher::PointPos lastEndPosId = (SegmentMode == SEGMENT_MODE_Arc
|
| | && startAngle > endAngle)
|
| | ? Sketcher::PointPos::start
|
| | : Sketcher::PointPos::end;
|
| |
|
| | std::string constrType = "Coincident";
|
| | if (!suppressTransition && previousCurve != -1) {
|
| | if (TransitionMode == TRANSITION_MODE_Tangent) {
|
| | constrType = "Tangent";
|
| | }
|
| | else if (TransitionMode == TRANSITION_MODE_Perpendicular_L
|
| | || TransitionMode == TRANSITION_MODE_Perpendicular_R) {
|
| | constrType = "Perpendicular";
|
| | }
|
| | }
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('%s',%i,%i,%i,%i)) ",
|
| | constrType.c_str(),
|
| | previousCurve,
|
| | static_cast<int>(previousPosId),
|
| | lastCurve,
|
| | static_cast<int>(lastStartPosId)
|
| | );
|
| |
|
| | if (SnapMode == SNAP_MODE_45Degree && Mode != STATUS_Close) {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | double arcAngle = abs(
|
| | round((endAngle - startAngle) / (std::numbers::pi / 4)) * 45
|
| | );
|
| |
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Angle',%i,App.Units."
|
| | "Quantity('%f deg'))) ",
|
| | lastCurve,
|
| | arcAngle
|
| | );
|
| | }
|
| | if (Mode == STATUS_Close) {
|
| |
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Coincident',%i,%i,%i,%i)) ",
|
| | lastCurve,
|
| | static_cast<int>(lastEndPosId),
|
| | firstCurve,
|
| | static_cast<int>(firstPosId)
|
| | );
|
| | firstsegment = true;
|
| | }
|
| | Gui::Command::commitCommand();
|
| |
|
| | tryAutoRecomputeIfNotSolve(sketchgui->getObject<Sketcher::SketchObject>());
|
| | }
|
| |
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/Mod/Sketcher"
|
| | );
|
| | bool avoidredundant = sketchgui->AvoidRedundant.getValue()
|
| | && sketchgui->Autoconstraints.getValue();
|
| |
|
| | if (Mode == STATUS_Close) {
|
| |
|
| | if (avoidredundant) {
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | if (sugConstr1.size() > 0) {
|
| | removeRedundantHorizontalVertical(
|
| | sketchgui->getObject<Sketcher::SketchObject>(),
|
| | sugConstr1,
|
| | sugConstr2
|
| | );
|
| | }
|
| | else {
|
| | removeRedundantHorizontalVertical(
|
| | sketchgui->getObject<Sketcher::SketchObject>(),
|
| | virtualsugConstr1,
|
| | sugConstr2
|
| | );
|
| | }
|
| | }
|
| | }
|
| |
|
| | if (!sugConstr2.empty()) {
|
| |
|
| | std::vector<AutoConstraint> sugConstr;
|
| | for (unsigned int i = 0; i < sugConstr2.size(); i++) {
|
| | if (sugConstr2[i].Type != Sketcher::Coincident) {
|
| | sugConstr.push_back(sugConstr2[i]);
|
| | }
|
| | }
|
| | createAutoConstraints(sugConstr, getHighestCurveIndex(), Sketcher::PointPos::end);
|
| | sugConstr2.clear();
|
| | }
|
| |
|
| | tryAutoRecomputeIfNotSolve(sketchgui->getObject<Sketcher::SketchObject>());
|
| |
|
| | unsetCursor();
|
| |
|
| | resetPositionText();
|
| | EditCurve.clear();
|
| | drawEdit(EditCurve);
|
| |
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/Mod/Sketcher"
|
| | );
|
| | bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true);
|
| |
|
| | if (continuousMode) {
|
| |
|
| | Mode = STATUS_SEEK_First;
|
| | SegmentMode = SEGMENT_MODE_Line;
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | SnapMode = SNAP_MODE_Free;
|
| | suppressTransition = false;
|
| | firstCurve = -1;
|
| | previousCurve = -1;
|
| | firstPosId = Sketcher::PointPos::none;
|
| | previousPosId = Sketcher::PointPos::none;
|
| | EditCurve.clear();
|
| | drawEdit(EditCurve);
|
| | EditCurve.resize(2);
|
| | applyCursor();
|
| | |
| | |
| | |
| |
|
| | }
|
| | else {
|
| | sketchgui->purgeHandler();
|
| |
|
| | }
|
| | }
|
| | else {
|
| | Gui::Command::commitCommand();
|
| |
|
| |
|
| | if (!sugConstr1.empty()) {
|
| | createAutoConstraints(sugConstr1, getHighestCurveIndex(), Sketcher::PointPos::start);
|
| | sugConstr1.clear();
|
| | }
|
| |
|
| |
|
| | if (avoidredundant) {
|
| | if (SegmentMode == SEGMENT_MODE_Line) {
|
| | if (sugConstr1.size() > 0) {
|
| | removeRedundantHorizontalVertical(
|
| | sketchgui->getObject<Sketcher::SketchObject>(),
|
| | sugConstr1,
|
| | sugConstr2
|
| | );
|
| | }
|
| | else {
|
| | removeRedundantHorizontalVertical(
|
| | sketchgui->getObject<Sketcher::SketchObject>(),
|
| | virtualsugConstr1,
|
| | sugConstr2
|
| | );
|
| | }
|
| | }
|
| | }
|
| |
|
| | virtualsugConstr1 = sugConstr2;
|
| |
|
| |
|
| | if (!sugConstr2.empty()) {
|
| | createAutoConstraints(
|
| | sugConstr2,
|
| | getHighestCurveIndex(),
|
| | (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle)
|
| | ? Sketcher::PointPos::start
|
| | : Sketcher::PointPos::end
|
| | );
|
| | sugConstr2.clear();
|
| | }
|
| |
|
| | tryAutoRecomputeIfNotSolve(sketchgui->getObject<Sketcher::SketchObject>());
|
| |
|
| |
|
| | previousCurve = getHighestCurveIndex();
|
| | previousPosId = (SegmentMode == SEGMENT_MODE_Arc && startAngle > endAngle)
|
| | ? Sketcher::PointPos::start
|
| | : Sketcher::PointPos::end;
|
| |
|
| |
|
| |
|
| | updateTransitionData(previousCurve, previousPosId);
|
| |
|
| | applyCursor();
|
| | Mode = STATUS_SEEK_Second;
|
| | if (SegmentMode == SEGMENT_MODE_Arc) {
|
| | TransitionMode = TRANSITION_MODE_Tangent;
|
| | EditCurve.resize(3);
|
| | EditCurve[2] = EditCurve[0];
|
| | }
|
| | else {
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | EditCurve.resize(2);
|
| | }
|
| | SegmentMode = SEGMENT_MODE_Line;
|
| | SnapMode = SNAP_MODE_Free;
|
| | EditCurve[1] = EditCurve[0];
|
| | auto snapHandle = std::make_unique<SnapManager::SnapHandle>(nullptr, onSketchPos);
|
| | mouseMove(*snapHandle);
|
| | }
|
| | }
|
| |
|
| | updateHint();
|
| |
|
| | return true;
|
| | }
|
| |
|
| | void quit() override
|
| | {
|
| |
|
| |
|
| |
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/Mod/Sketcher"
|
| | );
|
| |
|
| | bool continuousMode = hGrp->GetBool("ContinuousCreationMode", true);
|
| |
|
| | if (firstsegment) {
|
| |
|
| | DrawSketchHandler::quit();
|
| | }
|
| | else {
|
| |
|
| | if (!continuousMode) {
|
| | DrawSketchHandler::quit();
|
| | }
|
| | else {
|
| |
|
| | Mode = STATUS_SEEK_First;
|
| | SegmentMode = SEGMENT_MODE_Line;
|
| | TransitionMode = TRANSITION_MODE_Free;
|
| | SnapMode = SNAP_MODE_Free;
|
| | suppressTransition = false;
|
| | firstCurve = -1;
|
| | previousCurve = -1;
|
| | firstPosId = Sketcher::PointPos::none;
|
| | previousPosId = Sketcher::PointPos::none;
|
| | firstsegment = true;
|
| | EditCurve.clear();
|
| | drawEdit(EditCurve);
|
| | EditCurve.resize(2);
|
| | applyCursor();
|
| | }
|
| | }
|
| | }
|
| |
|
| | private:
|
| | QString getCrosshairCursorSVGName() const override
|
| | {
|
| | return QStringLiteral("Sketcher_Pointer_Create_Lineset");
|
| | }
|
| |
|
| | std::list<Gui::InputHint> getToolHints() const override
|
| | {
|
| | using enum Gui::InputHint::UserInput;
|
| |
|
| |
|
| | return Gui::lookupHints<SELECT_MODE>(
|
| | Mode,
|
| | {
|
| | {.state = STATUS_SEEK_First,
|
| | .hints =
|
| | {
|
| | {tr("%1 pick first point"), {MouseLeft}},
|
| | }},
|
| | {.state = STATUS_SEEK_Second,
|
| | .hints =
|
| | {
|
| | {tr("%1 pick next point"), {MouseLeft}},
|
| | {tr("%1 finish"), {MouseRight}},
|
| | {tr("%1 switch mode"), {KeyM}},
|
| | }},
|
| | });
|
| |
|
| | }
|
| |
|
| | protected:
|
| | SELECT_MODE Mode;
|
| | SEGMENT_MODE SegmentMode;
|
| | TRANSITION_MODE TransitionMode;
|
| | SNAP_MODE SnapMode;
|
| | bool suppressTransition;
|
| |
|
| | std::vector<Base::Vector2d> EditCurve;
|
| | int firstCurve;
|
| | int previousCurve;
|
| | Sketcher::PointPos firstPosId;
|
| | Sketcher::PointPos previousPosId;
|
| |
|
| |
|
| | std::vector<AutoConstraint> sugConstr1, sugConstr2, virtualsugConstr1;
|
| |
|
| | Base::Vector2d CenterPoint;
|
| | Base::Vector3d dirVec;
|
| | double startAngle, endAngle, arcRadius;
|
| |
|
| | bool firstsegment;
|
| |
|
| | void updateTransitionData(int GeoId, Sketcher::PointPos PosId)
|
| | {
|
| |
|
| |
|
| | const Part::Geometry* geom = sketchgui->getSketchObject()->getGeometry(GeoId);
|
| | if (geom->is<Part::GeomLineSegment>()) {
|
| | const Part::GeomLineSegment* lineSeg = static_cast<const Part::GeomLineSegment*>(geom);
|
| | dirVec.Set(
|
| | lineSeg->getEndPoint().x - lineSeg->getStartPoint().x,
|
| | lineSeg->getEndPoint().y - lineSeg->getStartPoint().y,
|
| | 0.f
|
| | );
|
| | if (PosId == Sketcher::PointPos::start) {
|
| | dirVec *= -1;
|
| | EditCurve[0] = Base::Vector2d(lineSeg->getStartPoint().x, lineSeg->getStartPoint().y);
|
| | }
|
| | else {
|
| | EditCurve[0] = Base::Vector2d(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y);
|
| | }
|
| | }
|
| | else if (geom->is<Part::GeomArcOfCircle>()) {
|
| | const Part::GeomArcOfCircle* arcSeg = static_cast<const Part::GeomArcOfCircle*>(geom);
|
| | if (PosId == Sketcher::PointPos::start) {
|
| | EditCurve[0] = Base::Vector2d(
|
| | arcSeg->getStartPoint(true).x,
|
| | arcSeg->getStartPoint(true).y
|
| | );
|
| | dirVec = Base::Vector3d(0.f, 0.f, -1.0)
|
| | % (arcSeg->getStartPoint(true) - arcSeg->getCenter());
|
| | }
|
| | else {
|
| | EditCurve[0] = Base::Vector2d(
|
| | arcSeg->getEndPoint(true).x,
|
| | arcSeg->getEndPoint(true).y
|
| | );
|
| | dirVec = Base::Vector3d(0.f, 0.f, 1.0)
|
| | % (arcSeg->getEndPoint(true) - arcSeg->getCenter());
|
| | }
|
| | }
|
| | dirVec.Normalize();
|
| | }
|
| | };
|
| | }
|
| |
|
| |
|
| | #endif
|
| |
|