summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlstrzebinczyk <[email protected]>2017-05-21 21:26:12 +0200
committerTom Black <[email protected]>2017-05-31 23:36:04 -0400
commit65187cd5126227778146ec33c2857a391fbab620 (patch)
tree328c21a2bdf9365d5c018326c229760986cf412f
parent09ed2811ad3ccb9af50028447fabbcee5b5c5ae2 (diff)
downloadruby2d-65187cd5126227778146ec33c2857a391fbab620.tar.gz
ruby2d-65187cd5126227778146ec33c2857a391fbab620.zip
Implement #contains? for all renderables
-rw-r--r--lib/ruby2d/image.rb4
-rw-r--r--lib/ruby2d/line.rb17
-rw-r--r--lib/ruby2d/quad.rb18
-rw-r--r--lib/ruby2d/rectangle.rb4
-rw-r--r--lib/ruby2d/renderable.rb4
-rw-r--r--lib/ruby2d/text.rb4
-rw-r--r--lib/ruby2d/triangle.rb17
-rw-r--r--test/contains.rb32
-rw-r--r--test/image_spec.rb16
-rw-r--r--test/line_spec.rb23
-rw-r--r--test/quad_spec.rb26
-rw-r--r--test/rectangle_spec.rb18
-rw-r--r--test/text_spec.rb15
-rw-r--r--test/triangle_spec.rb24
14 files changed, 221 insertions, 1 deletions
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
diff --git a/test/contains.rb b/test/contains.rb
new file mode 100644
index 0000000..5a11064
--- /dev/null
+++ b/test/contains.rb
@@ -0,0 +1,32 @@
+require 'ruby2d'
+
+set title: "Ruby 2D — Contains", height: 350
+
+if RUBY_ENGINE == 'opal'
+ media = "../test/media"
+ font = "sans-serif"
+else
+ media = "media"
+ font = "#{media}/bitstream_vera/vera.ttf"
+end
+
+objects = []
+objects.push Square.new(50, 50, 100)
+objects.push Rectangle.new(200, 50, 100, 75)
+objects.push Quad.new(350, 50, 500, 75, 450, 150, 375, 125)
+objects.push Triangle.new(550, 50, 600, 125, 500, 150)
+objects.push Line.new(225, 175, 375, 225, 20)
+objects.push Image.new(50, 200, "#{media}/colors.png")
+objects.push Text.new(450, 200, "Hello", 50, font)
+
+on :key_down do |event|
+ close if event.key == 'escape'
+end
+
+update do
+ objects.each do |o|
+ o.contains?(get(:mouse_x), get(:mouse_y)) ? o.opacity = 1.0 : o.opacity = 0.5
+ end
+end
+
+show
diff --git a/test/image_spec.rb b/test/image_spec.rb
index 3eb5d86..33dee35 100644
--- a/test/image_spec.rb
+++ b/test/image_spec.rb
@@ -1,11 +1,25 @@
require 'ruby2d'
RSpec.describe Ruby2D::Image do
-
describe '#new' do
it "raises exception if image file doesn't exist" do
expect { Image.new(0, 0, 'bad_image.png') }.to raise_error(Ruby2D::Error)
end
end
+ # Image has 100 width and 100 height
+ describe '#contains?' do
+ it "returns true if point is inside image" do
+ image = Image.new(0, 0, "test/media/image.bmp")
+ expect(image.contains?(50, 50)).to be true
+ end
+
+ it "returns true if point is not inside image" do
+ image = Image.new(0, 0, "test/media/image.bmp")
+ expect(image.contains?(-50, 50)).to be false
+ expect(image.contains?(50, -50)).to be false
+ expect(image.contains?(50, 150)).to be false
+ expect(image.contains?(150, 50)).to be false
+ end
+ end
end
diff --git a/test/line_spec.rb b/test/line_spec.rb
new file mode 100644
index 0000000..04445d1
--- /dev/null
+++ b/test/line_spec.rb
@@ -0,0 +1,23 @@
+require 'ruby2d'
+
+RSpec.describe Ruby2D::Triangle do
+ describe '#contains?' do
+ it "returns true if point is inside line" do
+ line = Line.new(
+ 0, 0,
+ 100, 100
+ )
+ expect(line.contains?(25, 25)).to be true
+ end
+
+ it "returns true if point is inside text" do
+ line = Line.new(
+ 0, 0,
+ 100, 100
+ )
+
+ expect(line.contains?(0, 10)).to be false
+ expect(line.contains?(10, 0)).to be false
+ end
+ end
+end
diff --git a/test/quad_spec.rb b/test/quad_spec.rb
index 58f2dfd..a6cfca4 100644
--- a/test/quad_spec.rb
+++ b/test/quad_spec.rb
@@ -89,4 +89,30 @@ RSpec.describe Ruby2D::Quad do
end.to raise_error("Quads require 4 colors, one for each vertex. 5 were given.")
end
end
+
+ describe '#contains?' do
+ it "returns true if point is inside quad" do
+ quad = Quad.new(
+ -25, 0,
+ 0, -25,
+ 25, 0,
+ 0, 25
+ )
+ expect(quad.contains?(0, 0)).to be true
+ end
+
+ it "returns true if point is not inside quad" do
+ quad = Quad.new(
+ -25, 0,
+ 0, -25,
+ 25, 0,
+ 0, 25
+ )
+
+ expect(quad.contains?( 20, 20)).to be false
+ expect(quad.contains?(-20, 20)).to be false
+ expect(quad.contains?( 20, -20)).to be false
+ expect(quad.contains?(-20, -20)).to be false
+ end
+ end
end
diff --git a/test/rectangle_spec.rb b/test/rectangle_spec.rb
new file mode 100644
index 0000000..493f3d1
--- /dev/null
+++ b/test/rectangle_spec.rb
@@ -0,0 +1,18 @@
+require 'ruby2d'
+
+RSpec.describe Ruby2D::Rectangle do
+ describe '#contains?' do
+ it "returns true if point is inside rectangle" do
+ rectangle = Rectangle.new(0, 0, 50, 50)
+ expect(rectangle.contains?(25, 25)).to be true
+ end
+
+ it "returns true if point is not inside rectangle" do
+ rectangle = Rectangle.new(0, 0, 50, 50)
+ expect(rectangle.contains?(-25, 25)).to be false
+ expect(rectangle.contains?(25, -25)).to be false
+ expect(rectangle.contains?(25, 50)).to be false
+ expect(rectangle.contains?(50, 25)).to be false
+ end
+ end
+end
diff --git a/test/text_spec.rb b/test/text_spec.rb
index ad12cbf..15038d2 100644
--- a/test/text_spec.rb
+++ b/test/text_spec.rb
@@ -41,4 +41,19 @@ RSpec.describe Ruby2D::Text do
expect(t.height).to eq(48)
end
end
+
+ describe '#contains?' do
+ it "returns true if point is inside text" do
+ text = Text.new(0, 0, "Hello world!", 40, "test/media/bitstream_vera/vera.ttf")
+ expect(text.contains?(text.width / 2, text.height / 2)).to be true
+ end
+
+ it "returns true if point is not inside text" do
+ text = Text.new(0, 0, "Hello world!", 40, "test/media/bitstream_vera/vera.ttf")
+ expect(text.contains?( - text.width / 2, text.height / 2)).to be false
+ expect(text.contains?( text.width / 2, - text.height / 2)).to be false
+ expect(text.contains?(3 * text.width / 2, text.height / 2)).to be false
+ expect(text.contains?( text.width / 2, 3 * text.height / 2)).to be false
+ end
+ end
end
diff --git a/test/triangle_spec.rb b/test/triangle_spec.rb
index f71b097..b562e59 100644
--- a/test/triangle_spec.rb
+++ b/test/triangle_spec.rb
@@ -79,4 +79,28 @@ RSpec.describe Ruby2D::Triangle do
end.to raise_error("Triangles require 3 colors, one for each vertex. 4 were given.")
end
end
+
+
+ describe '#contains?' do
+ it "returns true if point is inside triangle" do
+ triangle = Triangle.new(
+ 0, 0,
+ 0, 100,
+ 100, 0
+ )
+ expect(triangle.contains?(25, 25)).to be true
+ end
+
+ it "returns true if point is inside text" do
+ triangle = Triangle.new(
+ 0, 0,
+ 0, 100,
+ 100, 0
+ )
+
+ expect(triangle.contains?(25, -25)).to be false
+ expect(triangle.contains?(-25, 25)).to be false
+ expect(triangle.contains?(100, 100)).to be false
+ end
+ end
end