diff --git a/src/core/control/CompassController.cpp b/src/core/control/CompassController.cpp index 1965c70fc69e..41e2b7cdeecc 100644 --- a/src/core/control/CompassController.cpp +++ b/src/core/control/CompassController.cpp @@ -22,7 +22,7 @@ auto CompassController::posRelToSide(double x, double y) const -> utl::Point bool { - const auto p = posRelToSide(x, y); + const utl::Point p = posRelToSide(x, y); return std::hypot(p.x, p.y) <= geometryTool->getHeight() + border; } @@ -35,12 +35,21 @@ auto CompassController::getPointForAngle(double a) const -> utl::Point { return utl::Point(x, y); } +auto CompassController::getPointForRadius(double r) const -> utl::Point { + cairo_matrix_t matrix = geometryTool->getMatrix(); + double x = r; + double y = 0.; + cairo_matrix_transform_point(&matrix, &x, &y); + + return utl::Point(x, y); +} + void CompassController::createOutlineStroke(double a) { if (!std::isnan(a)) { angleMax = a; angleMin = a; - const auto p = this->getPointForAngle(a); + const utl::Point p = this->getPointForAngle(a); initializeStroke(); stroke->addPoint(Point(p.x, p.y)); stroke->addPoint(Point(p.x, p.y)); // doubled point @@ -50,6 +59,21 @@ void CompassController::createOutlineStroke(double a) { } } +void CompassController::createRadialStroke(double x) { + if (!std::isnan(x)) { + radiusMax = x; + radiusMin = x; + + const utl::Point p = posRelToSide(x, 0.); + initializeStroke(); + stroke->addPoint(Point(p.x, p.y)); + stroke->addPoint(Point(p.x, p.y)); // doubled point + geometryTool->notify(); + } else { + g_warning("No valid radius from compass!"); + } +} + void CompassController::updateOutlineStroke(double x) { angleMax = std::max(this->angleMax, x); angleMin = std::min(this->angleMin, x); @@ -72,10 +96,30 @@ void CompassController::updateOutlineStroke(double x) { geometryTool->notify(); } +void CompassController::updateRadialStroke(double x) { + radiusMax = std::max(this->radiusMax, x); + radiusMin = std::min(this->radiusMin, x); + stroke->deletePointsFrom(0); + const utl::Point p1 = getPointForRadius(radiusMin); + const utl::Point p2 = getPointForRadius(radiusMax); + + stroke->addPoint(Point(p1.x, p1.y)); + stroke->addPoint(Point(p2.x, p2.y)); + geometryTool->notify(); +} + void CompassController::finalizeOutlineStroke() { angleMax = std::numeric_limits::lowest(); angleMin = std::numeric_limits::max(); addStrokeToLayer(); } +void CompassController::finalizeRadialStroke() { + radiusMax = std::numeric_limits::lowest(); + radiusMin = std::numeric_limits::max(); + addStrokeToLayer(); +} + auto CompassController::existsOutlineStroke() -> bool { return angleMax != std::numeric_limits::lowest(); } + +auto CompassController::existsRadialStroke() -> bool { return radiusMax != std::numeric_limits::lowest(); } diff --git a/src/core/control/CompassController.h b/src/core/control/CompassController.h index d45467bcd1f5..6fb7e9ddc2fe 100644 --- a/src/core/control/CompassController.h +++ b/src/core/control/CompassController.h @@ -59,10 +59,17 @@ class CompassController: public GeometryToolController { bool isInsideGeometryTool(double x, double y, double border = 0.0) const override; /** - * @brief the point (in document coordinates) for a given angle on the outline of the setsquare + * @brief the point (in document coordinates) for a given angle on the outline of the compass * @param a the angle with respect to the distinguished compass axis of the point */ - utl::Point getPointForPos(double a) const; + utl::Point getPointForAngle(double a) const; + + /** + * @brief the point (in document coordinates) for a given radius on the marked radius of the compass + * @param r the x-coordinate with respect to a coordinate system, in which the positive x-axis + * coincides with the marked radius and the origin lies in the center of the compass + */ + utl::Point getPointForRadius(double r) const; /** * @brief creates a stroke starting at the given angle of the outline of the compass @@ -82,12 +89,43 @@ class CompassController: public GeometryToolController { */ void finalizeOutlineStroke(); + /** + * @brief finishes the stroke aligned to the marked radius of the compass + */ + void finalizeRadialStroke(); + + /** + * @brief creates a stroke starting at the given point of the marked radius of the compass + * @param x the x-coordinate with respect to the marked radius + */ + void createRadialStroke(double x); + + /** + * @brief updates the stroke near the marked radius of the compass + * @param x the x-coordinate with respect to the marked radius + */ + void updateRadialStroke(double x); + /** * checks whether a stroke near the outline already exists */ bool existsOutlineStroke(); + /** + * checks whether a radius already exists + */ + bool existsRadialStroke(); + private: + /** + * @brief when a stroke near the radius with the measuring marks + * is drawn, the minimal and maximal radii are saved in + * the variables radiusMax and radiusMin + * + */ + double radiusMax = std::numeric_limits::lowest(); + double radiusMin = std::numeric_limits::max(); + /** * @brief when a stroke near the outline of the compass is drawn, the minimal and maximal * angles of the point to be drawn (with respect to an unrotated, and untranslated coordinate system) diff --git a/src/core/gui/inputdevices/CompassInputHandler.cpp b/src/core/gui/inputdevices/CompassInputHandler.cpp index 81d83f03e69e..946af380a80a 100644 --- a/src/core/gui/inputdevices/CompassInputHandler.cpp +++ b/src/core/gui/inputdevices/CompassInputHandler.cpp @@ -22,6 +22,7 @@ CompassInputHandler::~CompassInputHandler() noexcept { this->unregisterFromPool( auto CompassInputHandler::handlePointer(InputEvent const& event) -> bool { const auto coords = getCoords(event); CompassController* compassController = static_cast(controller); + const auto p = compassController->posRelToSide(coords.x, coords.y); const auto toolHandler = xournal->getControl()->getToolHandler(); switch (toolHandler->getToolType()) { @@ -31,21 +32,27 @@ auto CompassInputHandler::handlePointer(InputEvent const& event) -> bool { if (controller->isInsideGeometryTool(coords.x, coords.y, 0) && !controller->isInsideGeometryTool(coords.x, coords.y, -0.5)) { // initialize range - const auto p = compassController->posRelToSide(coords.x, coords.y); lastProj = std::atan2(-p.y, p.x); compassController->createOutlineStroke(lastProj); return true; + } else if (controller->isInsideGeometryTool(coords.x, coords.y, 0.) && + std::abs(compassController->posRelToSide(coords.x, coords.y).y) <= 0.5 && + std::abs(compassController->posRelToSide(coords.x, coords.y).x - 0.5 * height) <= + 0.5 * height) { + compassController->createRadialStroke(std::hypot(p.x, p.y)); + return true; } return false; } else if (event.type == MOTION_EVENT) { // update range and paint if (compassController->existsOutlineStroke()) { - const auto p = compassController->posRelToSide(coords.x, coords.y); auto proj = std::atan2(-p.y, p.x); proj = lastProj + std::remainder(proj - lastProj, 2 * M_PI); compassController->updateOutlineStroke(proj); lastProj = proj; return true; + } else if (compassController->existsRadialStroke()) { + compassController->updateRadialStroke(std::hypot(p.x, p.y)); } return false; } else if (event.type == BUTTON_RELEASE_EVENT) { @@ -54,6 +61,9 @@ auto CompassInputHandler::handlePointer(InputEvent const& event) -> bool { compassController->finalizeOutlineStroke(); lastProj = NAN; return true; + } else if (compassController->existsRadialStroke()) { + compassController->finalizeRadialStroke(); + return true; } } return false;