From 18fc89f0bb88ccfca56354cd7759cc588fb8c999 Mon Sep 17 00:00:00 2001 From: fiecueal Date: Mon, 21 Oct 2024 21:19:48 +0800 Subject: [PATCH 1/5] fix Geometry.intersect_circle? when one or both circles increase to some size, the method returns true even when no intersection is occuring; removes unused resolved_circle_(one|two) vars; properly handles anchor_(x|y); removes necessity for anchor_(x|y) on args without radius; uses the center points of the circles in distance_squared; adds error message; --- dragon/geometry.rb | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/dragon/geometry.rb b/dragon/geometry.rb index b37469b9..dca1962d 100644 --- a/dragon/geometry.rb +++ b/dragon/geometry.rb @@ -785,14 +785,46 @@ def circle? shape end def intersect_circle? circle_one, circle_two - resolved_circle_one = rect_to_circle circle_one - resolved_circle_two = rect_to_circle circle_two - distance_squared(circle_one, circle_two) <= (circle_one.radius + circle_two.radius)**2 + circle_one_radius = circle_one.radius if circle_one.respond_to? :radius + circle_one_radius ||= if circle_one.w <= circle_one.h + circle_one.w / 2 + else + circle_one.h / 2 + end + circle_two_radius = circle_two.radius if circle_two.respond_to? :radius + circle_two_radius ||= if circle_two.w <= circle_one.h + circle_two.w / 2 + else + circle_two.h / 2 + end + + circle_one_center = { x: circle_one.x + circle_one_radius, + y: circle_one.y + circle_one_radius } + circle_two_center = { x: circle_two.x + circle_two_radius, + y: circle_two.y + circle_two_radius } + + if circle_one.respond_to?(:anchor_x) && circle_one.anchor_x + circle_one_center.x -= circle_one.anchor_x * circle_one_radius * 2 + end + if circle_one.respond_to?(:anchor_y) && circle_one.anchor_y + circle_one_center.y -= circle_one.anchor_y * circle_one_radius * 2 + end + if circle_two.respond_to?(:anchor_x) && circle_two.anchor_x + circle_two_center.x -= circle_two.anchor_x * circle_two_radius * 2 + end + if circle_two.respond_to?(:anchor_y) && circle_two.anchor_y + circle_two_center.y -= circle_two.anchor_y * circle_two_radius * 2 + end + + distance_squared(circle_one_center, circle_two_center) <= (circle_one_radius + circle_two_radius)**2 rescue Exception => e raise e, <<-S * ERROR: Geometry::intersect_circle? for circle_one #{circle_one} and circle_two #{circle_two}. #{e} +Make sure the parameters adhere to one of the following: +- A ~Hash~ with ~x~, ~y~, and ~radius~ (or an object that responds to ~x~, ~y~, and ~radius~). +- A ~Hash~ with ~x~, ~y~, ~w~, and ~h~ (or an object that responds to ~x~, ~y~, ~w~, and ~h~). S end From 68c0b826824b0f74f50ee1bcc10ea3114dfdf491 Mon Sep 17 00:00:00 2001 From: fiecueal Date: Mon, 21 Oct 2024 21:22:21 +0800 Subject: [PATCH 2/5] remove unused methods --- dragon/geometry.rb | 60 ---------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/dragon/geometry.rb b/dragon/geometry.rb index dca1962d..16e1177b 100644 --- a/dragon/geometry.rb +++ b/dragon/geometry.rb @@ -724,66 +724,6 @@ def line_normal line, point S end - def rect_to_circle rect - if circle? rect - rect - elsif rect? rect - x = rect.x - y = rect.y - anchor_shift_x = 0.5 - (rect.anchor_x || 0) - anchor_shift_y = 0.5 - (rect.anchor_y || 0) - x += rect.w * anchor_shift_x - y += rect.h * anchor_shift_y - radius = if rect.w <= rect.h - rect.w / 2 - else - rect.h / 2 - end - { x: x, y: y, radius: radius } - else - raise <<-S -Parameter provided returned false for both Geometry::circle? and Geometry::rect?. -S - end - rescue Exception => e - raise e, <<-S -* ERROR: -Geometry::rect_to_circle for rect #{rect}. -#{e} -Make sure the parameter adheres to one of the following: -- A ~Hash~ with ~x~, ~y~, and ~radius~ (or an object that responds to ~x~, ~y~, and ~radius~). -- A ~Hash~ with ~x~, ~y~, ~w~, ~h~, ~anchor_x~, and ~anchor_y~ (or an object that responds to ~x~, ~y~, ~w~, ~h~, ~anchor_x~, and ~anchor_y~). - If the parameter is a ~Hash~, ~anchor_x~ and ~anchor_y~ are optional and default to ~0~. -S - end - - def rect? shape - if shape.is_a? Hash - shape.w && shape.h - else - shape.respond_to?(:x) && - shape.respond_to?(:y) && - shape.respond_to?(:w) && - shape.respond_to?(:h) && - shape.respond_to?(:anchor_x) && - shape.respond_to?(:anchor_y) - end - rescue Exception => e - raise e, <<-S -* ERROR: -Geometry::rect? for shape #{shape}. -#{e} -S - end - - def circle? shape - if shape.is_a?(Hash) - !!shape.radius - else - shape.respond_to?(:radius) - end - end - def intersect_circle? circle_one, circle_two circle_one_radius = circle_one.radius if circle_one.respond_to? :radius circle_one_radius ||= if circle_one.w <= circle_one.h From d3ca91e7c26cce73a9200218d6ee54fcd99c949c Mon Sep 17 00:00:00 2001 From: fiecueal Date: Tue, 22 Oct 2024 08:26:13 +0800 Subject: [PATCH 3/5] re-add Geometry.rect_to_circle I didn't notice it was in the docs and removed it preemptively; re-implemented to work more closely to the docs descriptions; removes necessity for anchor_(x|y) on args without a radius; allows anchor_(x|y) to work on args with a radius; original implementation returns {x:, y:, radius:} but the docs implies that what is returned is a rect, re-implementation returns {x:, y:, w:, h:, radius:} for the best of both worlds --- dragon/geometry.rb | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/dragon/geometry.rb b/dragon/geometry.rb index 16e1177b..bfd669c7 100644 --- a/dragon/geometry.rb +++ b/dragon/geometry.rb @@ -724,6 +724,68 @@ def line_normal line, point S end + def rect_to_circle rect + x = y = w = h = radius = nil + + if circle? rect + radius = rect.radius + w = h = radius * 2 + elsif rect? rect + w = rect.w + h = rect.h + radius = if w <= h + w / 2 + else + h / 2 + end + else + raise <<-S +Parameter provided returned false for both Geometry::circle? and Geometry::rect?. +S + end + + x = rect.x + y = rect.y + x -= rect.anchor_x * w if rect.respond_to?(:anchor_x) && rect.anchor_x + y -= rect.anchor_y * h if rect.respond_to?(:anchor_y) && rect.anchor_y + + { x: x, y: y, w: w, h: h, radius: radius } + rescue Exception => e + raise e, <<-S +* ERROR: +Geometry::rect_to_circle for rect #{rect}. +#{e} +Make sure the parameter adheres to one of the following: +- A ~Hash~ with ~x~, ~y~, and ~radius~ (or an object that responds to ~x~, ~y~, and ~radius~). +- A ~Hash~ with ~x~, ~y~, ~w~, and ~h~ (or an object that responds to ~x~, ~y~, ~w~, and ~h~). +S + end + + def rect? shape + shape.respond_to?(:x) && + shape.respond_to?(:y) && + shape.respond_to?(:w) && + shape.respond_to?(:h) + rescue Exception => e + raise e, <<-S +* ERROR: +Geometry::rect? for shape #{shape}. +#{e} +S + end + + def circle? shape + shape.respond_to?(:x) && + shape.respond_to?(:y) && + shape.respond_to?(:radius) + rescue Exception => e + raise e, <<-S +* ERROR: +Geometry::circle? for shape #{shape}. +#{e} +S + end + def intersect_circle? circle_one, circle_two circle_one_radius = circle_one.radius if circle_one.respond_to? :radius circle_one_radius ||= if circle_one.w <= circle_one.h From 9217049f3a6b8f08554f9240cb899ffb3c72d8b2 Mon Sep 17 00:00:00 2001 From: fiecueal Date: Tue, 22 Oct 2024 09:12:59 +0800 Subject: [PATCH 4/5] update Geometry.intersect_circle? utilize Geometry.rect_to_circle now that it works as intended --- dragon/geometry.rb | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/dragon/geometry.rb b/dragon/geometry.rb index bfd669c7..fb605660 100644 --- a/dragon/geometry.rb +++ b/dragon/geometry.rb @@ -787,38 +787,15 @@ def circle? shape end def intersect_circle? circle_one, circle_two - circle_one_radius = circle_one.radius if circle_one.respond_to? :radius - circle_one_radius ||= if circle_one.w <= circle_one.h - circle_one.w / 2 - else - circle_one.h / 2 - end - circle_two_radius = circle_two.radius if circle_two.respond_to? :radius - circle_two_radius ||= if circle_two.w <= circle_one.h - circle_two.w / 2 - else - circle_two.h / 2 - end + resolved_circle_one = rect_to_circle circle_one + resolved_circle_two = rect_to_circle circle_two - circle_one_center = { x: circle_one.x + circle_one_radius, - y: circle_one.y + circle_one_radius } - circle_two_center = { x: circle_two.x + circle_two_radius, - y: circle_two.y + circle_two_radius } - - if circle_one.respond_to?(:anchor_x) && circle_one.anchor_x - circle_one_center.x -= circle_one.anchor_x * circle_one_radius * 2 - end - if circle_one.respond_to?(:anchor_y) && circle_one.anchor_y - circle_one_center.y -= circle_one.anchor_y * circle_one_radius * 2 - end - if circle_two.respond_to?(:anchor_x) && circle_two.anchor_x - circle_two_center.x -= circle_two.anchor_x * circle_two_radius * 2 - end - if circle_two.respond_to?(:anchor_y) && circle_two.anchor_y - circle_two_center.y -= circle_two.anchor_y * circle_two_radius * 2 - end + circle_one_center = { x: resolved_circle_one.x + resolved_circle_one.radius, + y: resolved_circle_one.y + resolved_circle_one.radius } + circle_two_center = { x: resolved_circle_two.x + resolved_circle_two.radius, + y: resolved_circle_two.y + resolved_circle_two.radius } - distance_squared(circle_one_center, circle_two_center) <= (circle_one_radius + circle_two_radius)**2 + distance_squared(circle_one_center, circle_two_center) <= (resolved_circle_one.radius + resolved_circle_two.radius)**2 rescue Exception => e raise e, <<-S * ERROR: From 9b2fafef37c45567881bc2c0a7cdc3738baa5b5b Mon Sep 17 00:00:00 2001 From: fiecueal Date: Tue, 22 Oct 2024 09:18:16 +0800 Subject: [PATCH 5/5] fix Geometry.circle_intersect_line? also adds anchor(x|y) functionality --- dragon/geometry.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dragon/geometry.rb b/dragon/geometry.rb index fb605660..664f65ea 100644 --- a/dragon/geometry.rb +++ b/dragon/geometry.rb @@ -690,7 +690,10 @@ def vec2_normal v end def circle_intersect_line? circle, line - center = { x: circle.x, y: circle.y } + center = { x: circle.x + circle.radius, y: circle.y + circle.radius } + center.x -= circle.anchor_x * circle.w if circle.respond_to?(:anchor_x) && circle.anchor_x + center.y -= circle.anchor_y * circle.h if circle.respond_to?(:anchor_y) && circle.anchor_y + closest_point = line_normal line, center result = distance_squared(center, closest_point) <= circle.radius**2 return false if !result