cartesius 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []