cartesius 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ca7c08a027f0547ece43bf75d1d622aa7a59279
4
- data.tar.gz: 9b95391ad0010c8dd2cb1eb11a37933e2fa74b2f
3
+ metadata.gz: 69e7a9e2b6c6f4edb2bcc0cd73e5f909ee2eed07
4
+ data.tar.gz: 4eda3671a45184320a8485a0bd389df017bc8b8f
5
5
  SHA512:
6
- metadata.gz: 6b141b69ced00426c9c461e07bec394bacf3a625058c68ee101caa3f8886c21711342a920d2adfd29fc3fadc2094a108354ca004ad47a891a5830f306d4370d6
7
- data.tar.gz: b37537b3e28b9973c9d2981742cc52e6a2b181a1bc7342407af1e37d96fff7d343ed5199f4fce435c5d344909906a83d252541380e720a8cbb1d9c29bb5cb3f9
6
+ metadata.gz: 005e1721917eb39048995f4567a084c53ec9bdc66f2d95ca78ae2a827ae9bb19561747072ac257f697c46d2fc572e2a4175c897feedd929408a7d1fe438cbc8b
7
+ data.tar.gz: 01db7a237a5fa5edc13314dee6503120f9e232f65665e1cba2a3c9d830c1d9bbf68da95f367bc634e3af493d51b3e004eff202b9f4250665504e212643a8c8b0
@@ -0,0 +1,95 @@
1
+ module Cartesius
2
+ class Angle
3
+ NULL, RIGHT, FLAT, FULL = 0, 90, 180, 360
4
+ private_constant(:NULL)
5
+ private_constant(:RIGHT)
6
+ private_constant(:FLAT)
7
+ private_constant(:FULL)
8
+
9
+ def initialize(angle)
10
+ @angle = angle
11
+ end
12
+
13
+ private_class_method(:new)
14
+
15
+ def self.by_degrees(degrees)
16
+ new(degrees)
17
+ end
18
+
19
+ def self.by_radiants(radiants)
20
+ by_degrees(radiants * FLAT / Math::PI)
21
+ end
22
+
23
+ def self.by_lines(line1:, line2:)
24
+ raise ArgumentError.new('Lines must not be parallel!') if line1.parallel?(line2)
25
+ if line1.perpendicular?(line2)
26
+ [right, right]
27
+ else
28
+ acute = by_radiants(Math.atan(line1.slope - line2.slope / 1 + line1.slope * line2.slope).abs)
29
+ [acute, new(FLAT - acute.degrees)]
30
+ end
31
+ end
32
+
33
+ def self.null
34
+ by_degrees(NULL)
35
+ end
36
+
37
+ def self.right
38
+ by_degrees(RIGHT)
39
+ end
40
+
41
+ def self.flat
42
+ by_degrees(FLAT)
43
+ end
44
+
45
+ def self.full
46
+ by_degrees(FULL)
47
+ end
48
+
49
+ def degrees(precision = 3)
50
+ @angle.round(precision)
51
+ end
52
+
53
+ def radiants(precision = 3)
54
+ (@angle * Math::PI / FLAT).round(precision)
55
+ end
56
+
57
+ def null?
58
+ degrees == NULL
59
+ end
60
+
61
+ def acute?
62
+ degrees > NULL and degrees < RIGHT
63
+ end
64
+
65
+ def right?
66
+ degrees == RIGHT
67
+ end
68
+
69
+ def obtuse?
70
+ degrees > RIGHT and degrees < FLAT
71
+ end
72
+
73
+ def flat?
74
+ degrees == FLAT
75
+ end
76
+
77
+ def full?
78
+ degrees == FULL
79
+ end
80
+
81
+ def congruent?(angle)
82
+ angle.instance_of?(self.class) and
83
+ angle.degrees == degrees
84
+ end
85
+
86
+ alias_method(:eql?, :congruent?)
87
+
88
+ private
89
+
90
+ def hash
91
+ @angle.hash
92
+ end
93
+
94
+ end
95
+ end
@@ -37,7 +37,7 @@ module Cartesius
37
37
  [point3.x, point3.y, 1],
