From 65187cd5126227778146ec33c2857a391fbab620 Mon Sep 17 00:00:00 2001 From: lstrzebinczyk Date: Sun, 21 May 2017 21:26:12 +0200 Subject: Implement #contains? for all renderables --- lib/ruby2d/image.rb | 4 ++++ lib/ruby2d/line.rb | 17 +++++++++++++++++ lib/ruby2d/quad.rb | 18 ++++++++++++++++++ lib/ruby2d/rectangle.rb | 4 ++++ lib/ruby2d/renderable.rb | 4 ++++ lib/ruby2d/text.rb | 4 ++++ lib/ruby2d/triangle.rb | 17 +++++++++++++++++ 7 files changed, 68 insertions(+) (limited to 'lib') diff --git a/lib/ruby2d/image.rb b/lib/ruby2d/image.rb index 6660a4d..2691f78 100644 --- a/lib/ruby2d/image.rb +++ b/lib/ruby2d/image.rb @@ -26,5 +26,9 @@ module Ruby2D def color=(c) @color = Color.new(c) end + + def contains?(x, y) + @x < x and @x + @width > x and @y < y and @y + @height > y + end end end diff --git a/lib/ruby2d/line.rb b/lib/ruby2d/line.rb index 9ef534e..769c37f 100644 --- a/lib/ruby2d/line.rb +++ b/lib/ruby2d/line.rb @@ -19,8 +19,25 @@ module Ruby2D update_color(@color) end + def length + points_distance(@x1, @y1, @x2, @y2) + end + + # Line contains a point if the point is closer than the length of line from both ends + # and if the distance from point to line is smaller than half of the width. + # Check https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line for reference + def contains?(x, y) + points_distance(x1, y1, x, y) < length and + points_distance(x2, y2, x, y) < length and + (((@y2 - @y1) * x - (@x2 - @x1) * y + @x2 * @y1 - @y2 * @x1).abs / length) < 0.5 * @width + end + private + def points_distance(x1, y1, x2, y2) + Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) + end + def update_color(c) if c.is_a? Color::Set if c.length == 4 diff --git a/lib/ruby2d/quad.rb b/lib/ruby2d/quad.rb index e3906c0..4fac328 100644 --- a/lib/ruby2d/quad.rb +++ b/lib/ruby2d/quad.rb @@ -29,8 +29,26 @@ module Ruby2D update_color(@color) end + # The logic is the same as for a triangle + # See triangle.rb for reference + def contains?(x, y) + self_area = triangle_area(@x1, @y1, @x2, @y2, @x3, @y3) + + triangle_area(@x1, @y1, @x3, @y3, @x4, @y4) + + questioned_area = triangle_area(@x1, @y1, @x2, @y2, x, y) + + triangle_area(@x2, @y2, @x3, @y3, x, y) + + triangle_area(@x3, @y3, @x4, @y4, x, y) + + triangle_area(@x4, @y4, @x1, @y1, x, y) + + questioned_area <= self_area + end + private + def triangle_area(x1, y1, x2, y2, x3, y3) + (x1*y2 + x2*y3 + x3*y1 - x3*y2 - x1*y3 - x2*y1).abs / 2 + end + def update_color(c) if c.is_a? Color::Set if c.length == 4 diff --git a/lib/ruby2d/rectangle.rb b/lib/ruby2d/rectangle.rb index 569b8b5..db54b46 100644 --- a/lib/ruby2d/rectangle.rb +++ b/lib/ruby2d/rectangle.rb @@ -39,6 +39,10 @@ module Ruby2D update_coords(@x, @y, @width, h) end + def contains?(x, y) + @x < x and @x + @width > x and @y < y and @y + @height > y + end + private def update_coords(x, y, w, h) diff --git a/lib/ruby2d/renderable.rb b/lib/ruby2d/renderable.rb index d80482a..8a581ae 100644 --- a/lib/ruby2d/renderable.rb +++ b/lib/ruby2d/renderable.rb @@ -27,5 +27,9 @@ module Ruby2D def opacity=(val) self.color.opacity = val end + + def contains?(x, y) + raise "Not implemented yet" + end end end diff --git a/lib/ruby2d/text.rb b/lib/ruby2d/text.rb index d3c525f..c036a92 100644 --- a/lib/ruby2d/text.rb +++ b/lib/ruby2d/text.rb @@ -33,6 +33,10 @@ module Ruby2D @color = Color.new(c) end + def contains?(x, y) + @x < x and @x + @width > x and @y < y and @y + @height > y + end + private def resolve_path(font) diff --git a/lib/ruby2d/triangle.rb b/lib/ruby2d/triangle.rb index eb6b07f..e3b091b 100644 --- a/lib/ruby2d/triangle.rb +++ b/lib/ruby2d/triangle.rb @@ -25,8 +25,25 @@ module Ruby2D update_color(@color) end + # Point is inside a triangle if + # the area of 3 triangles, constructed from triangle sides and that point + # is equal to the area of triangle. + def contains?(x, y) + self_area = triangle_area(@x1, @y1, @x2, @y2, @x3, @y3) + questioned_area = + triangle_area(@x1, @y1, @x2, @y2, x, y) + + triangle_area(@x2, @y2, @x3, @y3, x, y) + + triangle_area(@x3, @y3, @x1, @y1, x, y) + + questioned_area <= self_area + end + private + def triangle_area(x1, y1, x2, y2, x3, y3) + (x1*y2 + x2*y3 + x3*y1 - x3*y2 - x1*y3 - x2*y1).abs / 2 + end + def update_color(c) if c.is_a? Color::Set if c.length == 3 -- cgit v1.2.3