| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <cmath>
|
| |
|
| | #include <QGuiApplication>
|
| | #include <QPainter>
|
| |
|
| | #include <Inventor/events/SoKeyboardEvent.h>
|
| |
|
| | #include <Base/Console.h>
|
| | #include <Base/Exception.h>
|
| | #include <Gui/Application.h>
|
| | #include <Gui/BitmapFactory.h>
|
| | #include <Gui/CommandT.h>
|
| | #include <Gui/MainWindow.h>
|
| | #include <Gui/View3DInventor.h>
|
| | #include <Gui/View3DInventorViewer.h>
|
| | #include <Mod/Sketcher/App/SketchObject.h>
|
| |
|
| | #include "CommandConstraints.h"
|
| | #include "DrawSketchHandler.h"
|
| | #include "Utils.h"
|
| | #include "ViewProviderSketch.h"
|
| |
|
| |
|
| | using namespace SketcherGui;
|
| | using namespace Sketcher;
|
| |
|
| |
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::
|
| | setConstraintSelectability(ViewProviderSketch& vp, bool enabled )
|
| | {
|
| | vp.setConstraintSelectability(enabled);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::setPositionText(
|
| | ViewProviderSketch& vp,
|
| | const Base::Vector2d& Pos,
|
| | const SbString& txt
|
| | )
|
| | {
|
| | vp.setPositionText(Pos, txt);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::setPositionText(
|
| | ViewProviderSketch& vp,
|
| | const Base::Vector2d& Pos
|
| | )
|
| | {
|
| | vp.setPositionText(Pos);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::resetPositionText(ViewProviderSketch& vp)
|
| | {
|
| | vp.resetPositionText();
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::drawEdit(
|
| | ViewProviderSketch& vp,
|
| | const std::vector<Base::Vector2d>& EditCurve
|
| | )
|
| | {
|
| | vp.drawEdit(EditCurve);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::drawEdit(
|
| | ViewProviderSketch& vp,
|
| | const std::list<std::vector<Base::Vector2d>>& list
|
| | )
|
| | {
|
| | vp.drawEdit(list);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::drawEditMarkers(
|
| | ViewProviderSketch& vp,
|
| | const std::vector<Base::Vector2d>& EditMarkers,
|
| | unsigned int augmentationlevel
|
| | )
|
| | {
|
| | vp.drawEditMarkers(EditMarkers, augmentationlevel);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::setAxisPickStyle(ViewProviderSketch& vp, bool on)
|
| | {
|
| | vp.setAxisPickStyle(on);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::moveCursorToSketchPoint(
|
| | ViewProviderSketch& vp,
|
| | Base::Vector2d point
|
| | )
|
| | {
|
| | vp.moveCursorToSketchPoint(point);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::ensureFocus(ViewProviderSketch& vp)
|
| | {
|
| | vp.ensureFocus();
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::preselectAtPoint(
|
| | ViewProviderSketch& vp,
|
| | Base::Vector2d point
|
| | )
|
| | {
|
| | vp.preselectAtPoint(point);
|
| | }
|
| |
|
| | inline int ViewProviderSketchDrawSketchHandlerAttorney::getPreselectPoint(const ViewProviderSketch& vp)
|
| | {
|
| | return vp.getPreselectPoint();
|
| | }
|
| |
|
| | inline int ViewProviderSketchDrawSketchHandlerAttorney::getPreselectCurve(const ViewProviderSketch& vp)
|
| | {
|
| | return vp.getPreselectCurve();
|
| | }
|
| |
|
| | inline int ViewProviderSketchDrawSketchHandlerAttorney::getPreselectCross(const ViewProviderSketch& vp)
|
| | {
|
| | return vp.getPreselectCross();
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping(
|
| | ViewProviderSketch& vp,
|
| | bool enable,
|
| | Base::Vector2d referencePoint
|
| | )
|
| | {
|
| | vp.setAngleSnapping(enable, referencePoint);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::moveConstraint(
|
| | ViewProviderSketch& vp,
|
| | int constNum,
|
| | const Base::Vector2d& toPos,
|
| | OffsetMode offset
|
| | )
|
| | {
|
| | vp.moveConstraint(constNum, toPos, offset);
|
| | }
|
| |
|
| | inline void ViewProviderSketchDrawSketchHandlerAttorney::signalToolChanged(
|
| | const ViewProviderSketch& vp,
|
| | const std::string& toolname
|
| | )
|
| | {
|
| | vp.signalToolChanged(toolname);
|
| | }
|
| |
|
| |
|
| |
|
| | CurveConverter::CurveConverter()
|
| | {
|
| | try {
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/View"
|
| | );
|
| | hGrp->Attach(this);
|
| | }
|
| | catch (const Base::ValueError& e) {
|
| |
|
| | Base::Console().developerError("CurveConverter", "Malformed parameter string: %s\n", e.what());
|
| | }
|
| |
|
| | updateCurvedEdgeCountSegmentsParameter();
|
| | }
|
| |
|
| | CurveConverter::~CurveConverter()
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | }
|
| |
|
| | std::vector<Base::Vector2d> CurveConverter::toVector2D(const Part::Geometry* geometry)
|
| | {
|
| | std::vector<Base::Vector2d> vector2d;
|
| |
|
| | auto emplaceasvector2d = [&vector2d](const Base::Vector3d& point) {
|
| | vector2d.emplace_back(point.x, point.y);
|
| | };
|
| |
|
| | auto isperiodicconic = geometry->is<Part::GeomCircle>() || geometry->is<Part::GeomEllipse>();
|
| | auto isbounded = geometry->isDerivedFrom<Part::GeomBoundedCurve>();
|
| |
|
| | if (geometry->is<Part::GeomLineSegment>()) {
|
| | auto geo = static_cast<const Part::GeomLineSegment*>(geometry);
|
| |
|
| | emplaceasvector2d(geo->getStartPoint());
|
| | emplaceasvector2d(geo->getEndPoint());
|
| | }
|
| | else if (isperiodicconic || isbounded) {
|
| |
|
| | auto geo = static_cast<const Part::GeomConic*>(geometry);
|
| |
|
| | double segment = (geo->getLastParameter() - geo->getFirstParameter())
|
| | / curvedEdgeCountSegments;
|
| |
|
| | for (int i = 0; i < curvedEdgeCountSegments; i++) {
|
| | emplaceasvector2d(geo->value(geo->getFirstParameter() + i * segment));
|
| | }
|
| |
|
| |
|
| | emplaceasvector2d(isperiodicconic ? geo->value(0) : geo->value(geo->getLastParameter()));
|
| | }
|
| |
|
| | return vector2d;
|
| | }
|
| |
|
| | std::list<std::vector<Base::Vector2d>> CurveConverter::toVector2DList(
|
| | const std::vector<Part::Geometry*>& geometries
|
| | )
|
| | {
|
| | std::list<std::vector<Base::Vector2d>> list;
|
| |
|
| | for (const auto& geo : geometries) {
|
| | list.push_back(toVector2D(geo));
|
| | }
|
| |
|
| | return list;
|
| | }
|
| |
|
| | void CurveConverter::updateCurvedEdgeCountSegmentsParameter()
|
| | {
|
| | ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/View"
|
| | );
|
| | int stdcountsegments = hGrp->GetInt("SegmentsPerGeometry", 50);
|
| |
|
| |
|
| | if (stdcountsegments < 6) {
|
| | stdcountsegments = 6;
|
| | }
|
| |
|
| | curvedEdgeCountSegments = stdcountsegments;
|
| | };
|
| |
|
| |
|
| | void CurveConverter::OnChange(Base::Subject<const char*>& rCaller, const char* sReason)
|
| | {
|
| | (void)rCaller;
|
| |
|
| | if (strcmp(sReason, "SegmentsPerGeometry") == 0) {
|
| | updateCurvedEdgeCountSegmentsParameter();
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | DrawSketchHandler::DrawSketchHandler()
|
| | : Gui::ToolHandler()
|
| | , sketchgui(nullptr)
|
| | {}
|
| |
|
| | DrawSketchHandler::~DrawSketchHandler()
|
| | {}
|
| |
|
| | std::string DrawSketchHandler::getToolName() const
|
| | {
|
| | return "DSH_None";
|
| | }
|
| |
|
| | std::unique_ptr<QWidget> DrawSketchHandler::createWidget() const
|
| | {
|
| | return nullptr;
|
| | }
|
| |
|
| | bool DrawSketchHandler::isWidgetVisible() const
|
| | {
|
| | return false;
|
| | };
|
| |
|
| | QPixmap DrawSketchHandler::getToolIcon() const
|
| | {
|
| | return QPixmap();
|
| | }
|
| |
|
| | QString DrawSketchHandler::getToolWidgetText() const
|
| | {
|
| | return QString();
|
| | }
|
| |
|
| |
|
| | void DrawSketchHandler::activate(ViewProviderSketch* vp)
|
| | {
|
| | sketchgui = vp;
|
| |
|
| | if (!Gui::ToolHandler::activate()) {
|
| | sketchgui->purgeHandler();
|
| | }
|
| | }
|
| | void DrawSketchHandler::setSketchGui(ViewProviderSketch* vp)
|
| | {
|
| | sketchgui = vp;
|
| | }
|
| |
|
| | void DrawSketchHandler::deactivate()
|
| | {
|
| | Gui::ToolHandler::deactivate();
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setConstraintSelectability(*sketchgui, true);
|
| |
|
| |
|
| | clearEdit();
|
| | clearEditMarkers();
|
| | resetPositionText();
|
| | setAngleSnapping(false);
|
| |
|
| | ViewProviderSketchDrawSketchHandlerAttorney::signalToolChanged(*sketchgui, "DSH_None");
|
| | }
|
| |
|
| | void DrawSketchHandler::preActivated()
|
| | {
|
| | this->signalToolChanged();
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setConstraintSelectability(*sketchgui, false);
|
| | }
|
| |
|
| | void DrawSketchHandler::registerPressedKey(bool pressed, int key)
|
| | {
|
| |
|
| |
|
| | if (key == SoKeyboardEvent::ESCAPE && !pressed) {
|
| | quit();
|
| | }
|
| | }
|
| |
|
| | void DrawSketchHandler::pressRightButton(Base::Vector2d )
|
| | {
|
| |
|
| |
|
| | quit();
|
| | }
|
| |
|
| |
|
| | void DrawSketchHandler::quit()
|
| | {
|
| | assert(sketchgui);
|
| |
|
| | Gui::Selection().rmvSelectionGate();
|
| | Gui::Selection().rmvPreselect();
|
| |
|
| | sketchgui->purgeHandler();
|
| | }
|
| |
|
| | void DrawSketchHandler::toolWidgetChanged(QWidget* newwidget)
|
| | {
|
| | toolwidget = newwidget;
|
| | onWidgetChanged();
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | int DrawSketchHandler::getHighestVertexIndex()
|
| | {
|
| | return sketchgui->getSketchObject()->getHighestVertexIndex();
|
| | }
|
| |
|
| | int DrawSketchHandler::getHighestCurveIndex()
|
| | {
|
| | return sketchgui->getSketchObject()->getHighestCurveIndex();
|
| | }
|
| |
|
| | std::vector<QPixmap> DrawSketchHandler::suggestedConstraintsPixmaps(
|
| | std::vector<AutoConstraint>& suggestedConstraints
|
| | )
|
| | {
|
| | std::vector<QPixmap> pixmaps;
|
| |
|
| | for (auto& autoCstr : suggestedConstraints) {
|
| | QString iconType;
|
| | switch (autoCstr.Type) {
|
| | case Horizontal:
|
| | iconType = QStringLiteral("Constraint_Horizontal");
|
| | break;
|
| | case Vertical:
|
| | iconType = QStringLiteral("Constraint_Vertical");
|
| | break;
|
| | case Coincident:
|
| | iconType = QStringLiteral("Constraint_PointOnPoint");
|
| | break;
|
| | case PointOnObject:
|
| | iconType = QStringLiteral("Constraint_PointOnObject");
|
| | break;
|
| | case Symmetric:
|
| | iconType = QStringLiteral("Constraint_Symmetric");
|
| | break;
|
| | case Tangent:
|
| | iconType = QStringLiteral("Constraint_Tangent");
|
| | break;
|
| | default:
|
| | break;
|
| | }
|
| | if (!iconType.isEmpty()) {
|
| | constexpr int iconWidth = 16;
|
| | QPixmap icon = Gui::BitmapFactory().pixmapFromSvg(
|
| | iconType.toStdString().c_str(),
|
| | QSize(iconWidth, iconWidth)
|
| | );
|
| | pixmaps.push_back(icon);
|
| | }
|
| | }
|
| | return pixmaps;
|
| | }
|
| |
|
| | DrawSketchHandler::PreselectionData DrawSketchHandler::getPreselectionData()
|
| | {
|
| | SketchObject* obj = sketchgui->getSketchObject();
|
| |
|
| |
|
| | PreselectionData preSelData;
|
| | int preSelPnt = getPreselectPoint();
|
| | int preSelCrv = getPreselectCurve();
|
| | int preSelCrs = getPreselectCross();
|
| |
|
| | if (preSelPnt != -1) {
|
| | obj->getGeoVertexIndex(preSelPnt, preSelData.geoId, preSelData.posId);
|
| | }
|
| | else if (preSelCrv != -1) {
|
| | const Part::Geometry* geom = obj->getGeometry(preSelCrv);
|
| | if (geom) {
|
| | preSelData.geoId = preSelCrv;
|
| | if (geom->is<Part::GeomLineSegment>()) {
|
| | auto* line = static_cast<const Part::GeomLineSegment*>(geom);
|
| | preSelData.hitShapeDir = line->getEndPoint() - line->getStartPoint();
|
| | preSelData.isLine = true;
|
| | }
|
| | }
|
| | }
|
| | else if (preSelCrs == 0) {
|
| | preSelData.geoId = Sketcher::GeoEnum::RtPnt;
|
| | preSelData.posId = PointPos::start;
|
| | }
|
| | else if (preSelCrs == 1) {
|
| | preSelData.geoId = Sketcher::GeoEnum::HAxis;
|
| | preSelData.hitShapeDir = Base::Vector3d(1, 0, 0);
|
| | preSelData.isLine = true;
|
| | }
|
| | else if (preSelCrs == 2) {
|
| | preSelData.geoId = Sketcher::GeoEnum::VAxis;
|
| | preSelData.hitShapeDir = Base::Vector3d(0, 1, 0);
|
| | preSelData.isLine = true;
|
| | }
|
| | return preSelData;
|
| | }
|
| |
|
| | bool DrawSketchHandler::isLineCenterAutoConstraint(int GeoId, const Base::Vector2d& Pos) const
|
| | {
|
| | SketchObject* obj = sketchgui->getSketchObject();
|
| |
|
| | auto* geo = obj->getGeometry(GeoId);
|
| | if (geo->isDerivedFrom<Part::GeomLineSegment>()) {
|
| | auto* line = static_cast<const Part::GeomLineSegment*>(geo);
|
| |
|
| | Base::Vector2d startPoint = toVector2d(line->getStartPoint());
|
| | Base::Vector2d endPoint = toVector2d(line->getEndPoint());
|
| | Base::Vector2d midPoint = (startPoint + endPoint) / 2;
|
| |
|
| |
|
| | if ((Pos - midPoint).Length() < (endPoint - startPoint).Length() * 0.05) {
|
| | return true;
|
| | }
|
| | }
|
| | return false;
|
| | }
|
| |
|
| | void DrawSketchHandler::seekPreselectionAutoConstraint(
|
| | std::vector<AutoConstraint>& suggestedConstraints,
|
| | const Base::Vector2d& Pos,
|
| | const Base::Vector2d& Dir,
|
| | AutoConstraint::TargetType type
|
| | )
|
| | {
|
| | PreselectionData preSel = getPreselectionData();
|
| |
|
| | if (preSel.geoId != GeoEnum::GeoUndef) {
|
| |
|
| | AutoConstraint constr;
|
| | constr.Type = Sketcher::None;
|
| | constr.GeoId = preSel.geoId;
|
| | constr.PosId = preSel.posId;
|
| | if (type == AutoConstraint::VERTEX || type == AutoConstraint::VERTEX_NO_TANGENCY) {
|
| | if (preSel.posId == PointPos::none) {
|
| | bool lineCenter = isLineCenterAutoConstraint(preSel.geoId, Pos);
|
| | constr.Type = lineCenter ? Sketcher::Symmetric : Sketcher::PointOnObject;
|
| | }
|
| | else {
|
| | constr.Type = Sketcher::Coincident;
|
| | }
|
| | }
|
| | else if (type == AutoConstraint::CURVE && preSel.posId != PointPos::none) {
|
| | constr.Type = Sketcher::PointOnObject;
|
| | }
|
| | else if (type == AutoConstraint::CURVE && preSel.posId == PointPos::none) {
|
| | constr.Type = Sketcher::Tangent;
|
| | }
|
| |
|
| | if (constr.Type == Sketcher::Tangent && preSel.isLine) {
|
| | if (Dir.Length() < 1e-8 || preSel.hitShapeDir.Length() < 1e-8) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | Base::Vector3d dir3d = Base::Vector3d(Dir.x, Dir.y, 0);
|
| | double cosangle = dir3d.Normalize() * preSel.hitShapeDir.Normalize();
|
| |
|
| |
|
| | if (fabs(cosangle) > 0.995f) {
|
| | return;
|
| | }
|
| | }
|
| |
|
| | if (constr.Type != Sketcher::None) {
|
| | suggestedConstraints.push_back(constr);
|
| | }
|
| | }
|
| | }
|
| |
|
| | void DrawSketchHandler::seekAlignmentAutoConstraint(
|
| | std::vector<AutoConstraint>& suggestedConstraints,
|
| | const Base::Vector2d& Dir
|
| | )
|
| | {
|
| | using std::numbers::pi;
|
| | constexpr double angleDevRad = Base::toRadians<double>(2);
|
| |
|
| | AutoConstraint constr;
|
| | constr.Type = Sketcher::None;
|
| | constr.GeoId = GeoEnum::GeoUndef;
|
| | constr.PosId = PointPos::none;
|
| | double angle = std::abs(atan2(Dir.y, Dir.x));
|
| | if (angle < angleDevRad || (pi - angle) < angleDevRad) {
|
| |
|
| | constr.Type = Sketcher::Horizontal;
|
| | }
|
| | else if (std::abs(angle - pi / 2) < angleDevRad) {
|
| |
|
| | constr.Type = Sketcher::Vertical;
|
| | }
|
| |
|
| | if (constr.Type != Sketcher::None) {
|
| | suggestedConstraints.push_back(constr);
|
| | }
|
| | }
|
| |
|
| | void DrawSketchHandler::seekTangentAutoConstraint(
|
| | std::vector<AutoConstraint>& suggestedConstraints,
|
| | const Base::Vector2d& Pos,
|
| | const Base::Vector2d& Dir
|
| | )
|
| | {
|
| | using std::numbers::pi;
|
| | SketchObject* obj = sketchgui->getSketchObject();
|
| | int tangId = GeoEnum::GeoUndef;
|
| |
|
| |
|
| |
|
| | double tangDeviation = 0.1 * sketchgui->getScaleFactor();
|
| |
|
| |
|
| | const std::vector<Part::Geometry*> geomlist = obj->getCompleteGeometry();
|
| |
|
| | Base::Vector3d tmpPos(Pos.x, Pos.y, 0.f);
|
| | Base::Vector3d tmpDir(Dir.x, Dir.y, 0.f);
|
| | Base::Vector3d tmpStart(Pos.x - Dir.x, Pos.y - Dir.y, 0.f);
|
| |
|
| | int i = -1;
|
| | for (auto* geo : geomlist) {
|
| | i++;
|
| |
|
| | if (geo->is<Part::GeomCircle>()) {
|
| | auto* circle = static_cast<const Part::GeomCircle*>(geo);
|
| |
|
| | Base::Vector3d center = circle->getCenter();
|
| |
|
| | double radius = circle->getRadius();
|
| |
|
| |
|
| | if (tmpDir * (center - tmpPos) > 0 || tmpDir * (center - tmpStart) < 0) {
|
| | continue;
|
| | }
|
| |
|
| | Base::Vector3d projPnt(0.f, 0.f, 0.f);
|
| | projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir);
|
| | double projDist = std::abs(projPnt.Length() - radius);
|
| |
|
| |
|
| | if (projDist < tangDeviation) {
|
| | tangId = i;
|
| | tangDeviation = projDist;
|
| | }
|
| | }
|
| | else if (geo->is<Part::GeomEllipse>()) {
|
| | auto* ellipse = static_cast<const Part::GeomEllipse*>(geo);
|
| |
|
| | Base::Vector3d center = ellipse->getCenter();
|
| |
|
| | double a = ellipse->getMajorRadius();
|
| | double b = ellipse->getMinorRadius();
|
| | Base::Vector3d majdir = ellipse->getMajorAxisDir();
|
| |
|
| | double cf = sqrt(a * a - b * b);
|
| |
|
| | Base::Vector3d focus1P = center + cf * majdir;
|
| | Base::Vector3d focus2P = center - cf * majdir;
|
| |
|
| | Base::Vector3d norm = Base::Vector3d(Dir.y, -Dir.x).Normalize();
|
| |
|
| | double distancetoline = norm * (tmpPos - focus1P);
|
| |
|
| |
|
| | Base::Vector3d focus1PMirrored = focus1P + 2 * distancetoline * norm;
|
| |
|
| | double error = fabs((focus1PMirrored - focus2P).Length() - 2 * a);
|
| |
|
| | if (error < tangDeviation) {
|
| | tangId = i;
|
| | tangDeviation = error;
|
| | }
|
| | }
|
| | else if (geo->is<Part::GeomArcOfCircle>()) {
|
| | auto* arc = static_cast<const Part::GeomArcOfCircle*>(geo);
|
| |
|
| | Base::Vector3d center = arc->getCenter();
|
| | double radius = arc->getRadius();
|
| |
|
| |
|
| | if (tmpDir * (center - tmpPos) > 0 || tmpDir * (center - tmpStart) < 0) {
|
| | continue;
|
| | }
|
| |
|
| | Base::Vector3d projPnt(0.f, 0.f, 0.f);
|
| | projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir);
|
| | double projDist = std::abs(projPnt.Length() - radius);
|
| |
|
| | if (projDist < tangDeviation) {
|
| | double startAngle, endAngle;
|
| | arc->getRange(startAngle, endAngle, true);
|
| |
|
| | double angle = atan2(projPnt.y, projPnt.x);
|
| | while (angle < startAngle) {
|
| | angle += 2 * pi;
|
| | }
|
| |
|
| |
|
| | if (angle <= endAngle) {
|
| | tangId = i;
|
| | tangDeviation = projDist;
|
| | }
|
| | }
|
| | }
|
| | else if (geo->is<Part::GeomArcOfEllipse>()) {
|
| | auto* aoe = static_cast<const Part::GeomArcOfEllipse*>(geo);
|
| |
|
| | Base::Vector3d center = aoe->getCenter();
|
| |
|
| | double a = aoe->getMajorRadius();
|
| | double b = aoe->getMinorRadius();
|
| | Base::Vector3d majdir = aoe->getMajorAxisDir();
|
| |
|
| | double cf = sqrt(a * a - b * b);
|
| |
|
| | Base::Vector3d focus1P = center + cf * majdir;
|
| | Base::Vector3d focus2P = center - cf * majdir;
|
| |
|
| | Base::Vector3d norm = Base::Vector3d(Dir.y, -Dir.x).Normalize();
|
| |
|
| | double distancetoline = norm * (tmpPos - focus1P);
|
| |
|
| |
|
| | Base::Vector3d focus1PMirrored = focus1P + 2 * distancetoline * norm;
|
| |
|
| | double error = fabs((focus1PMirrored - focus2P).Length() - 2 * a);
|
| |
|
| | if (error < tangDeviation) {
|
| | double startAngle, endAngle;
|
| | aoe->getRange(startAngle, endAngle, true);
|
| |
|
| | double angle = Base::fmod(
|
| | atan2(
|
| | -aoe->getMajorRadius()
|
| | * ((tmpPos.x - center.x) * majdir.y - (tmpPos.y - center.y) * majdir.x),
|
| | aoe->getMinorRadius()
|
| | * ((tmpPos.x - center.x) * majdir.x + (tmpPos.y - center.y) * majdir.y)
|
| | ) - startAngle,
|
| | 2.f * pi
|
| | );
|
| |
|
| | while (angle < startAngle) {
|
| | angle += 2 * pi;
|
| | }
|
| |
|
| |
|
| | if (angle <= endAngle) {
|
| | tangId = i;
|
| | tangDeviation = error;
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | if (tangId != GeoEnum::GeoUndef) {
|
| | if (tangId > getHighestCurveIndex()) {
|
| | tangId = getHighestCurveIndex() - tangId;
|
| | }
|
| | AutoConstraint constr;
|
| | constr.Type = Tangent;
|
| | constr.GeoId = tangId;
|
| | constr.PosId = PointPos::none;
|
| | suggestedConstraints.push_back(constr);
|
| | }
|
| | }
|
| |
|
| | int DrawSketchHandler::seekAutoConstraint(
|
| | std::vector<AutoConstraint>& suggestedConstraints,
|
| | const Base::Vector2d& Pos,
|
| | const Base::Vector2d& Dir,
|
| | AutoConstraint::TargetType type
|
| | )
|
| | {
|
| | suggestedConstraints.clear();
|
| |
|
| | if (!sketchgui->Autoconstraints.getValue()) {
|
| | return 0;
|
| | }
|
| |
|
| | seekPreselectionAutoConstraint(suggestedConstraints, Pos, Dir, type);
|
| |
|
| | if (Dir.Length() > 1e-8 && type != AutoConstraint::CURVE) {
|
| | seekAlignmentAutoConstraint(suggestedConstraints, Dir);
|
| |
|
| | if (type != AutoConstraint::VERTEX_NO_TANGENCY) {
|
| | seekTangentAutoConstraint(suggestedConstraints, Pos, Dir);
|
| | }
|
| | }
|
| |
|
| | return suggestedConstraints.size();
|
| | }
|
| |
|
| | void DrawSketchHandler::createAutoConstraints(
|
| | const std::vector<AutoConstraint>& autoConstrs,
|
| | int geoId1,
|
| | Sketcher::PointPos posId1,
|
| | bool createowncommand
|
| | )
|
| | {
|
| | if (!sketchgui->Autoconstraints.getValue()) {
|
| | return;
|
| | }
|
| |
|
| | if (!autoConstrs.empty()) {
|
| |
|
| | if (createowncommand) {
|
| |
|
| | Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Auto-Constraints"));
|
| | }
|
| |
|
| |
|
| | for (auto& cstr : autoConstrs) {
|
| | int geoId2 = cstr.GeoId;
|
| |
|
| | switch (cstr.Type) {
|
| | case Sketcher::Coincident: {
|
| | if (posId1 == Sketcher::PointPos::none) {
|
| | continue;
|
| | }
|
| |
|
| |
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ",
|
| | geoId1,
|
| | static_cast<int>(posId1),
|
| | cstr.GeoId,
|
| | static_cast<int>(cstr.PosId)
|
| | );
|
| | } break;
|
| | case Sketcher::PointOnObject: {
|
| | Sketcher::PointPos posId2 = cstr.PosId;
|
| | if (posId1 == Sketcher::PointPos::none) {
|
| |
|
| | std::swap(geoId1, geoId2);
|
| | std::swap(posId1, posId2);
|
| | }
|
| |
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ",
|
| | geoId1,
|
| | static_cast<int>(posId1),
|
| | geoId2
|
| | );
|
| | } break;
|
| | case Sketcher::Symmetric: {
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Symmetric',%d,1,%d,2,%d,%d)) ",
|
| | geoId2,
|
| | geoId2,
|
| | geoId1,
|
| | static_cast<int>(posId1)
|
| | );
|
| | } break;
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | case Sketcher::Horizontal: {
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Horizontal',%d)) ",
|
| | geoId2 != GeoEnum::GeoUndef ? geoId2 : geoId1
|
| | );
|
| | } break;
|
| | case Sketcher::Vertical: {
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Vertical',%d)) ",
|
| | geoId2 != GeoEnum::GeoUndef ? geoId2 : geoId1
|
| | );
|
| | } break;
|
| | case Sketcher::Tangent: {
|
| | Sketcher::SketchObject* Obj = sketchgui->getSketchObject();
|
| |
|
| | const Part::Geometry* geom1 = Obj->getGeometry(geoId1);
|
| | const Part::Geometry* geom2 = Obj->getGeometry(cstr.GeoId);
|
| |
|
| |
|
| | if (geom1 && geom2
|
| | && (geom1->is<Part::GeomEllipse>() || geom2->is<Part::GeomEllipse>())) {
|
| |
|
| | if (!geom1->is<Part::GeomEllipse>()) {
|
| | std::swap(geoId1, geoId2);
|
| | }
|
| |
|
| |
|
| | geom1 = Obj->getGeometry(geoId1);
|
| | geom2 = Obj->getGeometry(geoId2);
|
| |
|
| | if (geom2->is<Part::GeomEllipse>() || geom2->is<Part::GeomArcOfEllipse>()
|
| | || geom2->is<Part::GeomCircle>() || geom2->is<Part::GeomArcOfCircle>()) {
|
| |
|
| | makeTangentToEllipseviaNewPoint(
|
| | Obj,
|
| | static_cast<const Part::GeomEllipse*>(geom1),
|
| | geom2,
|
| | geoId1,
|
| | geoId2
|
| | );
|
| | return;
|
| | }
|
| | }
|
| |
|
| |
|
| | if (geom1 && geom2
|
| | && (geom1->is<Part::GeomArcOfEllipse>()
|
| | || geom2->is<Part::GeomArcOfEllipse>())) {
|
| |
|
| | if (!geom1->is<Part::GeomArcOfEllipse>()) {
|
| | std::swap(geoId1, geoId2);
|
| | }
|
| |
|
| |
|
| | geom1 = Obj->getGeometry(geoId1);
|
| | geom2 = Obj->getGeometry(geoId2);
|
| |
|
| | if (geom2->is<Part::GeomArcOfEllipse>() || geom2->is<Part::GeomCircle>()
|
| | || geom2->is<Part::GeomArcOfCircle>()) {
|
| |
|
| | makeTangentToArcOfEllipseviaNewPoint(
|
| | Obj,
|
| | static_cast<const Part::GeomArcOfEllipse*>(geom1),
|
| | geom2,
|
| | geoId1,
|
| | geoId2
|
| | );
|
| | return;
|
| | }
|
| | }
|
| |
|
| | Gui::cmdAppObjectArgs(
|
| | sketchgui->getObject(),
|
| | "addConstraint(Sketcher.Constraint('Tangent',%d, %d)) ",
|
| | geoId1,
|
| | cstr.GeoId
|
| | );
|
| | } break;
|
| | default:
|
| | break;
|
| | }
|
| |
|
| | if (createowncommand) {
|
| | Gui::Command::commitCommand();
|
| | }
|
| |
|
| |
|
| | }
|
| | }
|
| | }
|
| |
|
| | int DrawSketchHandler::seekAndRenderAutoConstraint(
|
| | std::vector<AutoConstraint>& suggestedConstraints,
|
| | const Base::Vector2d& Pos,
|
| | const Base::Vector2d& Dir,
|
| | AutoConstraint::TargetType type
|
| | )
|
| | {
|
| | if (seekAutoConstraint(suggestedConstraints, Pos, Dir, type)) {
|
| | renderSuggestConstraintsCursor(suggestedConstraints);
|
| | }
|
| | else {
|
| | applyCursor();
|
| | }
|
| |
|
| | return suggestedConstraints.size();
|
| | }
|
| |
|
| | void DrawSketchHandler::renderSuggestConstraintsCursor(std::vector<AutoConstraint>& suggestedConstraints)
|
| | {
|
| | std::vector<QPixmap> pixmaps = suggestedConstraintsPixmaps(suggestedConstraints);
|
| | addCursorTail(pixmaps);
|
| | }
|
| |
|
| | void DrawSketchHandler::setPositionText(const Base::Vector2d& Pos, const SbString& text)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setPositionText(*sketchgui, Pos, text);
|
| | }
|
| |
|
| |
|
| | void DrawSketchHandler::setPositionText(const Base::Vector2d& Pos)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setPositionText(*sketchgui, Pos);
|
| | }
|
| |
|
| | void DrawSketchHandler::resetPositionText()
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::resetPositionText(*sketchgui);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawEdit(const std::vector<Base::Vector2d>& EditCurve) const
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::drawEdit(*sketchgui, EditCurve);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawEdit(const std::list<std::vector<Base::Vector2d>>& list) const
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::drawEdit(*sketchgui, list);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawEdit(const std::vector<Part::Geometry*>& geometries) const
|
| | {
|
| | static CurveConverter c;
|
| |
|
| | auto list = c.toVector2DList(geometries);
|
| |
|
| | drawEdit(list);
|
| | }
|
| |
|
| | void DrawSketchHandler::clearEdit() const
|
| | {
|
| | drawEdit(std::vector<Base::Vector2d>());
|
| | }
|
| |
|
| | void DrawSketchHandler::clearEditMarkers() const
|
| | {
|
| | drawEditMarkers(std::vector<Base::Vector2d>());
|
| | }
|
| |
|
| | void DrawSketchHandler::drawPositionAtCursor(const Base::Vector2d& position)
|
| | {
|
| | setPositionText(position);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawDirectionAtCursor(const Base::Vector2d& position, const Base::Vector2d& origin)
|
| | {
|
| | if (!showCursorCoords()) {
|
| | return;
|
| | }
|
| |
|
| | float length = (position - origin).Length();
|
| | float angle = (position - origin).GetAngle(Base::Vector2d(1.f, 0.f));
|
| |
|
| | SbString text;
|
| | std::string lengthString = lengthToDisplayFormat(length, 1);
|
| | std::string angleString = angleToDisplayFormat(angle * 180.0 / std::numbers::pi, 1);
|
| | text.sprintf(" (%s, %s)", lengthString.c_str(), angleString.c_str());
|
| | setPositionText(position, text);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawWidthHeightAtCursor(
|
| | const Base::Vector2d& position,
|
| | const double val1,
|
| | const double val2
|
| | )
|
| | {
|
| | if (!showCursorCoords()) {
|
| | return;
|
| | }
|
| |
|
| | SbString text;
|
| | std::string val1String = lengthToDisplayFormat(val1, 1);
|
| | std::string val2String = lengthToDisplayFormat(val2, 1);
|
| | text.sprintf(" (%s x %s)", val1String.c_str(), val2String.c_str());
|
| | setPositionText(position, text);
|
| | }
|
| |
|
| | void DrawSketchHandler::drawDoubleAtCursor(const Base::Vector2d& position, const double val, Base::Unit unit)
|
| | {
|
| | if (!showCursorCoords()) {
|
| | return;
|
| | }
|
| |
|
| | SbString text;
|
| | std::string doubleString = unit == Base::Unit::Length
|
| | ? lengthToDisplayFormat(val, 1)
|
| | : angleToDisplayFormat(Base::toDegrees(val), 1);
|
| | text.sprintf(" (%s)", doubleString.c_str());
|
| | setPositionText(position, text);
|
| | }
|
| |
|
| | std::unique_ptr<QWidget> DrawSketchHandler::createToolWidget() const
|
| | {
|
| | return createWidget();
|
| | }
|
| |
|
| | bool DrawSketchHandler::isToolWidgetVisible() const
|
| | {
|
| | return isWidgetVisible();
|
| | }
|
| |
|
| | QPixmap DrawSketchHandler::getToolWidgetHeaderIcon() const
|
| | {
|
| | return getToolIcon();
|
| | }
|
| |
|
| | QString DrawSketchHandler::getToolWidgetHeaderText() const
|
| | {
|
| | return getToolWidgetText();
|
| | }
|
| |
|
| | void DrawSketchHandler::drawEditMarkers(
|
| | const std::vector<Base::Vector2d>& EditMarkers,
|
| | unsigned int augmentationlevel
|
| | ) const
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::drawEditMarkers(
|
| | *sketchgui,
|
| | EditMarkers,
|
| | augmentationlevel
|
| | );
|
| | }
|
| |
|
| | void DrawSketchHandler::setAxisPickStyle(bool on)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setAxisPickStyle(*sketchgui, on);
|
| | }
|
| |
|
| | void DrawSketchHandler::moveCursorToSketchPoint(Base::Vector2d point)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::moveCursorToSketchPoint(*sketchgui, point);
|
| | }
|
| |
|
| | void DrawSketchHandler::ensureFocus()
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::ensureFocus(*sketchgui);
|
| | }
|
| |
|
| | void DrawSketchHandler::preselectAtPoint(Base::Vector2d point)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::preselectAtPoint(*sketchgui, point);
|
| | }
|
| |
|
| | int DrawSketchHandler::getPreselectPoint() const
|
| | {
|
| | return ViewProviderSketchDrawSketchHandlerAttorney::getPreselectPoint(*sketchgui);
|
| | }
|
| |
|
| | int DrawSketchHandler::getPreselectCurve() const
|
| | {
|
| | return ViewProviderSketchDrawSketchHandlerAttorney::getPreselectCurve(*sketchgui);
|
| | }
|
| |
|
| | int DrawSketchHandler::getPreselectCross() const
|
| | {
|
| | return ViewProviderSketchDrawSketchHandlerAttorney::getPreselectCross(*sketchgui);
|
| | }
|
| |
|
| | Sketcher::SketchObject* DrawSketchHandler::getSketchObject()
|
| | {
|
| | return sketchgui->getSketchObject();
|
| | }
|
| |
|
| | void DrawSketchHandler::setAngleSnapping(bool enable, Base::Vector2d referencePoint)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::setAngleSnapping(*sketchgui, enable, referencePoint);
|
| | }
|
| |
|
| | void DrawSketchHandler::moveConstraint(int constNum, const Base::Vector2d& toPos, OffsetMode offset)
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::moveConstraint(*sketchgui, constNum, toPos, offset);
|
| | }
|
| |
|
| | void DrawSketchHandler::signalToolChanged() const
|
| | {
|
| | ViewProviderSketchDrawSketchHandlerAttorney::signalToolChanged(*sketchgui, this->getToolName());
|
| | }
|
| |
|