38
38
  [-(point1.x ** 2 + point1.y ** 2), -(point2.x ** 2 + point2.y ** 2), -(point3.x ** 2 + point3.y ** 2)]
39
39
  )
40
- self.new(x: alfa, y: beta, k: gamma)
40
+ new(x: alfa, y: beta, k: gamma)
41
41
  rescue
42
42
  raise ArgumentError.new('Invalid points!')
43
43
  end
@@ -59,17 +59,17 @@ module Cartesius
59
59
  end
60
60
 
61
61
  def congruent?(circumference)
62
- circumference.instance_of?(Circumference) and
63
- circumference.radius == self.radius
62
+ circumference.instance_of?(self.class) and
63
+ circumference.radius == radius
64
64
  end
65
65
 
66
66
  def == (circumference)
67
- circumference.instance_of?(Circumference) and
68
- circumference.center == self.center and circumference.radius == self.radius
67
+ circumference.instance_of?(self.class) and
68
+ circumference.center == center and circumference.radius == radius
69
69
  end
70
70
 
71
71
  def self.build_by(center, radius)
72
- self.new(x: -2 * center.x, y: -2 * center.y, k: center.x ** 2 + center.y ** 2 - radius.to_r ** 2)
72
+ new(x: -2 * center.x, y: -2 * center.y, k: center.x ** 2 + center.y ** 2 - radius.to_r ** 2)
73
73
  end
74
74
 
75
75
  private_class_method(:build_by)
@@ -151,17 +151,17 @@ module Cartesius
151
151
  end
152
152
 
153
153
  def congruent?(ellipse)
154
- ellipse.instance_of?(Ellipse) and
155
- ellipse.eccentricity == self.eccentricity
154
+ ellipse.instance_of?(self.class) and
155
+ ellipse.eccentricity == eccentricity
156
156
  end
157
157
 
158
158
  def == (ellipse)
159
- ellipse.instance_of?(Ellipse) and
160
- ellipse.focus1 == self.focus1 and ellipse.focus2 == self.focus2 and ellipse.distance == self.distance
159
+ ellipse.instance_of?(self.class) and
160
+ ellipse.focus1 == focus1 and ellipse.focus2 == focus2 and ellipse.distance == distance
161
161
  end
162
162
 
163
163
  def self.build_by(a2, b2, center)
164
- self.new(x2: b2, y2: a2, x: -2 * b2 * center.x, y: -2 * a2 * center.y, k: b2 * center.x ** 2 + a2 * center.y ** 2 - a2 * b2)
164
+ new(x2: b2, y2: a2, x: -2 * b2 * center.x, y: -2 * a2 * center.y, k: b2 * center.x ** 2 + a2 * center.y ** 2 - a2 * b2)
165
165
  end
166
166
 
167
167
  private_class_method(:build_by)
@@ -181,17 +181,17 @@ module Cartesius
181
181
  end
182
182
 
183
183
  def congruent?(hyperbola)
184
- hyperbola.instance_of?(Hyperbola) and
185
- hyperbola.eccentricity == self.eccentricity
184
+ hyperbola.instance_of?(self.class) and
185
+ hyperbola.eccentricity == eccentricity
186
186
  end
187
187
 
188
188
  def == (hyperbola)
189
- hyperbola.instance_of?(Hyperbola) and
190
- hyperbola.focus1 == self.focus1 and hyperbola.focus2 == self.focus2 and hyperbola.distance == self.distance
189
+ hyperbola.instance_of?(self.class) and
190
+ hyperbola.focus1 == focus1 and hyperbola.focus2 == focus2 and hyperbola.distance == distance
191
191
  end
192
192
 
193
193
  def self.build_by(a2, b2, center, position)
194
- self.new(x2: b2, y2: -a2, x: -2 * b2 * center.x, y: 2 * a2 * center.y, k: b2 * center.x ** 2 - a2 * center.y ** 2 + -position * a2 * b2)
194
+ new(x2: b2, y2: -a2, x: -2 * b2 * center.x, y: 2 * a2 * center.y, k: b2 * center.x ** 2 - a2 * center.y ** 2 + -position * a2 * b2)
195
195
  end
196
196
 
197
197
  private_class_method(:build_by)
@@ -7,6 +7,10 @@ module Cartesius
7
7
  VERTICAL_SLOPE = Float::INFINITY
8
8
  HORIZONTAL_SLOPE = 0
9
9
 
10
+ private_constant(:VERTICAL_SLOPE)
11
+ private_constant(:HORIZONTAL_SLOPE)
12
+
13
+ # equation type: dx + ey + f = 0
10
14
  def initialize(x:, y:, k:)
11
15
  @x_coeff, @y_coeff, @k_coeff = x.to_r, y.to_r, k.to_r
12
16
  validation
@@ -17,7 +21,7 @@ module Cartesius
17
21
  end
18
22
 
19
23
  def self.horizontal(known_term:)
20
- new(x: 0, y: 1, k: -known_term.to_r)
24
+ create(slope: HORIZONTAL_SLOPE, known_term: known_term)
21
25
  end
22
26
 
23
27
  def self.vertical(known_term:)
@@ -29,18 +33,16 @@ module Cartesius
29
33
  raise ArgumentError.new('Points must be different!')
30
34
  end
31
35
 
32
- if point1.y == point2.y
33
- return horizontal(known_term: point1.y)
34
- end
35
-
36
36
  if point1.x == point2.x
37
37
  return vertical(known_term: point1.x)
38
+ else
39
+ m, q = Cramer.solution2(
40
+ [point1.x, 1],
41
+ [point2.x, 1],
42
+ [point1.y, point2.y]
43
+ )
44
+ create(slope: m, known_term: q)
38
45
  end
39
-
40
- slope = Rational(point2.y - point1.y, point2.x - point1.x)
41
- known_term = point1.y - slope * point1.x
42
-
43
- create(slope: slope, known_term: known_term)
44
46
  end
45
47
 
46
48
  def self.x_axis
@@ -52,19 +54,27 @@ module Cartesius
52
54
  end
53
55
 
54
56
  def self.ascending_bisector
55
- new(x: -1, y: 1, k: 0)
57
+ create(slope: 1, known_term: 0)
56
58
  end
57
59
 
58
60
  def self.descending_bisector
59
- new(x: 1, y: 1, k: 0)
61
+ create(slope: -1, known_term: 0)
60
62
  end
61
63
 
62
64
  def slope
63
- @y_coeff == 0 ? VERTICAL_SLOPE : Rational(-@x_coeff, @y_coeff)
65
+ if @y_coeff.zero?
66
+ VERTICAL_SLOPE
67
+ else
68
+ numberfy(-@x_coeff, @y_coeff)
69
+ end
64
70
  end
65
71
 
66
72
  def known_term
67
- @y_coeff == 0 ? Rational(-@k_coeff, @x_coeff) : Rational(-@k_coeff, @y_coeff)
73
+ if @y_coeff.zero?
74
+ numberfy(-@k_coeff, @x_coeff)
75
+ else
76
+ numberfy(-@k_coeff, @y_coeff)
77
+ end
68
78
  end
69
79
 
70
80
  def x_axis?
@@ -92,65 +102,68 @@ module Cartesius
92
102
  end
93
103
 
94
104
  def inclined?
95
- (not horizontal?) and (not vertical?)
105
+ ascending? or descending?
96
106
  end
97
107
 
98
108
  def ascending?
99
- slope != VERTICAL_SLOPE and slope > 0
109
+ slope != VERTICAL_SLOPE and slope > HORIZONTAL_SLOPE
100
110
  end
101
111
 
102
112
  def descending?
103
- slope < 0
113
+ slope < HORIZONTAL_SLOPE
104
114
  end
105
115
 
106
116
  def parallel?(line)
107
- slope == line.slope
117
+ line.slope == slope
108
118
  end
109
119
 
110
120
  def perpendicular?(line)
