ruby-geometry 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -8,4 +8,8 @@ module Geometry
8
8
  x === another_point.x && y === another_point.y
9
9
  end
10
10
  end
11
- end
11
+ end
12
+
13
+ def Point(x, y)
14
+ Geometry::Point.new(x, y)
15
+ end
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
@@ -102,4 +102,8 @@ module Geometry
102
102
  self.to_vector.cross_product(vector_to_second_endpoint) <= 0
103
103
  end
104
104
  end
105
- end
105
+ end
106
+
107
+ def Segment(point1, point2)
108
+ Geometry::Segment.new point1, point2
109
+ end
@@ -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
- prerelease: false
5
- segments:
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
- files:
30
- - lib/point.rb
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/overlaps_test.rb
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/bounds_test.rb
47
- - test/segment/initialize_test.rb
48
- - test/line/x_intercept_test.rb
49
- - test/line/y_intercept_test.rb
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
- segments:
80
- - 0
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
- segments:
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.3.7
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/overlaps_test.rb
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/bounds_test.rb
108
- - test/segment/initialize_test.rb
109
- - test/line/x_intercept_test.rb
110
- - test/line/y_intercept_test.rb
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