ruby-geometry 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/algorithms/point_in_polygon.rb +64 -0
- data/lib/bounding_box.rb +11 -0
- data/lib/geometry.rb +5 -0
- data/lib/point.rb +5 -1
- data/lib/polygon.rb +17 -1
- data/lib/segment.rb +5 -1
- data/test/bounding_box/contains_test.rb +29 -0
- data/test/polygon/bounding_box_test.rb +43 -0
- data/test/polygon/contains_point_test.rb +73 -0
- metadata +72 -82
@@ -0,0 +1,64 @@
|
|
1
|
+
module Geometry
|
2
|
+
class PointInPolygon < Struct.new(:point, :polygon)
|
3
|
+
extend ActiveSupport::Memoizable
|
4
|
+
|
5
|
+
def inside?
|
6
|
+
point_location == :inside
|
7
|
+
end
|
8
|
+
|
9
|
+
def outside?
|
10
|
+
point_location == :outside
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_the_boundary?
|
14
|
+
point_location == :on_the_boundary
|
15
|
+
end
|
16
|
+
|
17
|
+
def point_location
|
18
|
+
return :outside unless bounding_box.contains?(point)
|
19
|
+
return :on_the_boundary if point_is_vertex? || point_on_edge?
|
20
|
+
|
21
|
+
intersection_count(choose_good_ray).odd? ? :inside : :outside
|
22
|
+
end
|
23
|
+
|
24
|
+
delegate :vertices, :edges, :bounding_box, :to => :polygon
|
25
|
+
memoize :point_location, :edges, :bounding_box
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def point_is_vertex?
|
30
|
+
vertices.any? { |vertex| vertex == point }
|
31
|
+
end
|
32
|
+
|
33
|
+
def point_on_edge?
|
34
|
+
edges.any? { |edge| edge.contains_point?(point) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def choose_good_ray
|
38
|
+
ray = random_ray
|
39
|
+
while ! good_ray?(ray) do
|
40
|
+
ray = random_ray
|
41
|
+
end
|
42
|
+
ray
|
43
|
+
end
|
44
|
+
|
45
|
+
def good_ray?(ray)
|
46
|
+
edges.none? { |edge| edge.parallel_to?(ray) } && vertices.none? { |vertex| ray.contains_point?(vertex) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def intersection_count(ray)
|
50
|
+
edges.select { |edge| edge.intersects_with?(ray) }.size
|
51
|
+
end
|
52
|
+
|
53
|
+
def random_ray
|
54
|
+
random_direction = rand * (2 * Math::PI)
|
55
|
+
|
56
|
+
ray_endpoint = Point sufficient_ray_radius * Math.cos(random_direction), sufficient_ray_radius * Math.sin(random_direction)
|
57
|
+
Segment point, ray_endpoint
|
58
|
+
end
|
59
|
+
|
60
|
+
def sufficient_ray_radius
|
61
|
+
@sufficient_ray_radius ||= bounding_box.diagonal.length * 2
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/bounding_box.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module Geometry
|
2
|
+
class BoundingBox < Struct.new(:leftbottom, :righttop)
|
3
|
+
def diagonal
|
4
|
+
Segment leftbottom, righttop
|
5
|
+
end
|
6
|
+
|
7
|
+
def contains?(point)
|
8
|
+
point.x.between?(leftbottom.x, righttop.x) && point.y.between?(leftbottom.y, righttop.y)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/geometry.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
require "active_support/memoizable"
|
3
|
+
|
1
4
|
require 'point'
|
2
5
|
require 'segment'
|
3
6
|
require 'vector'
|
4
7
|
require 'polygon'
|
5
8
|
require 'line'
|
9
|
+
require 'bounding_box'
|
10
|
+
require 'algorithms/point_in_polygon'
|
6
11
|
|
7
12
|
module Geometry
|
8
13
|
include Math
|
data/lib/point.rb
CHANGED
data/lib/polygon.rb
CHANGED
@@ -9,5 +9,21 @@ module Geometry
|
|
9
9
|
|
10
10
|
edges << Segment.new(vertices.last, vertices.first)
|
11
11
|
end
|
12
|
+
|
13
|
+
def bounding_box
|
14
|
+
leftbottom = Point vertices.map(&:x).min, vertices.map(&:y).min
|
15
|
+
righttop = Point vertices.map(&:x).max, vertices.map(&:y).max
|
16
|
+
|
17
|
+
BoundingBox.new leftbottom, righttop
|
18
|
+
end
|
19
|
+
|
20
|
+
def contains?(point)
|
21
|
+
point_in_polygon = PointInPolygon.new(point, self)
|
22
|
+
point_in_polygon.inside? || point_in_polygon.on_the_boundary?
|
23
|
+
end
|
12
24
|
end
|
13
|
-
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def Polygon(vertices)
|
28
|
+
Geometry::Polygon.new(vertices)
|
29
|
+
end
|
data/lib/segment.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'geometry'
|
3
|
+
|
4
|
+
class ContainsTest < Test::Unit::TestCase
|
5
|
+
include Geometry
|
6
|
+
|
7
|
+
def bounding_box
|
8
|
+
BoundingBox.new Point(-1, -1), Point(1, 1)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_contains
|
12
|
+
assert bounding_box.contains?(Point(0, 0))
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_does_not_contain
|
16
|
+
assert ! bounding_box.contains?(Point(2, 2))
|
17
|
+
assert ! bounding_box.contains?(Point(-2, -2))
|
18
|
+
assert ! bounding_box.contains?(Point(1, 2))
|
19
|
+
assert ! bounding_box.contains?(Point(0, -1.1))
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_on_the_edge
|
23
|
+
assert bounding_box.contains?(Point(1, 0))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_at_vertex
|
27
|
+
assert bounding_box.contains?(Point(1, 1))
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'geometry'
|
3
|
+
|
4
|
+
class BoundingBoxTest < Test::Unit::TestCase
|
5
|
+
include Geometry
|
6
|
+
|
7
|
+
def test_rectangle
|
8
|
+
polygon = Polygon [
|
9
|
+
Point(-1, -1),
|
10
|
+
Point(1, -1),
|
11
|
+
Point(1, 1),
|
12
|
+
Point(-1, 1)
|
13
|
+
]
|
14
|
+
assert polygon.bounding_box.leftbottom == Point(-1, -1)
|
15
|
+
assert polygon.bounding_box.righttop == Point(1, 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_sloped_rectangle
|
19
|
+
polygon = Polygon [
|
20
|
+
Point(-1, 0),
|
21
|
+
Point(0, -1),
|
22
|
+
Point(1, 0),
|
23
|
+
Point(0, 1)
|
24
|
+
]
|
25
|
+
|
26
|
+
assert polygon.bounding_box.leftbottom == Point(-1, -1)
|
27
|
+
assert polygon.bounding_box.righttop == Point(1, 1)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_nonconvex
|
31
|
+
polygon = Polygon [
|
32
|
+
Point(0, 2),
|
33
|
+
Point(2, 0),
|
34
|
+
Point(5, 1),
|
35
|
+
Point(3, 8),
|
36
|
+
Point(3, 1),
|
37
|
+
Point(1, 4)
|
38
|
+
]
|
39
|
+
|
40
|
+
assert polygon.bounding_box.leftbottom == Point(0, 0)
|
41
|
+
assert polygon.bounding_box.righttop == Point(5, 8)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'geometry'
|
3
|
+
|
4
|
+
class ContainsPointTest < Test::Unit::TestCase
|
5
|
+
include Geometry
|
6
|
+
|
7
|
+
def test_convex
|
8
|
+
rectangle = Polygon.new [
|
9
|
+
Point(0, 0),
|
10
|
+
Point(1, 0),
|
11
|
+
Point(1, 1),
|
12
|
+
Point(0, 1)
|
13
|
+
]
|
14
|
+
|
15
|
+
|
16
|
+
inner = Point(0.5, 0.5)
|
17
|
+
assert rectangle.contains?(inner)
|
18
|
+
|
19
|
+
outer = Point(1.5, 1.5)
|
20
|
+
assert ! rectangle.contains?(outer)
|
21
|
+
|
22
|
+
on_edge = Point(0.5, 1)
|
23
|
+
assert rectangle.contains?(on_edge)
|
24
|
+
|
25
|
+
at_vertex = Point(1, 1)
|
26
|
+
assert rectangle.contains?(at_vertex)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# +--------+
|
31
|
+
# | |
|
32
|
+
# | +---+
|
33
|
+
# | |
|
34
|
+
# | +---+
|
35
|
+
# | |
|
36
|
+
# +--------+
|
37
|
+
|
38
|
+
def test_nonconvex
|
39
|
+
nonconvex_polygon = Polygon.new [
|
40
|
+
Point(0, 0),
|
41
|
+
Point(0, 6),
|
42
|
+
Point(4, 6),
|
43
|
+
Point(4, 4),
|
44
|
+
Point(2, 4),
|
45
|
+
Point(2, 2),
|
46
|
+
Point(4, 2),
|
47
|
+
Point(4, 0)
|
48
|
+
]
|
49
|
+
|
50
|
+
inner_points = [
|
51
|
+
Point(1, 5),
|
52
|
+
Point(3, 5),
|
53
|
+
Point(1, 3),
|
54
|
+
Point(1, 1),
|
55
|
+
Point(3, 1)
|
56
|
+
]
|
57
|
+
|
58
|
+
outer_points = [
|
59
|
+
Point(7, 5),
|
60
|
+
Point(5, 3),
|
61
|
+
Point(7, 3),
|
62
|
+
Point(7, 1)
|
63
|
+
]
|
64
|
+
|
65
|
+
inner_points.each do |inner_point|
|
66
|
+
assert nonconvex_polygon.contains?(inner_point)
|
67
|
+
end
|
68
|
+
|
69
|
+
outer_points.each do |outer_point|
|
70
|
+
assert ! nonconvex_polygon.contains?(outer_point)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
metadata
CHANGED
@@ -1,125 +1,115 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-geometry
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
version: 0.0.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Daniel Vartanov
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
date: 2010-10-17 00:00:00 -04:00
|
18
|
-
default_executable:
|
12
|
+
date: 2011-12-04 00:00:00.000000000Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
14
|
description:
|
22
15
|
email: daniel.vartanov@gmail.com
|
23
16
|
executables: []
|
24
|
-
|
25
17
|
extensions: []
|
26
|
-
|
27
18
|
extra_rdoc_files: []
|
28
|
-
|
29
|
-
|
30
|
-
- lib/
|
31
|
-
- lib/line.rb
|
19
|
+
files:
|
20
|
+
- lib/algorithms/point_in_polygon.rb
|
21
|
+
- lib/bounding_box.rb
|
32
22
|
- lib/comparison_with_precision.rb
|
33
|
-
- lib/polygon.rb
|
34
|
-
- lib/vector.rb
|
35
23
|
- lib/geometry.rb
|
24
|
+
- lib/line.rb
|
25
|
+
- lib/point.rb
|
26
|
+
- lib/polygon.rb
|
36
27
|
- lib/segment.rb
|
28
|
+
- lib/vector.rb
|
29
|
+
- test/bounding_box/contains_test.rb
|
37
30
|
- test/geometry/distance_test.rb
|
31
|
+
- test/line/angle_to_test.rb
|
32
|
+
- test/line/horizontal_test.rb
|
33
|
+
- test/line/initialize_test.rb
|
34
|
+
- test/line/intersect_x_test.rb
|
35
|
+
- test/line/parallel_to_test.rb
|
36
|
+
- test/line/slope_test.rb
|
37
|
+
- test/line/vertical_test.rb
|
38
|
+
- test/line/x_intercept_test.rb
|
39
|
+
- test/line/y_intercept_test.rb
|
40
|
+
- test/point/equals_test.rb
|
41
|
+
- test/point/initialize_test.rb
|
42
|
+
- test/polygon/bounding_box_test.rb
|
43
|
+
- test/polygon/contains_point_test.rb
|
38
44
|
- test/polygon/edges_test.rb
|
45
|
+
- test/segment/bounds_test.rb
|
39
46
|
- test/segment/contains_point_test.rb
|
40
|
-
- test/segment/
|
41
|
-
- test/segment/to_vector_test.rb
|
42
|
-
- test/segment/length_test.rb
|
47
|
+
- test/segment/initialize_test.rb
|
43
48
|
- test/segment/intersection_point_with_test.rb
|
44
|
-
- test/segment/parallel_to_test.rb
|
45
49
|
- test/segment/intersects_with_test.rb
|
46
|
-
- test/segment/
|
47
|
-
- test/segment/
|
48
|
-
- test/
|
49
|
-
- test/
|
50
|
-
- test/line/parallel_to_test.rb
|
51
|
-
- test/line/angle_to_test.rb
|
52
|
-
- test/line/initialize_test.rb
|
53
|
-
- test/line/vertical_test.rb
|
54
|
-
- test/line/slope_test.rb
|
55
|
-
- test/line/intersect_x_test.rb
|
56
|
-
- test/line/horizontal_test.rb
|
57
|
-
- test/vector/equals_test.rb
|
58
|
-
- test/vector/modulus_test.rb
|
50
|
+
- test/segment/length_test.rb
|
51
|
+
- test/segment/overlaps_test.rb
|
52
|
+
- test/segment/parallel_to_test.rb
|
53
|
+
- test/segment/to_vector_test.rb
|
59
54
|
- test/vector/arithmetics_test.rb
|
55
|
+
- test/vector/collinear_with_test.rb
|
60
56
|
- test/vector/cross_product_test.rb
|
57
|
+
- test/vector/equals_test.rb
|
58
|
+
- test/vector/modulus_test.rb
|
61
59
|
- test/vector/scalar_product_test.rb
|
62
|
-
- test/vector/collinear_with_test.rb
|
63
|
-
- test/point/equals_test.rb
|
64
|
-
- test/point/initialize_test.rb
|
65
|
-
has_rdoc: true
|
66
60
|
homepage: http://github.com/DanielVartanov/ruby-geometry
|
67
61
|
licenses: []
|
68
|
-
|
69
62
|
post_install_message:
|
70
63
|
rdoc_options: []
|
71
|
-
|
72
|
-
require_paths:
|
64
|
+
require_paths:
|
73
65
|
- lib
|
74
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
67
|
none: false
|
76
|
-
requirements:
|
77
|
-
- -
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
|
80
|
-
|
81
|
-
version: "0"
|
82
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
73
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
|
88
|
-
- 0
|
89
|
-
version: "0"
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
90
78
|
requirements: []
|
91
|
-
|
92
79
|
rubyforge_project:
|
93
|
-
rubygems_version: 1.
|
80
|
+
rubygems_version: 1.8.10
|
94
81
|
signing_key:
|
95
82
|
specification_version: 3
|
96
83
|
summary: Implementation of basic 2D geometry algorithms in Ruby
|
97
|
-
test_files:
|
84
|
+
test_files:
|
85
|
+
- test/bounding_box/contains_test.rb
|
98
86
|
- test/geometry/distance_test.rb
|
87
|
+
- test/line/angle_to_test.rb
|
88
|
+
- test/line/horizontal_test.rb
|
89
|
+
- test/line/initialize_test.rb
|
90
|
+
- test/line/intersect_x_test.rb
|
91
|
+
- test/line/parallel_to_test.rb
|
92
|
+
- test/line/slope_test.rb
|
93
|
+
- test/line/vertical_test.rb
|
94
|
+
- test/line/x_intercept_test.rb
|
95
|
+
- test/line/y_intercept_test.rb
|
96
|
+
- test/point/equals_test.rb
|
97
|
+
- test/point/initialize_test.rb
|
98
|
+
- test/polygon/bounding_box_test.rb
|
99
|
+
- test/polygon/contains_point_test.rb
|
99
100
|
- test/polygon/edges_test.rb
|
101
|
+
- test/segment/bounds_test.rb
|
100
102
|
- test/segment/contains_point_test.rb
|
101
|
-
- test/segment/
|
102
|
-
- test/segment/to_vector_test.rb
|
103
|
-
- test/segment/length_test.rb
|
103
|
+
- test/segment/initialize_test.rb
|
104
104
|
- test/segment/intersection_point_with_test.rb
|
105
|
-
- test/segment/parallel_to_test.rb
|
106
105
|
- test/segment/intersects_with_test.rb
|
107
|
-
- test/segment/
|
108
|
-
- test/segment/
|
109
|
-
- test/
|
110
|
-
- test/
|
111
|
-
- test/line/parallel_to_test.rb
|
112
|
-
- test/line/angle_to_test.rb
|
113
|
-
- test/line/initialize_test.rb
|
114
|
-
- test/line/vertical_test.rb
|
115
|
-
- test/line/slope_test.rb
|
116
|
-
- test/line/intersect_x_test.rb
|
117
|
-
- test/line/horizontal_test.rb
|
118
|
-
- test/vector/equals_test.rb
|
119
|
-
- test/vector/modulus_test.rb
|
106
|
+
- test/segment/length_test.rb
|
107
|
+
- test/segment/overlaps_test.rb
|
108
|
+
- test/segment/parallel_to_test.rb
|
109
|
+
- test/segment/to_vector_test.rb
|
120
110
|
- test/vector/arithmetics_test.rb
|
111
|
+
- test/vector/collinear_with_test.rb
|
121
112
|
- test/vector/cross_product_test.rb
|
113
|
+
- test/vector/equals_test.rb
|
114
|
+
- test/vector/modulus_test.rb
|
122
115
|
- test/vector/scalar_product_test.rb
|
123
|
-
- test/vector/collinear_with_test.rb
|
124
|
-
- test/point/equals_test.rb
|
125
|
-
- test/point/initialize_test.rb
|