111
- if slope == 0
112
- return line.slope == VERTICAL_SLOPE
113
- end
114
- if slope == VERTICAL_SLOPE
115
- return line.slope == 0
121
+ if line.slope == HORIZONTAL_SLOPE
122
+ slope == VERTICAL_SLOPE
123
+ elsif line.slope == VERTICAL_SLOPE
124
+ slope == HORIZONTAL_SLOPE
125
+ else
126
+ line.slope * slope == -1
116
127
  end
117
- slope * line.slope == -1
118
128
  end
119
129
 
120
130
  def include?(point)
121
131
  if vertical?
122
- return known_term == point.x
132
+ point.x == known_term
133
+ else
134
+ point.y == slope * point.x + known_term
123
135
  end
124
- point.y == slope * point.x + known_term
125
136
  end
126
137
 
127
138
  def x_intercept
128
- @x_coeff.zero? ? nil : -Rational(@k_coeff, @x_coeff)
139
+ unless @x_coeff.zero?
140
+ numberfy(-@k_coeff, @x_coeff)
141
+ end
129
142
  end
130
143
 
131
144
  def y_intercept
132
- @y_coeff.zero? ? nil : -Rational(@k_coeff, @y_coeff)
145
+ unless @y_coeff.zero?
146
+ numberfy(-@k_coeff, @y_coeff)
147
+ end
133
148
  end
134
149
 
135
150
  def to_equation
136
- equationfy(
137
- 'x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff
138
- )
151
+ equationfy('x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff)
139
152
  end
140
153
 
141
154
  def congruent?(line)
142
- line.instance_of?(Line)
155
+ line.instance_of?(self.class)
143
156
  end
144
157
 
145
158
  def == (line)
146
- line.instance_of?(Line) and
147
- line.slope == self.slope and line.known_term == self.known_term
159
+ line.instance_of?(self.class) and
160
+ line.slope == slope and line.known_term == known_term
148
161
  end
149
162
 
150
163
  private
151
164
 
152
165
  def validation
153
- if (@x_coeff == 0 and @y_coeff == 0)
166
+ if @x_coeff.zero? and @y_coeff.zero?
154
167
  raise ArgumentError.new('Invalid coefficients!')
155
168
  end
156
169
  end
@@ -28,7 +28,7 @@ module Cartesius
28
28
  b = -2 * a * focus.x
29
29
  c = a * (focus.x ** 2) + focus.y - Rational(1, 4 * a)
30
30
 
31
- self.new(x2: a, x: b, k: c)
31
+ new(x2: a, x: b, k: c)
32
32
  end
33
33
 
34
34
  def self.by_points(point1:, point2:, point3:)
@@ -39,7 +39,7 @@ module Cartesius
39
39
  [point1.y, point2.y, point3.y]
40
40
  )
41
41
 
42
- self.new(x2: a, x: b, k: c)
42
+ new(x2: a, x: b, k: c)
43
43
  rescue
44
44
  raise ArgumentError.new('Invalid points!')
45
45
  end
@@ -71,13 +71,13 @@ module Cartesius
71
71
  end
72
72
 
73
73
  def congruent?(parabola)
74
- parabola.instance_of?(Parabola) and
75
- parabola.eccentricity == self.eccentricity
74
+ parabola.instance_of?(self.class) and
75
+ parabola.eccentricity == eccentricity
76
76
  end
77
77
 
78
78
  def == (parabola)
79
- parabola.instance_of?(Parabola) and
80
- parabola.focus == self.focus and parabola.directrix == self.directrix
79
+ parabola.instance_of?(self.class) and
80
+ parabola.focus == focus and parabola.directrix == directrix
81
81
  end
82
82
 
83
83
  private
@@ -1,7 +1,6 @@
1
1
  require('cartesius/numerificator')
2
2
 
3
3
  module Cartesius
4
-
5
4
  class Point
6
5
  include Numerificator
7
6
  attr_reader :x, :y
@@ -15,36 +14,36 @@ module Cartesius
15
14
  end
16
15
 
17
16
  def self.distance(point1, point2)
18
- Math.sqrt((point1.x - point2.x)** 2 + (point1.y - point2.y)** 2)
17
+ Math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)
19
18
  end
