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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70556ef99614ea62c841ad75365fa26624e3df95
4
- data.tar.gz: f4c84a985efa555eab3412a7fa59d79897b3a3bf
3
+ metadata.gz: 7ac00b6ca3f12a6cf9ff5f8f34ef6e440bbc8e6d
4
+ data.tar.gz: 0da763b5764c2e3098aabce450ce456f1074f31d
5
5
  SHA512:
6
- metadata.gz: 96a80e0db01959db3a6009c66c41065eda379be0caffe82f543b064542ca061bf85945e99967d59cf4d26f7d12c9154e70d8c714e856eba5c3692f5c957ed6ec
7
- data.tar.gz: 8657f232c02798b274f3bdf79b251b477db057906a286f8e85783441fd122351c7aacf7d2f18d25921a8c96e7453d32b09f37999f9c90e998ec4372a89cc088d
6
+ metadata.gz: 4bad29fbf34ede0252c1db5ec83af74531e3aa1ea9c8c32ab723c287095ea0f0faf26215443cd88480e861e17ab73a4a401ca60db1e2e924b9bb5655771383fd
7
+ data.tar.gz: cabbcf950fb5891d326775907f34c86c1193dea00f94f0da442175a6420c77b8327af5d05861aa975a718b746f0832d867478b92615f43e895c9e845bcb434e9
@@ -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
- def vertical
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
- def on_me(x, y)
45
- if vertical
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
- fail 'There is no suitable pair of points.'
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
- @s2counter += 1
44
- points = @input.select { |p| !@two_points.include?(p) }
45
- @perpendicular_points_pairs_list = [@two_points.dup]
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
- @perpendicular_points_pairs_list[0] = pppair(points, line)
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
- # puts "\n Iterations:\n Step1 = #{@s1counter}\n Step2 = #{@s2counter}\n Step2Loop = #{@s2loopcounter}"
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.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-28 00:00:00.000000000 Z
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: