symmetry_axis 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/lib/symmetry_axis/line.rb +35 -10
- data/lib/symmetry_axis.rb +19 -15
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ac00b6ca3f12a6cf9ff5f8f34ef6e440bbc8e6d
|
4
|
+
data.tar.gz: 0da763b5764c2e3098aabce450ce456f1074f31d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bad29fbf34ede0252c1db5ec83af74531e3aa1ea9c8c32ab723c287095ea0f0faf26215443cd88480e861e17ab73a4a401ca60db1e2e924b9bb5655771383fd
|
7
|
+
data.tar.gz: cabbcf950fb5891d326775907f34c86c1193dea00f94f0da442175a6420c77b8327af5d05861aa975a718b746f0832d867478b92615f43e895c9e845bcb434e9
|
data/lib/symmetry_axis/line.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# Every line here defined by the coefficients of the equation:
|
2
|
+
# y = a + bx
|
3
|
+
# But this equation can not describe vertical lines (infinite +b+).
|
4
|
+
# So the vertical lines are defined by +x+.
|
1
5
|
class Line
|
2
6
|
attr_reader :a, :b, :x
|
3
7
|
EPS, TOO_BIG_B = 0.000001, 100_000_000
|
@@ -11,6 +15,8 @@ class Line
|
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
18
|
+
# Shorthand for constructor.
|
19
|
+
# @return [Line]
|
14
20
|
def self.for_points(p1, p2)
|
15
21
|
Line.new(p1[0], p1[1], p2[0], p2[1])
|
16
22
|
end
|
@@ -19,30 +25,41 @@ class Line
|
|
19
25
|
self.class.aeq(self, other) && self.class.beq(self, other)
|
20
26
|
end
|
21
27
|
|
28
|
+
# @return [String]
|
22
29
|
def to_s
|
23
|
-
if !vertical
|
30
|
+
if !vertical?
|
24
31
|
"(a=#{@a}, b=#{@b})"
|
25
32
|
else
|
26
33
|
"(x=#{@x})"
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
30
|
-
|
37
|
+
# Is the line strictly vertical. This line could be created from
|
38
|
+
# almost vertical pair of points (+b+ coefficient was just Too Big).
|
39
|
+
#
|
40
|
+
# If +true+, you cannot use +a+ and +b+ fields
|
41
|
+
# (you can read +x+ field instead).
|
42
|
+
def vertical?
|
31
43
|
@vertical = (nil == @b) || (TOO_BIG_B <= @b.abs) if nil == @vertical
|
32
44
|
@vertical
|
33
45
|
end
|
34
46
|
|
47
|
+
# Zero means three o'clock, +pi/2+ means noon.
|
48
|
+
# @return [Float]
|
35
49
|
def angle_rad
|
36
|
-
return (Math::PI / 2) if vertical
|
50
|
+
return (Math::PI / 2) if vertical?
|
37
51
|
Math.atan(@b)
|
38
52
|
end
|
39
53
|
|
54
|
+
# Zero means three o'clock, 90 means noon.
|
55
|
+
# @return [Float]
|
40
56
|
def angle_degrees
|
41
57
|
angle_rad / Math::PI * 180
|
42
58
|
end
|
43
59
|
|
44
|
-
|
45
|
-
|
60
|
+
# Does the point lie on the line.
|
61
|
+
def on_me?(x, y)
|
62
|
+
if vertical?
|
46
63
|
(@x - x).abs < EPS
|
47
64
|
else
|
48
65
|
f = @a + @b * x
|
@@ -57,10 +74,14 @@ class Line
|
|
57
74
|
e
|
58
75
|
end
|
59
76
|
|
77
|
+
# Symmetry line of two points.
|
78
|
+
# The perpendicular line drawn through the center
|
79
|
+
# of the line segment between the points.
|
80
|
+
# @return [Line]
|
60
81
|
def self.symmetryof(x1, y1, x2, y2)
|
61
82
|
line = Line.new(x1, y1, x2, y2)
|
62
83
|
x, y = (x1 + x2) / 2, (y1 + y2) / 2
|
63
|
-
if line.vertical
|
84
|
+
if line.vertical?
|
64
85
|
Line.new(0, y, 1, y)
|
65
86
|
else
|
66
87
|
r = line.angle_rad + (Math::PI / 2)
|
@@ -69,11 +90,15 @@ class Line
|
|
69
90
|
end
|
70
91
|
end
|
71
92
|
|
93
|
+
# Draw a parallel line through the point.
|
94
|
+
# @return [Line]
|
72
95
|
def parallel(x, y)
|
73
|
-
return Line.new(x, y, x, y + 1) if vertical
|
96
|
+
return Line.new(x, y, x, y + 1) if vertical?
|
74
97
|
Line.new(x, y, x + 1, y + @b)
|
75
98
|
end
|
76
99
|
|
100
|
+
private :on_me_eps
|
101
|
+
|
77
102
|
private
|
78
103
|
|
79
104
|
def resolve_coefs(xmin, yxmin, xmax, yxmax)
|
@@ -83,7 +108,7 @@ class Line
|
|
83
108
|
@b = (yxmax - yxmin) / Float(xmax - xmin)
|
84
109
|
@a = yxmin - @b * xmin
|
85
110
|
end
|
86
|
-
@x, @a = xmin, 0 if vertical
|
111
|
+
@x, @a = xmin, 0 if vertical?
|
87
112
|
end
|
88
113
|
|
89
114
|
def self.aeq(o1, o2)
|
@@ -91,8 +116,8 @@ class Line
|
|
91
116
|
end
|
92
117
|
|
93
118
|
def self.beq(o1, o2)
|
94
|
-
if o1.vertical || o2.vertical
|
95
|
-
return false unless o1.vertical && o2.vertical
|
119
|
+
if o1.vertical? || o2.vertical?
|
120
|
+
return false unless o1.vertical? && o2.vertical?
|
96
121
|
(o1.x - o2.x).abs < (2 * EPS)
|
97
122
|
else
|
98
123
|
(o1.b - o2.b).abs < (2 * EPS)
|
data/lib/symmetry_axis.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
+
# The algorithm, based on principle, every point have a pair.
|
2
|
+
# It uses the first got point and iterates over +(N - 1)+
|
3
|
+
# other points to find a line,
|
4
|
+
# all points lie by twos on lines parallel to.
|
5
|
+
# The perpendicular line to this line is the symmetry axis.
|
1
6
|
class SymmetryAxis
|
2
7
|
attr_reader :line
|
3
8
|
|
4
9
|
def initialize(point_array)
|
5
10
|
@input = point_array
|
11
|
+
return if @input.size.odd?
|
6
12
|
@impossible_angles = []
|
7
13
|
@two_points_cursor = 1
|
8
|
-
@s1counter, @s2counter, @s2loopcounter = 0, 0, 0
|
9
14
|
loop do
|
10
|
-
take_two_points # step 1
|
15
|
+
return unless take_two_points # step 1
|
11
16
|
break if points_are_on_parallel_lines # step 2
|
12
17
|
end
|
13
18
|
find_axis # step 3
|
@@ -16,15 +21,14 @@ class SymmetryAxis
|
|
16
21
|
private
|
17
22
|
|
18
23
|
def take_two_points
|
19
|
-
@s1counter += 1
|
20
24
|
@two_points = [@input.first]
|
21
25
|
(@two_points_cursor...(@input.size)).each do |i|
|
22
26
|
rad = Line.for_points(@two_points[0], @input[i]).angle_rad
|
23
27
|
next if impossible?(rad)
|
24
28
|
choose_point i
|
25
|
-
return
|
29
|
+
return true
|
26
30
|
end
|
27
|
-
|
31
|
+
false
|
28
32
|
end
|
29
33
|
|
30
34
|
def choose_point(i)
|
@@ -40,15 +44,17 @@ class SymmetryAxis
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def points_are_on_parallel_lines
|
43
|
-
@
|
44
|
-
|
45
|
-
|
47
|
+
other_points = @input.select { |p| !@two_points.include?(p) }
|
48
|
+
@axis_perpendicular_points = @two_points.dup
|
49
|
+
check_perpendiculars(other_points)
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_perpendiculars(points)
|
46
53
|
loop do
|
47
54
|
break if points.empty?
|
48
|
-
@s2loopcounter += 1
|
49
55
|
line = @two_points_line.parallel(*points.first)
|
50
56
|
size0 = points.size
|
51
|
-
on_line = points.select { |p2| line.on_me(*p2) }
|
57
|
+
on_line = points.select { |p2| line.on_me?(*p2) }
|
52
58
|
points -= on_line
|
53
59
|
return false if size0 - points.size < 2
|
54
60
|
save_perpendicular_points(on_line, line)
|
@@ -59,11 +65,11 @@ class SymmetryAxis
|
|
59
65
|
def save_perpendicular_points(points, line)
|
60
66
|
return if line != @two_points_line
|
61
67
|
points += @two_points
|
62
|
-
@
|
68
|
+
@axis_perpendicular_points = pppair(points, line)
|
63
69
|
end
|
64
70
|
|
65
71
|
def pppair(points, line)
|
66
|
-
if line.vertical
|
72
|
+
if line.vertical?
|
67
73
|
[points.min_by { |p| p[1] }, points.max_by { |p| p[1] }]
|
68
74
|
else
|
69
75
|
[points.min_by { |p| p[0] }, points.max_by { |p| p[0] }]
|
@@ -71,9 +77,7 @@ class SymmetryAxis
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def find_axis
|
74
|
-
|
75
|
-
points = @perpendicular_points_pairs_list[0]
|
76
|
-
p1, p2 = points[0], points[1]
|
80
|
+
p1, p2 = *@axis_perpendicular_points
|
77
81
|
@line = Line.symmetryof(p1[0], p1[1], p2[0], p2[1])
|
78
82
|
end
|
79
83
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: symmetry_axis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Георгий Устинов"
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: codeclimate-test-reporter
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: 'Symmetry axis from a point list. It has the restriction: no points must
|
42
56
|
be on axis. Thus every point must have a pair. You can separately use the Line class
|
43
57
|
from the gem. It allows you to compare for equality the lines, defined by different
|
@@ -74,3 +88,4 @@ signing_key:
|
|
74
88
|
specification_version: 4
|
75
89
|
summary: Symmetry axis from a point list.
|
76
90
|
test_files: []
|
91
|
+
has_rdoc:
|