20
19
 
21
20
  def origin?
22
21
  self == Point.origin
23
22
  end
24
23
 
25
- def distance_from(point)
26
- Math.sqrt((@x - point.x)** 2 + (@y - point.y)** 2)
27
- end
28
-
29
24
  def to_coordinates
30
25
  "(#{stringfy(x)}; #{stringfy(y)})"
31
26
  end
32
27
 
33
28
  def to_equation
34
- equationfy(
35
- 'x^2' => 1, 'y^2' => 1, 'x' => -2 * @x, 'y' => -2 * @y, '1' => @x ** 2 + @y ** 2
36
- )
29
+ equationfy('x^2' => 1, 'y^2' => 1, 'x' => -2 * @x, 'y' => -2 * @y, '1' => @x ** 2 + @y ** 2)
37
30
  end
38
31
 
39
32
  def congruent?(point)
40
- point.instance_of?(Point)
33
+ point.instance_of?(self.class)
41
34
  end
42
35
 
43
36
  def == (point)
44
- point.instance_of?(Point) and
37
+ point.instance_of?(self.class) and
45
38
  point.x == @x and point.y == @y
46
39
  end
47
40
 
48
- end
41
+ alias_method(:eql?, :==)
49
42
 
43
+ private
44
+
45
+ def hash
46
+ @x.hash ^ @y.hash
47
+ end
48
+ end
50
49
  end
@@ -4,6 +4,7 @@ require('cartesius/line')
4
4
  module Cartesius
5
5
 
6
6
  class Segment
7
+ include Numerificator
7
8
  extend Forwardable
8
9
  attr_reader :extreme1, :extreme2
9
10
  def_delegators(:@line, :horizontal?, :vertical?, :inclined?, :ascending?, :descending?)
@@ -24,8 +25,8 @@ module Cartesius
24
25
 
25
26
  def mid
26
27
  Point.new(
27
- x: Rational(@extreme1.x + @extreme2.x, 2),
28
- y: Rational(@extreme1.y + @extreme2.y, 2)
28
+ x: numberfy(@extreme1.x + @extreme2.x, 2),
29
+ y: numberfy(@extreme1.y + @extreme2.y, 2)
29
30
  )
30
31
  end
31
32
 
@@ -34,17 +35,15 @@ module Cartesius
34
35
  end
35
36
 
36
37
  def congruent?(segment)
37
- segment.instance_of?(Segment) and
38
+ segment.instance_of?(self.class) and
38
39
  segment.length == self.length
39
40
  end
40
41
 
41
42
  def == (segment)
42
- unless segment.instance_of?(Segment)
43
- return false
44
- end
45
-
46
- (segment.extreme1 == self.extreme1 and segment.extreme2 == self.extreme2) or
47
- (segment.extreme1 == self.extreme2 and segment.extreme2 == self.extreme1)
43
+ segment.instance_of?(self.class) and (
44
+ (segment.extreme1 == extreme1 and segment.extreme2 == extreme2) or
45
+ (segment.extreme1 == extreme2 and segment.extreme2 == extreme1)
46
+ )
48
47
  end
49
48
 
50
49
  private
