cartesius 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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 95fd724a37b3fd9e2e072f649cd34ffcd6ade1bd
4
+ data.tar.gz: 304ab894b81c52b1d02c63076be66879a20319f7
5
+ SHA512:
6
+ metadata.gz: 5f3b5b319332a590bcd796952e58328cbafa0b6857fea724bc796cbdc72520c715a167d063bf3510a5db5617cb52c49e55b75938c42c69c484a47a82a817471e
7
+ data.tar.gz: 3abcc3dc0cdc72e7878dbb1c55cf7c4d887f1fe464e228083e993e0d11f4952ee9769c9afaf34cfc69212e51f848f56c32bc08b808cf1f2c259b941006bdc50d
@@ -0,0 +1,95 @@
1
+ require('cartesius/line')
2
+ require('cartesius/determinator')
3
+ require('cartesius/numerificator')
4
+ require('cartesius/cramer')
5
+
6
+ module Cartesius
7
+
8
+ class Circumference
9
+ include Determinator, Numerificator
10
+
11
+ # Conic
12
+ # Conic equation type: x^2 + y^2 + dx + ey + f = 0
13
+ def initialize(x:, y:, k:)
14
+ @x2_coeff, @y2_coeff, @x_coeff, @y_coeff, @k_coeff = 1, 1, x.to_r, y.to_r, k.to_r
15
+ validation
16
+ end
17
+
18
+ def self.by_definition(focus:, radius:)
19
+ alfa = -2 * focus.x
20
+ beta = -2 * focus.y
21
+ gamma = focus.x ** 2 + focus.y ** 2 - radius.to_r ** 2
22
+
23
+ self.new(x: alfa, y: beta, k: gamma)
24
+ end
25
+
26
+ def self.by_canonical(focus:, radius:)
27
+ by_definition(focus: focus, radius: radius)
28
+ end
29
+
30
+ def self.by_points(point1:, point2:, point3:)
31
+ if point1 == point2 or point1 == point3 or point2 == point3
32
+ raise ArgumentError.new('Points must be distinct!')
33
+ end
34
+
35
+ line = Line.by_points(point1: point1, point2: point2)
36
+ if line.include?(point3)
37
+ raise ArgumentError.new('Points must not be aligned!')
38
+ end
39
+
40
+ alfa, beta, gamma = Cramer.solution3(
41
+ [point1.x, point1.y, 1],
42
+ [point2.x, point2.y, 1],
43
+ [point3.x, point3.y, 1],
44
+ [-(point1.x ** 2 + point1.y ** 2), -(point2.x ** 2 + point2.y ** 2), -(point3.x ** 2 + point3.y ** 2)]
45
+ )
46
+
47
+ self.new(x: alfa, y: beta, k: gamma)
48
+ end
49
+
50
+
51
+ def self.unitary
52
+ new(x: 0, y: 0, k: -1)
53
+ end
54
+
55
+ def center
56
+ Point.new(x: centrum[:xc], y: centrum[:yc])
57
+ end
58
+
59
+ def radius
60
+ Math.sqrt(a2)
61
+ end
62
+
63
+ def unitary?
64
+ self == Circumference.unitary
65
+ end
66
+
67
+ def == (circumference)
68
+ circumference.instance_of?(Circumference) and
69
+ circumference.center == self.center and circumference.radius == self.radius
70
+ end
71
+
72
+ def congruent?(circumference)
73
+ unless circumference.instance_of?(self.class)
74
+ return false
75
+ end
76
+
77
+ circumference.radius == self.radius
78
+ end
79
+
80
+ def to_equation
81
+ equationfy(
82
+ 'x^2' => @x2_coeff, 'y^2' => @y2_coeff, 'x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff
83
+ )
84
+ end
85
+
86
+ private
87
+
88
+ def validation
89
+ if determinator <= @k_coeff
90
+ raise ArgumentError.new('Invalid coefficients!')
91
+ end
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,173 @@
1
+ require('cartesius/segment')
2
+ require('cartesius/determinator')
3
+ require('cartesius/numerificator')
4
+ require('cartesius/cramer')
5
+
6
+ module Cartesius
7
+
8
+ class Ellipse
9
+ include Determinator, Numerificator
10
+
11
+ # Conic
12
+ # Conic equation type: ax^2 + by^2 + dx + ey + f = 0
13
+ def initialize(x2:, y2:, x:, y:, k:)
14
+ x2, y2, x, y, k = normalize(x2, y2, x, y, k)
15
+ @x2_coeff, @y2_coeff, @x_coeff, @y_coeff, @k_coeff = x2.to_r, y2.to_r, x.to_r, y.to_r, k.to_r
16
+ validation
17
+ end
18
+
19
+ def self.by_definition(focus1:, focus2:, distance:)
20
+ if focus1 == focus2
21
+ raise ArgumentError.new('Focus points must be different!')
22
+ end
23
+
24
+ unless focus1.aligned_horizontally_with?(focus2) or focus1.aligned_vertically_with?(focus2)
25
+ raise ArgumentError.new('Focus must be aligned to axis!')
26
+ end
27
+
28
+ focal_distance = Point.distance(focus1, focus2)
29
+ if distance <= focal_distance
30
+ raise ArgumentError.new('Sum of distances must be greater than focal distance!')
31
+ end
32
+
33
+ center = Segment.new(extreme1: focus1, extreme2: focus2).mid
34
+ c2 = Rational(focal_distance, 2) ** 2
35
+ if focus1.aligned_horizontally_with?(focus2)
36
+ a2 = Rational(distance, 2) ** 2
37
+ b2 = a2 - c2
38
+ end
39
+ if focus1.aligned_vertically_with?(focus2)
40
+ b2 = Rational(distance, 2) ** 2
41
+ a2 = b2 - c2
42
+ end
43
+
44
+ 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)
45
+ end
46
+
47
+ def self.by_canonical(center:, x_semi_axis:, y_semi_axis:)
48
+ if x_semi_axis <= 0 or y_semi_axis <= 0
49
+ raise ArgumentError.new('Semi axis length must be positive!')
50
+ end
51
+
52
+ if x_semi_axis == y_semi_axis
53
+ raise ArgumentError.new('Semi axis length must be different!')
54
+ end
55
+
56
+ b2 = y_semi_axis ** 2
57
+ a2 = x_semi_axis ** 2
58
+
59
+ 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)
60
+ end
61
+
62
+ def self.by_points(center:, point1:, point2:)
63
+ if center == point1 or center == point2 or point1 == point2
64
+ raise ArgumentError.new('Points must be different!')
65
+ end
66
+
67
+ shifted1 = Point.new(x: point1.x - center.x, y: point1.y - center.y)
68
+ shifted2 = Point.new(x: point2.x - center.x, y: point2.y - center.y)
69
+
70
+ begin
71
+ alfa, beta = Cramer.solution2(
72
+ [shifted1.x ** 2, shifted1.y ** 2],
73
+ [shifted2.x ** 2, shifted2.y ** 2],
74
+ [1, 1]
75
+ )
76
+ rescue
77
+ raise ArgumentError.new('No Ellipse for these points!')
78
+ end
79
+
80
+ a2 = Rational(1, alfa)
81
+ b2 = Rational(1, beta)
82
+
83
+ 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)
84
+ end
85
+
86
+ def focus1
87
+ if a2 > b2
88
+ Point.new(x: center.x + Math.sqrt(a2 - b2), y: center.y)
89
+ else
90
+ Point.new(x: center.x, y: center.y + Math.sqrt(b2 - a2))
91
+ end
92
+ end
93
+
94
+ def focus2
95
+ if a2 > b2
96
+ Point.new(x: center.x - Math.sqrt(a2 - b2), y: center.y)
97
+ else
98
+ Point.new(x: center.x, y: center.y - Math.sqrt(b2 - a2))
99
+ end
100
+ end
101
+
102
+ def focal_distance
103
+ Point.distance(focus1, focus2)
104
+ end
105
+
106
+ def center
107
+ Point.new(x: centrum[:xc], y: centrum[:yc])
108
+ end
109
+
110
+ def sum_of_distances
111
+ if a2 > b2
112
+ 2 * Math.sqrt(a2)
113
+ else
114
+ 2 * Math.sqrt(b2)
115
+ end
116
+ end
117
+
118
+ def x_semi_axis_length
119
+ Math.sqrt(a2)
120
+ end
121
+
122
+ def y_semi_axis_length
123
+ Math.sqrt(b2)
124
+ end
125
+
126
+ def major_semi_axis
127
+ [x_semi_axis_length, y_semi_axis_length].max
128
+ end
129
+
130
+ def minor_semi_axis
131
+ [x_semi_axis_length, y_semi_axis_length].min
132
+ end
133
+
134
+ def vertices
135
+ [
136
+ Point.new(x: center.x + x_semi_axis_length, y: center.y),
137
+ Point.new(x: center.x, y: center.y - y_semi_axis_length),
138
+ Point.new(x: center.x - x_semi_axis_length, y: center.y),
139
+ Point.new(x: center.x, y: center.y + y_semi_axis_length)
140
+ ]
141
+ end
142
+
143
+ def eccentricity
144
+ Rational(focal_distance, 2 * major_semi_axis)
145
+ end
146
+
147
+ def congruent?(ellipse)
148
+ ellipse.instance_of?(Ellipse) and
149
+ ellipse.eccentricity == self.eccentricity
150
+ end
151
+
152
+ def == (ellipse)
153
+ ellipse.instance_of?(Ellipse) and
154
+ ellipse.focus1 == self.focus1 and ellipse.focus2 == self.focus2 and ellipse.sum_of_distances == self.sum_of_distances
155
+ end
156
+
157
+ def to_equation
158
+ equationfy(
159
+ 'x^2' => @x2_coeff, 'y^2' => @y2_coeff, 'x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff
160
+ )
161
+ end
162
+
163
+ private
164
+
165
+ def validation
166
+ if @x2_coeff <= 0 or @y2_coeff <= 0 or @x2_coeff == @y2_coeff or determinator <= @k_coeff
167
+ raise ArgumentError.new('Invalid coefficients!')
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+ end
@@ -0,0 +1,168 @@
1
+ require('cartesius/segment')
2
+ require('cartesius/determinator')
3
+ require('cartesius/numerificator')
4
+ require('cartesius/cramer')
5
+
6
+ module Cartesius
7
+
8
+ class Hyperbola
9
+ include Determinator, Numerificator
10
+
11
+ # Conic
12
+ # Conic equation type: ax^2 + by^2 + dx + ey + f = 0
13
+ def initialize(x2:, y2:, x:, y:, k:)
14
+ x2, y2, x, y, k = normalize(x2, y2, x, y, k)
15
+ @x2_coeff, @y2_coeff, @x_coeff, @y_coeff, @k_coeff = x2.to_r, y2.to_r, x.to_r, y.to_r, k.to_r
16
+ validation
17
+ end
18
+
19
+ def self.by_definition(focus1:, focus2:, distance:)
20
+ if focus1 == focus2
21
+ raise ArgumentError.new('Focus points must be different!')
22
+ end
23
+
24
+ unless focus1.aligned_horizontally_with?(focus2) or focus1.aligned_vertically_with?(focus2)
25
+ raise ArgumentError.new('Focus must be aligned to axis!')
26
+ end
27
+
28
+ focal_distance = Point.distance(focus1, focus2)
29
+ if distance >= focal_distance
30
+ raise ArgumentError.new('Difference of distances must be less than focal distance!')
31
+ end
32
+
33
+ center = Segment.new(extreme1: focus1, extreme2: focus2).mid
34
+ c2 = Rational(focal_distance, 2) ** 2
35
+ if focus1.aligned_horizontally_with?(focus2)
36
+ a2 = Rational(distance, 2) ** 2
37
+ b2 = c2 - a2
38
+ position = 1
39
+ end
40
+ if focus1.aligned_vertically_with?(focus2)
41
+ b2 = Rational(distance, 2) ** 2
42
+ a2 = c2 - b2
43
+ position = -1
44
+ end
45
+
46
+ 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)
47
+ end
48
+
49
+ def self.by_canonical(center:, transverse_axis:, not_transverse_axis:, position:)
50
+ if transverse_axis <= 0 or not_transverse_axis <= 0
51
+ raise ArgumentError.new('Axis length must be positive!')
52
+ end
53
+
54
+ unless [-1, 1].include?(position)
55
+ raise ArgumentError.new('Position must be up or right!')
56
+ end
57
+
58
+ if position == -1
59
+ a2 = not_transverse_axis ** 2
60
+ b2 = transverse_axis ** 2
61
+ end
62
+
63
+ if position == 1
64
+ a2 = transverse_axis ** 2
65
+ b2 = not_transverse_axis ** 2
66
+ end
67
+
68
+ 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)
69
+ end
70
+
71
+ def self.by_points(center:, vertex:, point:)
72
+ if center == vertex or center == point or vertex == point
73
+ raise ArgumentError.new('Points must be different!')
74
+ end
75
+
76
+ unless vertex.aligned_horizontally_with?(center) or vertex.aligned_vertically_with?(center)
77
+ raise ArgumentError.new('Vertex must be aligned with center!')
78
+ end
79
+
80
+ if vertex.aligned_horizontally_with?(center)
81
+ position = 1
82
+ end
83
+
84
+ if vertex.aligned_vertically_with?(center)
85
+ position = -1
86
+ end
87
+
88
+ shifted1 = Point.new(x: vertex.x - center.x, y: vertex.y - center.y)
89
+ shifted2 = Point.new(x: point.x - center.x, y: point.y - center.y)
90
+
91
+ begin
92
+ alfa, beta = Cramer.solution2(
93
+ [shifted1.x ** 2, shifted1.y ** 2],
94
+ [shifted2.x ** 2, shifted2.y ** 2],
95
+ [1, 1]
96
+ )
97
+ rescue
98
+ raise ArgumentError.new('No Hyperbola for these points!')
99
+ end
100
+
101
+ a2 = Rational(1, alfa)
102
+ b2 = Rational(1, beta)
103
+
104
+ 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)
105
+ end
106
+
107
+ def focus1
108
+ if position == 1
109
+ return Point.new(x: center.x + Math.sqrt(a2 + b2), y: center.y)
110
+ end
111
+ if position == -1
112
+ return Point.new(x: center.x, y: center.y + Math.sqrt(a2 + b2))
113
+ end
114
+ end
115
+
116
+ def focus2
117
+ if position == 1
118
+ return Point.new(x: center.x - Math.sqrt(a2 + b2), y: center.y)
119
+ end
120
+ if position == -1
121
+ return Point.new(x: center.x, y: center.y - Math.sqrt(a2 + b2))
122
+ end
123
+ end
124
+
125
+ def focal_distance
126
+ Point.distance(focus1, focus2)
127
+ end
128
+
129
+ def center
130
+ Point.new(x: centrum[:xc], y: centrum[:yc])
131
+ end
132
+
133
+ def difference_of_distances
134
+ if position == 1
135
+ return 2 * Math.sqrt(a2)
136
+ end
137
+ if position == -1
138
+ return 2 * Math.sqrt(b2)
139
+ end
140
+ end
141
+
142
+ def congruent?(hyperbola)
143
+ hyperbola.instance_of?(Hyperbola) and
144
+ hyperbola.eccentricity == self.eccentricity
145
+ end
146
+
147
+ def == (hyperbola)
148
+ hyperbola.instance_of?(Hyperbola) and
149
+ hyperbola.focus1 == self.focus1 and hyperbola.focus2 == self.focus2 and hyperbola.difference_of_distances == self.difference_of_distances
150
+ end
151
+
152
+ private
153
+
154
+ def validation
155
+
156
+ if signum(@x2_coeff * @y2_coeff) >= 0 or determinator == @k_coeff
157
+ raise ArgumentError.new('Invalid coefficients!')
158
+ end
159
+
160
+ end
161
+
162
+ def position
163
+ signum(determinator - @k_coeff)
164
+ end
165
+
166
+ end
167
+
168
+ end
@@ -0,0 +1,159 @@
1
+ require('cartesius/numerificator')
2
+
3
+ module Cartesius
4
+
5
+ class Line
6
+ include Numerificator
7
+ VERTICAL_SLOPE = Float::INFINITY
8
+ HORIZONTAL_SLOPE = 0
9
+
10
+ def initialize(x:, y:, k:)
11
+ @x_coeff, @y_coeff, @k_coeff = x.to_r, y.to_r, k.to_r
12
+ validation
13
+ end
14
+
15
+ def self.create(slope:, known_term:)
16
+ new(x: -slope.to_r, y: 1, k: -known_term.to_r)
17
+ end
18
+
19
+ def self.horizontal(known_term:)
20
+ new(x: 0, y: 1, k: -known_term.to_r)
21
+ end
22
+
23
+ def self.vertical(known_term:)
24
+ new(x: 1, y: 0, k: -known_term.to_r)
25
+ end
26
+
27
+ def self.by_points(point1:, point2:)
28
+ if point1 == point2
29
+ raise ArgumentError.new('Points must be different!')
30
+ end
31
+
32
+ if point1.aligned_horizontally_with?(point2)
33
+ return horizontal(known_term: point1.y)
34
+ end
35
+
36
+ if point1.aligned_vertically_with?(point2)
37
+ return vertical(known_term: point1.x)
38
+ 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
+ end
45
+
46
+ def self.x_axis
47
+ horizontal(known_term: 0)
48
+ end
49
+
50
+ def self.y_axis
51
+ vertical(known_term: 0)
52
+ end
53
+
54
+ def self.ascending_bisector
55
+ new(x: -1, y: 1, k: 0)
56
+ end
57
+
58
+ def self.descending_bisector
59
+ new(x: 1, y: 1, k: 0)
60
+ end
61
+
62
+ def slope
63
+ @y_coeff == 0 ? VERTICAL_SLOPE : Rational(-@x_coeff, @y_coeff)
64
+ end
65
+
66
+ def known_term
67
+ @y_coeff == 0 ? Rational(-@k_coeff, @x_coeff) : Rational(-@k_coeff, @y_coeff)
68
+ end
69
+
70
+ def x_axis?
71
+ self == Line.x_axis
72
+ end
73
+
74
+ def y_axis?
75
+ self == Line.y_axis
76
+ end
77
+
78
+ def ascending_bisector?
79
+ self == Line.ascending_bisector
80
+ end
81
+
82
+ def descending_bisector?
83
+ self == Line.descending_bisector
84
+ end
85
+
86
+ def horizontal?
87
+ slope == HORIZONTAL_SLOPE
88
+ end
89
+
90
+ def vertical?
91
+ slope == VERTICAL_SLOPE
92
+ end
93
+
94
+ def inclined?
95
+ (not horizontal?) and (not vertical?)
96
+ end
97
+
98
+ def ascending?
99
+ slope != VERTICAL_SLOPE and slope > 0
100
+ end
101
+
102
+ def descending?
103
+ slope < 0
104
+ end
105
+
106
+ def parallel?(line)
107
+ slope == line.slope
108
+ end
109
+
110
+ 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
116
+ end
117
+ slope * line.slope == -1
118
+ end
119
+
120
+ def include?(point)
121
+ if vertical?
122
+ return known_term == point.x
123
+ end
124
+ point.y == slope * point.x + known_term
125
+ end
126
+
127
+ def x_intercept
128
+ @x_coeff.zero? ? nil : -Rational(@k_coeff, @x_coeff)
129
+ end
130
+
131
+ def y_intercept
132
+ @y_coeff.zero? ? nil : -Rational(@k_coeff, @y_coeff)
133
+ end
134
+
135
+ def to_equation
136
+ equationfy(
137
+ 'x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff
138
+ )
139
+ end
140
+
141
+ def congruent?(line)
142
+ line.instance_of?(Line)
143
+ end
144
+
145
+ def == (line)
146
+ congruent?(line) and
147
+ line.slope == self.slope and line.known_term == self.known_term
148
+ end
149
+
150
+ private
151
+
152
+ def validation
153
+ if (@x_coeff == 0 and @y_coeff == 0)
154
+ raise ArgumentError.new('Invalid coefficients!')
155
+ end
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,118 @@
1
+ require('cartesius/point')
2
+ require('cartesius/line')
3
+ require('cartesius/numerificator')
4
+ require('cartesius/cramer')
5
+
6
+ module Cartesius
7
+
8
+ class Parabola
9
+ include Numerificator
10
+
11
+ # Conic
12
+ # Conic equation type: ax^2 + dx - y + f = 0
13
+ def initialize(x2:, x:, k:)
14
+ @x2_coeff, @x_coeff, @y_coeff, @k_coeff = x2.to_r, x.to_r, -1, k.to_r
15
+ validation
16
+ end
17
+
18
+ def self.unitary_convex
19
+ new(x2: 1, x: 0, k: 0)
20
+ end
21
+
22
+ def self.unitary_concave
23
+ new(x2: -1, x: 0, k: 0)
24
+ end
25
+
26
+ def self.by_definition(directrix:, focus:)
27
+ if directrix.include?(focus)
28
+ raise ArgumentError.new('Focus belongs to directrix!')
29
+ end
30
+
31
+ unless directrix.horizontal?
32
+ raise ArgumentError.new('Directrix is not parallel to x-axis!')
33
+ end
34
+
35
+ a = Rational(1, 2 * (focus.y - directrix.y_intercept))
36
+ b = -2 * a * focus.x
37
+ c = a * (focus.x ** 2) + focus.y - Rational(1, 4 * a)
38
+
39
+ self.new(x2: -a, x: -b, k: -c)
40
+ end
41
+
42
+ def self.by_canonical(focus:, gap:)
43
+ if gap.zero?
44
+ raise ArgumentError.new('Gap must not be zero!')
45
+ end
46
+
47
+ a = gap
48
+ b = -2 * a * focus.x
49
+ c = (focus.x ** 2) + focus.y - Rational(1, 4 * a)
50
+
51
+ self.new(x2: -a, x: -b, k: -c)
52
+ end
53
+
54
+ def self.by_points(point1:, point2:, point3:)
55
+
56
+ if point1 == point2 or point1 == point3 or point2 == point3
57
+ raise ArgumentError.new('Points must be distinct!')
58
+ end
59
+
60
+ a, b, c = Cramer.solution3(
61
+ [point1.x ** 2, point1.x, 1],
62
+ [point2.x ** 2, point2.x, 1],
63
+ [point3.x ** 2, point3.x, 1],
64
+ [point1.y, point2.y, point3.y]
65
+ )
66
+
67
+ self.new(x2: -a, x: -b, k: -c)
68
+ end
69
+
70
+ def directrix
71
+ Line.horizontal(known_term: Rational(-delta - 1, 4 * @x2_coeff))
72
+ end
73
+
74
+ def focus
75
+ Point.new(x: Rational(-@x_coeff, 2 * @x2_coeff), y: Rational(1 - delta, 4 * @x2_coeff))
76
+ end
77
+
78
+ def vertex
79
+ Point.new(x: Rational(-@x_coeff, 2 * @x2_coeff), y: Rational(-delta, 4 * @x2_coeff))
80
+ end
81
+
82
+ def symmetry_axis
83
+ Line.vertical(known_term: Rational(-@x_coeff, 2* @x2_coeff))
84
+ end
85
+
86
+ def unitary_convex?
87
+ self == Parabola.unitary_convex
88
+ end
89
+
90
+ def unitary_concave?
91
+ self == Parabola.unitary_concave
92
+ end
93
+
94
+ def == (parabola)
95
+ parabola.instance_of?(Parabola) and
96
+ parabola.focus == self.focus and parabola.directrix == self.directrix
97
+ end
98
+
99
+ def to_equation
100
+ equationfy(
101
+ 'x^2' => @x2_coeff, 'x' => @x_coeff, 'y' => @y_coeff, '1' => @k_coeff
102
+ )
103
+ end
104
+
105
+ private
106
+
107
+ def validation
108
+ if @x2_coeff == 0
109
+ raise ArgumentError.new('Invalid coefficients!')
110
+ end
111
+ end
112
+
113
+ def delta
114
+ (@x_coeff ** 2) - (4 * @x2_coeff * @k_coeff)
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,62 @@
1
+ require('cartesius/numerificator')
2
+
3
+ module Cartesius
4
+
5
+ class Point
6
+ include Numerificator
7
+ attr_reader :x, :y
8
+
9
+ def initialize(x:, y:)
10
+ @x, @y = x.to_r, y.to_r
11
+ end
12
+
13
+ def self.origin
14
+ new(x: 0, y: 0)
15
+ end
16
+
17
+ def self.distance(point1, point2)
18
+ Math.sqrt(
19
+ (point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2
20
+ )
21
+ end
22
+
23
+ def origin?
24
+ self == Point.origin
25
+ end
26
+
27
+ def aligned_horizontally_with?(point)
28
+ @y == point.y
29
+ end
30
+
31
+ def aligned_vertically_with?(point)
32
+ @x == point.x
33
+ end
34
+
35
+ def distance_from(point)
36
+ Math.sqrt(
37
+ (@x - point.x) ** 2 + (@y - point.y) ** 2
38
+ )
39
+ end
40
+
41
+ def to_coordinates
42
+ "(#{stringfy(x)}; #{stringfy(y)})"
43
+ end
44
+
45
+ def to_equation
46
+ equationfy(
47
+ 'x^2' => 1, 'y^2' => 1, 'x' => -2 * @x, 'y' => -2 * @y, '1' => @x ** 2 + @y ** 2
48
+ )
49
+ end
50
+
51
+ def congruent?(point)
52
+ point.instance_of?(Point)
53
+ end
54
+
55
+ def == (point)
56
+ congruent?(point) and
57
+ point.x == @x and point.y == @y
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,60 @@
1
+ require('cartesius/point')
2
+ require('cartesius/line')
3
+
4
+ module Cartesius
5
+
6
+ class Segment
7
+ extend Forwardable
8
+ attr_reader :extreme1, :extreme2
9
+ def_delegators(:@line, :horizontal?, :vertical?, :inclined?, :ascending?, :descending?)
10
+
11
+ def initialize(extreme1:, extreme2:)
12
+ @extreme1, @extreme2 = extreme1, extreme2
13
+ validation
14
+ @line = Line.by_points(point1: @extreme1, point2: @extreme2)
15
+ end
16
+
17
+ def to_line
18
+ @line
19
+ end
20
+
21
+ def length
22
+ Point.distance(@extreme1, @extreme2)
23
+ end
24
+
25
+ def mid
26
+ Point.new(
27
+ x: Rational(@extreme1.x + @extreme2.x, 2),
28
+ y: Rational(@extreme1.y + @extreme2.y, 2)
29
+ )
30
+ end
31
+
32
+ def extremes
33
+ [@extreme1, @extreme2]
34
+ end
35
+
36
+ def congruent?(segment)
37
+ segment.instance_of?(Segment) and
38
+ segment.length == self.length
39
+ end
40
+
41
+ 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)
48
+ end
49
+
50
+ private
51
+
52
+ def validation
53
+ if @extreme1 == @extreme2
54
+ raise ArgumentError.new('Extremes cannot be the same!')
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cartesius
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mauro Quaglia
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: The cartesian plan and its elements.
14
+ email: mauroquaglia@libero.it
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/cartesius/circumference.rb
20
+ - lib/cartesius/ellipse.rb
21
+ - lib/cartesius/hyperbola.rb
22
+ - lib/cartesius/line.rb
23
+ - lib/cartesius/parabola.rb
24
+ - lib/cartesius/point.rb
25
+ - lib/cartesius/segment.rb
26
+ homepage: https://github.com/MauroQuaglia/cartesius
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.6.13
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: The cartesian coordinate system.
50
+ test_files: []