From 9f0ae2109580ad4e259a3820010e2b9d4bd92782 Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Mon, 21 Oct 2024 08:19:00 +0300 Subject: [PATCH] Expose `Geometry2D.bresenham_line()` method Co-authored-by: Hugo Locurcio --- core/core_bind.cpp | 15 +++++++++++++++ core/core_bind.h | 2 ++ core/math/geometry_2d.h | 12 ++++++------ doc/classes/Geometry2D.xml | 14 ++++++++++++++ doc/classes/InputEventMouseMotion.xml | 2 +- 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 891e3a28c9e..095c6c44dda 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -920,6 +920,19 @@ Dictionary Geometry2D::make_atlas(const Vector &p_rects) { return ret; } +TypedArray Geometry2D::bresenham_line(const Point2i &p_from, const Point2i &p_to) { + Vector points = ::Geometry2D::bresenham_line(p_from, p_to); + + TypedArray result; + result.resize(points.size()); + + for (int i = 0; i < points.size(); i++) { + result[i] = points[i]; + } + + return result; +} + void Geometry2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &Geometry2D::is_point_in_circle); ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &Geometry2D::segment_intersects_circle); @@ -954,6 +967,8 @@ void Geometry2D::_bind_methods() { ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &Geometry2D::make_atlas); + ClassDB::bind_method(D_METHOD("bresenham_line", "from", "to"), &Geometry2D::bresenham_line); + BIND_ENUM_CONSTANT(OPERATION_UNION); BIND_ENUM_CONSTANT(OPERATION_DIFFERENCE); BIND_ENUM_CONSTANT(OPERATION_INTERSECTION); diff --git a/core/core_bind.h b/core/core_bind.h index d59a2c55f1e..b6903765518 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -324,6 +324,8 @@ public: Dictionary make_atlas(const Vector &p_rects); + TypedArray bresenham_line(const Point2i &p_from, const Point2i &p_to); + Geometry2D() { singleton = this; } }; diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index 83ebdc5a847..abd395d8dfb 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -451,17 +451,17 @@ public: return H; } - static Vector bresenham_line(const Point2i &p_start, const Point2i &p_end) { + static Vector bresenham_line(const Point2i &p_from, const Point2i &p_to) { Vector points; - Vector2i delta = (p_end - p_start).abs() * 2; - Vector2i step = (p_end - p_start).sign(); - Vector2i current = p_start; + Vector2i delta = (p_to - p_from).abs() * 2; + Vector2i step = (p_to - p_from).sign(); + Vector2i current = p_from; if (delta.x > delta.y) { int err = delta.x / 2; - for (; current.x != p_end.x; current.x += step.x) { + for (; current.x != p_to.x; current.x += step.x) { points.push_back(current); err -= delta.y; @@ -473,7 +473,7 @@ public: } else { int err = delta.y / 2; - for (; current.y != p_end.y; current.y += step.y) { + for (; current.y != p_to.y; current.y += step.y) { points.push_back(current); err -= delta.x; diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml index 2dd76ad989b..71e6cf93ae2 100644 --- a/doc/classes/Geometry2D.xml +++ b/doc/classes/Geometry2D.xml @@ -9,6 +9,20 @@ + + + + + + Returns the [url=https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm]Bresenham line[/url] between the [param from] and [param to] points. A Bresenham line is a series of pixels that draws a line and is always 1-pixel thick on every row and column of the drawing (never more, never less). + Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls: + [codeblock] + func _draw(): + for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position): + draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE) + [/codeblock] + + diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml index bcfe5b70fd9..4c1461d03a5 100644 --- a/doc/classes/InputEventMouseMotion.xml +++ b/doc/classes/InputEventMouseMotion.xml @@ -5,7 +5,7 @@ Stores information about a mouse or a pen motion. This includes relative position, absolute position, and velocity. See [method Node._input]. - [b]Note:[/b] By default, this event is only emitted once per frame rendered at most. If you need more precise input reporting, set [member Input.use_accumulated_input] to [code]false[/code] to make events emitted as often as possible. If you use InputEventMouseMotion to draw lines, consider implementing [url=https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm]Bresenham's line algorithm[/url] as well to avoid visible gaps in lines if the user is moving the mouse quickly. + [b]Note:[/b] By default, this event is only emitted once per frame rendered at most. If you need more precise input reporting, set [member Input.use_accumulated_input] to [code]false[/code] to make events emitted as often as possible. If you use InputEventMouseMotion to draw lines, consider using [method Geometry2D.bresenham_line] as well to avoid visible gaps in lines if the user is moving the mouse quickly. [b]Note:[/b] This event may be emitted even when the mouse hasn't moved, either by the operating system or by Godot itself. If you really need to know if the mouse has moved (e.g. to suppress displaying a tooltip), you should check that [code]relative.is_zero_approx()[/code] is [code]false[/code].