@@ -0,0 +1,106 @@
1
+ require('cartesius/validator')
2
+ require('cartesius/segment')
3
+ require('cartesius/angle')
4
+
5
+ module Cartesius
6
+
7
+ class Triangle
8
+
9
+ def initialize(a:, b:, c:)
10
+ validation(a, b, c)
11
+ @v_a = a
12
+ @v_b = b
13
+ @v_c = c
14
+ @s_a = Segment.new(extreme1: @v_b, extreme2: @v_c)
15
+ @s_b = Segment.new(extreme1: @v_a, extreme2: @v_c)
16
+ @s_c = Segment.new(extreme1: @v_a, extreme2: @v_b)
17
+ @a_a = Angle.by_radiants(carnot(@s_a, @s_b, @s_c))
18
+ @a_b = Angle.by_radiants(carnot(@s_b, @s_a, @s_c))
19
+ @a_c = Angle.by_radiants(carnot(@s_c, @s_a, @s_b))
20
+ end
21
+
22
+ def angles
23
+ {a: @a_a, b: @a_b, c: @a_c}
24
+ end
25
+
26
+ def sides
27
+ {a: @s_a, b: @s_b, c: @s_c}
28
+ end
29
+
30
+ def vertices
31
+ {a: @v_a, b: @v_b, c: @v_c}
32
+ end
33
+
34
+ def rectangle?
35
+ angles.values.any?(&:right?)
36
+ end
37
+
38
+ def obtuse?
39
+ angles.values.any?(&:obtuse?)
40
+ end
41
+
42
+ def acute?
43
+ not rectangle? and not obtuse?
44
+ end
45
+
46
+ def equilateral?(precision = 2)
47
+ sides_congruent(precision) == 1
48
+ end
49
+
50
+ def isosceles?(precision = 2)
51
+ equilateral? or sides_congruent(precision) == 2
52
+ end
53
+
54
+ def scalene?(precision = 2)
55
+ sides_congruent(precision) == 3
56
+ end
57
+
58
+ def perimeter
59
+ sides.values.inject(0) {|sum, side| sum + side.length}
60
+ end
61
+
62
+ def area(precision = 2)
63
+ Rational(sides[:a].length * sides[:b].length * Math.sin(angles[:c].radiants), 2).round(precision)
64
+ end
65
+
66
+ def == (triangle)
67
+ triangle.instance_of?(self.class) and
68
+ triangle.vertices.values.to_set == vertices.values.to_set
69
+ end
70
+
71
+ def congruent? (triangle)
72
+ triangle.instance_of?(self.class) and
73
+ sides_length(triangle) == sides_length(self)
74
+ end
75
+
76
+ def similar?(triangle)
77
+ triangle.instance_of?(self.class) and
78
+ triangle.angles.values.to_set == angles.values.to_set
79
+ end
80
+
81
+ private
82
+
83
+ def carnot(side1, side2, side3)
84
+ cosine = Rational(
85
+ side2.length ** 2 + side3.length ** 2 - side1.length ** 2,
86
+ 2 * side2.length * side3.length
87
+ )
88
+ Math.acos(cosine)
89
+ end
90
+
91
+ def validation(a, b, c)
92
+ Validator.same_points([a, b, c])
93
+ Validator.aligned_points([a, b, c])
94
+ end
95
+
96
+ def sides_length(triangle)
97
+ triangle.sides.values.collect(&:length).sort
98
+ end
99
+
100
+ def sides_congruent(precision)
101
+ sides_length(self).map {|side| side.round(precision)}.uniq.count
102
+ end
103
+
104
+ end
105
+
106
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cartesius
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mauro Quaglia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-01 00:00:00.000000000 Z
11
+ date: 2018-01-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: The cartesian plan and its elements.
14
14
  email: mauroquaglia@libero.it
@@ -16,6 +16,7 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - lib/cartesius/angle.rb
19
20
  - lib/cartesius/circumference.rb
20
21
  - lib/cartesius/ellipse.rb
21
22
  - lib/cartesius/hyperbola.rb
@@ -23,6 +24,7 @@ files:
23
24
  - lib/cartesius/parabola.rb
24
25
  - lib/cartesius/point.rb
25
26
  - lib/cartesius/segment.rb
27
+ - lib/cartesius/triangle.rb
26
28
  homepage: https://github.com/MauroQuaglia/cartesius
27
29
  licenses:
28
30
  - MIT
@@ -35,7 +37,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
37
  requirements:
36
38
  - - ">="
37
39
  - !ruby/object:Gem::Version
38
- version: 2.4.0
40
+ version: 2.1.0
39
41
  required_rubygems_version: !ruby/object:Gem::Requirement
40
42
  requirements:
41
43
  - - ">="
@@ -43,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
45
  version: '0'
44
46
  requirements: []
45
47
  rubyforge_project:
46
- rubygems_version: 2.6.10
48
+ rubygems_version: 2.6.14
47
49
  signing_key:
48
50
  specification_version: 4
49
51
  summary: The cartesian coordinate system.