laptimer-geometry 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require File.expand_path('../../src/lap_counter', __FILE__)
3
+
4
+ describe LapCounter do
5
+ it "should find a straight segment witch is valid" do
6
+ true.should be_true
7
+ end
8
+ end
data/spec/line_spec.rb ADDED
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+ require File.expand_path('../../src/geometry', __FILE__)
3
+
4
+ describe Line do
5
+ before do
6
+ # first semi-line
7
+ @pointA = {:x => 2, :y => 1}
8
+ @pointB = {:x => 4, :y => 3}
9
+ #second semi-line
10
+ @pointC = {:x => 3, :y => 1}
11
+ @pointD = {:x => 2, :y => 4}
12
+ #third semi-line
13
+ @pointE = {:x => 3, :y => 0}
14
+ @pointF = {:x => 1, :y => 2}
15
+ end
16
+
17
+ it "should find the gradient of the straight line" do
18
+ sl = Line.new(@pointA, @pointB)
19
+ sl.gradient.should be_eql(1.to_f)
20
+ end
21
+
22
+ it "should find the linear touch of the line" do
23
+ sl = Line.new(@pointA, @pointB)
24
+ sl.linear_touch.should be_eql(-1.to_f)
25
+
26
+ # Double Test
27
+ sl2 = Line.new(@pointE, @pointF)
28
+ sl2.linear_touch.should be_eql(3.to_f)
29
+ end
30
+
31
+ it "should include anotther point from the line" do
32
+ pointC = {:x => 3, :y => 2}
33
+ sl = Line.new(@pointA, @pointB)
34
+ sl.include?(pointC).should be_true
35
+ end
36
+
37
+ it "should intercept with the other line (3,0) and (1,2)" do
38
+ sl = Line.new(@pointA, @pointB)
39
+ sl2 = Line.new(@pointC, @pointD)
40
+ sl.intercept?(sl2).should be_true
41
+ sl3 = Line.new(@pointE, @pointF)
42
+ sl.intercept?(sl3).should be_true
43
+ end
44
+
45
+ it "two concurrent lines should intercept at (2,2)" do
46
+ pA = {:x => 1, :y => 1}
47
+ pB = {:x => 3, :y => 3}
48
+ pC = {:x => 1, :y => 3}
49
+ pD = {:x => 3, :y => 1}
50
+ sl = Line.new(pA, pB)
51
+ sl2 = Line.new(pC, pD)
52
+ sl.intercept?(sl2).should be_true
53
+ sl.intercept_at(sl2).should be_eql({:x => 2.0, :y => 2.0})
54
+ end
55
+
56
+ it "should not intercept with a parallel line" do
57
+ pA = {:x => 1, :y => 1}
58
+ pB = {:x => 3, :y => 3}
59
+ pC = {:x => 2, :y => 1}
60
+ pD = {:x => 3, :y => 2}
61
+ sl = Line.new(pA, pB)
62
+ sl2 = Line.new(pC, pD)
63
+ sl.intercept?(sl2).should be_false
64
+ end
65
+
66
+ it "should intercept between the 2 original points of the first line" do
67
+ pA = {:x => 1, :y => 1}
68
+ pB = {:x => 3, :y => 3}
69
+ pC = {:x => 1, :y => 3}
70
+ pD = {:x => 3, :y => 1}
71
+ sl = Line.new(pA, pB)
72
+ sl2 = Line.new(pC, pD)
73
+ sl.intercept_line_segment?(sl2).should be_true
74
+ end
75
+
76
+ it "should not find an interception between the two segments" do
77
+ pA = {:x => 1, :y => 1}
78
+ pB = {:x => 3, :y => 3}
79
+ pC = {:x => 4, :y => 3}
80
+ pD = {:x => 6, :y => 1}
81
+ sl = Line.new(pA, pB)
82
+ sl2 = Line.new(pC, pD)
83
+ sl.intercept_line_segment?(sl2).should be_false
84
+ end
85
+
86
+ it "should intercept event in the negative Y quadrant" do
87
+ flag_line = Line.new({:x => 1, :y => -1, }, {:x => 3, :y => -4})
88
+ segment1 = Line.new({:x => 1, :y => -3}, {:x => 3, :y => -1})
89
+
90
+ flag_line.intercept_line_segment?(segment1).should be_true
91
+ end
92
+
93
+
94
+ it "should intercept event in the negative X quadrant" do
95
+ flag_line = Line.new({:x => -1, :y => 1, }, {:x => -3, :y => 4})
96
+ segment1 = Line.new({:x => -3, :y => 1}, {:x => -1, :y => 3})
97
+
98
+ flag_line.intercept_line_segment?(segment1).should be_true
99
+ end
100
+
101
+ it "should intercept event in the all negative quadrant" do
102
+ flag_line = Line.new({:x => -1, :y => -1, }, {:x => -3, :y => -3})
103
+ segment1 = Line.new({:x => -1, :y => -3}, {:x => -2, :y => -2})
104
+
105
+ flag_line.intercept_line_segment?(segment1).should be_true
106
+ end
107
+
108
+ it "should intercept when segments are in different quadrants" do
109
+ flag_line = Line.new({:x => -1, :y => 1, }, {:x => -3, :y => 4})
110
+ segment1 = Line.new({:x => 1, :y => 3}, {:x => 3, :y => 1})
111
+
112
+ flag_line.intercept_line_segment?(segment1).should be_false
113
+ end
114
+
115
+ it "should calculate the distance using the Earth radius Nelson Piquet" do
116
+ point1 = {:x => -47.900648, :y => -15.772954}
117
+ point2 = {:x => -47.900365, :y => -15.772869}
118
+ point3 = {:x => -47.90025, :y => -15.772835}
119
+ Geometry.calculate_distance(point1, point2).should be_true
120
+ Geometry.calculate_distance(point1, point3).should be_true
121
+ end
122
+
123
+ it "should find the crossing segment with some real coordinates - Aut. Nelson Piquet" do
124
+ flag_line = Line.new({:x => -47.900333, :y => -15.772656, }, {:x => -47.900148, :y => -15.773056})
125
+ segment1 = Line.new({:x => -47.900648, :y => -15.772954}, {:x =>-47.899923, :y => -15.772683})
126
+
127
+ flag_line.intercept_line_segment?(segment1).should be_true
128
+ end
129
+
130
+ it "should not accept the crossing form real segments with they do not touch - Aut. Nelson Piquet" do
131
+ flag_line = Line.new({:x => -47.900333, :y => -15.772656, }, {:x => -47.900148, :y => -15.773056})
132
+ segment1 = Line.new({:x => -47.900648, :y => -15.772954}, {:x =>-47.900365, :y => -15.772869})
133
+
134
+ flag_line.intercept_line_segment?(segment1).should be_false
135
+ end
136
+
137
+ end
data/src/geometry.rb ADDED
@@ -0,0 +1,129 @@
1
+ module Geometry
2
+ include Math
3
+ extend Math
4
+
5
+ def distance(point1, point2)
6
+ x1 = (point1[:x] > 0) ? point1[:x] : (point1[:x]*-1 )
7
+ x2 = (point2[:x] > 0) ? point2[:x] : (point2[:x]*-1 )
8
+ y1 = (point1[:y] > 0) ? point1[:y] : (point1[:y]*-1 )
9
+ y2 = (point2[:y] > 0) ? point2[:y] : (point2[:y]*-1 )
10
+ hypot x1 - x2, y1 - y2
11
+ end
12
+
13
+ def calculate_distance(point1, point2)
14
+ x1 = point1[:x] * Math::PI / 180
15
+ x2 = point2[:x] * Math::PI / 180
16
+ y1 = point1[:y] * Math::PI / 180
17
+ y2 = point2[:y] * Math::PI / 180
18
+
19
+ s = sin(y2)*sin(y1)+(cos(y2)*cos(y1)*cos(x2 - x1))
20
+ rad_distance = acos(s)
21
+ degree_distance = rad_distance/(Math::PI/180)
22
+ earth_radius = 6378
23
+ distance_km = earth_radius*degree_distance
24
+ distance_km
25
+ end
26
+
27
+ module_function :distance
28
+ module_function :calculate_distance
29
+ end
30
+
31
+ class Line
32
+ include Math
33
+ def initialize(pointA, pointB)
34
+ @a, @b, @c = nil, nil, nil
35
+ @gradient = nil
36
+ @linear = nil
37
+ @pointA = pointA
38
+ @pointB = pointB
39
+ calculate_gradient
40
+ calculate_linear
41
+ end
42
+
43
+ def pointA
44
+ @pointA
45
+ end
46
+
47
+ def pointB
48
+ @pointB
49
+ end
50
+
51
+ def gradient(ac = nil)
52
+ if ac.nil?
53
+ @gradient
54
+ else
55
+ @gradient = ac
56
+ end
57
+
58
+ @gradient
59
+ end
60
+
61
+ # m(x2-x1) - y2 + y1 = 0
62
+ def include?(point)
63
+ result = @gradient * (point[:x] - @pointA[:x]) - point[:y] + @pointA[:y]
64
+ if(result == 0)
65
+ true
66
+ else
67
+ false
68
+ end
69
+ end
70
+
71
+ def intercept?(line)
72
+ (intercept_at(line).nil? == true) ? false : true
73
+ end
74
+
75
+ def intercept_at(line)
76
+ if @gradient != line.gradient
77
+ x = calculate_x_from_two_lines(self, line)
78
+ y = (@gradient*x.to_f) + @linear
79
+
80
+ new_point = { :x => sprintf('%.6f',x).to_f, :y => sprintf('%.6f',y).to_f}
81
+ return new_point
82
+ end
83
+
84
+ return nil
85
+ end
86
+
87
+ def linear_touch
88
+ @linear
89
+ end
90
+
91
+ def intercept_line_segment?(line)
92
+
93
+ # verify the distance
94
+ if intercept?(line)
95
+ interception_point = intercept_at(line)
96
+
97
+ distance_segment = Geometry.calculate_distance(line.pointA, line.pointB)
98
+ distance_A_line_segment = Geometry.calculate_distance(line.pointA, interception_point)
99
+ distance_B_line_segment = Geometry.calculate_distance(line.pointB, interception_point)
100
+
101
+ if distance_A_line_segment > distance_segment
102
+ return false
103
+ elsif distance_B_line_segment > distance_segment
104
+ return false
105
+ else
106
+ return true
107
+ end
108
+ end
109
+
110
+ return false
111
+ end
112
+
113
+ private
114
+ def calculate_gradient
115
+ @gradient = (@pointB[:y] - @pointA[:y]) / (@pointB[:x] - @pointA[:x]).to_f
116
+ end
117
+
118
+ def calculate_linear
119
+ @linear = nil
120
+ if not @gradient.nil?
121
+ @linear = @pointA[:y].to_f - (@gradient * @pointA[:x].to_f )
122
+ end
123
+ @linear
124
+ end
125
+
126
+ def calculate_x_from_two_lines(line1, line2)
127
+ (line2.linear_touch - line1.linear_touch) / (line1.gradient - line2.gradient)
128
+ end
129
+ end
@@ -0,0 +1,2 @@
1
+ class LapCounter
2
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: laptimer-geometry
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Eduardo Marques
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-03 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: " laptimer-geometry is a gem created to help the coordinates calculations used in a laptimer software.\n"
22
+ email: edhana@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - src/geometry.rb
31
+ - src/lap_counter.rb
32
+ - spec/lap_counter_spec.rb
33
+ - spec/line_spec.rb
34
+ homepage: http://github.com/edhana/laptimer-geometry
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - src
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.8.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Implementation of basic 2D geometry algorithms, to help with a lap timer system written in Ruby
67
+ test_files:
68
+ - spec/lap_counter_spec.rb
69
+ - spec/line_spec.rb