silicium 0.0.14 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +4 -0
- data/.gitignore +13 -11
- data/.rakeTasks +8 -0
- data/.travis.yml +17 -3
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +8 -4
- data/LICENSE.txt +21 -21
- data/Makefile +269 -0
- data/README.md +588 -44
- data/Rakefile +17 -10
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/docs/Object.html +117 -0
- data/docs/README_md.html +142 -0
- data/docs/Silicium/Combinatorics.html +270 -0
- data/docs/Silicium/Dice/Polyhedron.html +315 -0
- data/docs/Silicium/Dice/PolyhedronSet.html +321 -0
- data/docs/Silicium/Dice.html +99 -0
- data/docs/Silicium/Error.html +106 -0
- data/docs/Silicium/Geometry/Line2dCanon.html +243 -0
- data/docs/Silicium/Geometry/VariablesOrderException.html +106 -0
- data/docs/Silicium/Geometry.html +940 -0
- data/docs/Silicium/GraphVisualizer.html +226 -0
- data/docs/Silicium/Graphs/GraphError.html +106 -0
- data/docs/Silicium/Graphs/OrientedGraph.html +901 -0
- data/docs/Silicium/Graphs/UnorientedGraph.html +237 -0
- data/docs/Silicium/Graphs.html +374 -0
- data/docs/Silicium/IntegralDoesntExistError.html +106 -0
- data/docs/Silicium/NumericalIntegration.html +521 -0
- data/docs/Silicium/Optimization.html +629 -0
- data/docs/Silicium/Plotter/Image.html +297 -0
- data/docs/Silicium/Plotter.html +186 -0
- data/docs/Silicium.html +101 -0
- data/docs/created.rid +9 -0
- data/docs/css/fonts.css +167 -0
- data/docs/css/rdoc.css +619 -0
- data/docs/fonts/Lato-Light.ttf +0 -0
- data/docs/fonts/Lato-LightItalic.ttf +0 -0
- data/docs/fonts/Lato-Regular.ttf +0 -0
- data/docs/fonts/Lato-RegularItalic.ttf +0 -0
- data/docs/fonts/SourceCodePro-Bold.ttf +0 -0
- data/docs/fonts/SourceCodePro-Regular.ttf +0 -0
- data/docs/images/add.png +0 -0
- data/docs/images/arrow_up.png +0 -0
- data/docs/images/brick.png +0 -0
- data/docs/images/brick_link.png +0 -0
- data/docs/images/bug.png +0 -0
- data/docs/images/bullet_black.png +0 -0
- data/docs/images/bullet_toggle_minus.png +0 -0
- data/docs/images/bullet_toggle_plus.png +0 -0
- data/docs/images/date.png +0 -0
- data/docs/images/delete.png +0 -0
- data/docs/images/find.png +0 -0
- data/docs/images/loadingAnimation.gif +0 -0
- data/docs/images/macFFBgHack.png +0 -0
- data/docs/images/package.png +0 -0
- data/docs/images/page_green.png +0 -0
- data/docs/images/page_white_text.png +0 -0
- data/docs/images/page_white_width.png +0 -0
- data/docs/images/plugin.png +0 -0
- data/docs/images/ruby.png +0 -0
- data/docs/images/tag_blue.png +0 -0
- data/docs/images/tag_green.png +0 -0
- data/docs/images/transparent.png +0 -0
- data/docs/images/wrench.png +0 -0
- data/docs/images/wrench_orange.png +0 -0
- data/docs/images/zoom.png +0 -0
- data/docs/index.html +134 -0
- data/docs/js/darkfish.js +84 -0
- data/docs/js/navigation.js +105 -0
- data/docs/js/navigation.js.gz +0 -0
- data/docs/js/search.js +110 -0
- data/docs/js/search_index.js +1 -0
- data/docs/js/search_index.js.gz +0 -0
- data/docs/js/searcher.js +229 -0
- data/docs/js/searcher.js.gz +0 -0
- data/docs/table_of_contents.html +697 -0
- data/lib/algebra.rb +452 -0
- data/lib/algebra_diff.rb +258 -0
- data/lib/geometry/figure.rb +62 -0
- data/lib/geometry.rb +290 -0
- data/lib/geometry3d.rb +270 -0
- data/lib/graph/dfs.rb +41 -0
- data/lib/graph/kruskal.rb +36 -0
- data/lib/graph/scc.rb +97 -0
- data/lib/graph.rb +350 -0
- data/lib/graph_visualizer.rb +286 -0
- data/lib/ml_algorithms.rb +181 -0
- data/lib/numerical_integration.rb +184 -0
- data/lib/optimization.rb +208 -0
- data/lib/plotter.rb +258 -0
- data/lib/polynomial_division.rb +132 -0
- data/lib/polynomial_interpolation.rb +94 -0
- data/lib/regression.rb +120 -0
- data/lib/silicium/adding.rb +37 -0
- data/lib/silicium/conversions.rb +23 -0
- data/lib/silicium/multi.rb +82 -0
- data/lib/silicium/sparse.rb +76 -0
- data/lib/silicium/sugar.rb +37 -0
- data/lib/silicium/trans.rb +26 -0
- data/lib/silicium/version.rb +3 -3
- data/lib/silicium.rb +29 -6
- data/lib/theory_of_probability.rb +240 -0
- data/lib/topological_sort.rb +50 -0
- data/oriented_graph.png +0 -0
- data/plot.png +0 -0
- data/silicium.gemspec +4 -3
- metadata +122 -12
@@ -0,0 +1,62 @@
|
|
1
|
+
module Silicium
|
2
|
+
|
3
|
+
module Geometry
|
4
|
+
class Figure
|
5
|
+
include Geometry
|
6
|
+
end
|
7
|
+
|
8
|
+
class Triangle < Figure
|
9
|
+
|
10
|
+
def initialize(p1, p2, p3)
|
11
|
+
s_p1p2 = distance_point_to_point2d(p1, p2)
|
12
|
+
s_p1p3 = distance_point_to_point2d(p1, p3)
|
13
|
+
s_p2p3 = distance_point_to_point2d(p2, p3)
|
14
|
+
if s_p1p2 + s_p2p3 <= s_p1p3 || s_p1p2 + s_p1p3 <= s_p2p3 || s_p2p3 + s_p1p3 <= s_p1p2
|
15
|
+
raise ArgumentError, 'Triangle does not exist'
|
16
|
+
else
|
17
|
+
@side_p1p2 = s_p1p2
|
18
|
+
@side_p1p3 = s_p1p3
|
19
|
+
@side_p2p3 = s_p2p3
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def perimeter
|
24
|
+
@side_p1p2 + @side_p1p3 + @side_p2p3
|
25
|
+
end
|
26
|
+
|
27
|
+
def area
|
28
|
+
half_perimeter = perimeter / 2.0
|
29
|
+
Math.sqrt(half_perimeter * (half_perimeter - @side_p1p2) * (half_perimeter - @side_p2p3) * (half_perimeter - @side_p1p3))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
##
|
35
|
+
# TODO: Add a description
|
36
|
+
class Rectangle < Figure
|
37
|
+
|
38
|
+
def initialize(p1, p2, p3, p4)
|
39
|
+
raise ArgumentError, 'This is not a rectangle.' unless valid?(p1, p2, p3, p4)
|
40
|
+
|
41
|
+
@side1 = distance_point_to_point2d(p1, p2)
|
42
|
+
@side2 = distance_point_to_point2d(p2, p3)
|
43
|
+
@side3 = distance_point_to_point2d(p3, p4)
|
44
|
+
@side4 = distance_point_to_point2d(p4, p1)
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Checks if input points form rectangle
|
49
|
+
def valid?(p1, p2, p3, p4)
|
50
|
+
distance_point_to_point2d(p1, p3) == distance_point_to_point2d(p2, p4)
|
51
|
+
end
|
52
|
+
|
53
|
+
def perimeter
|
54
|
+
@side1 + @side2 + @side3 + @side4
|
55
|
+
end
|
56
|
+
|
57
|
+
def area
|
58
|
+
@side1 * @side2
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/geometry.rb
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'geometry/figure'
|
4
|
+
|
5
|
+
module Silicium
|
6
|
+
|
7
|
+
module Geometry
|
8
|
+
##
|
9
|
+
# Represents a point as two coordinates
|
10
|
+
# in two-dimensional space
|
11
|
+
Point = Struct.new(:x, :y)
|
12
|
+
|
13
|
+
##
|
14
|
+
# Calculates the distance from given points in two-dimensional space
|
15
|
+
def distance_point_to_point2d(a, b)
|
16
|
+
Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Class represents a line as equation Ax + By + C = 0
|
21
|
+
# in two-dimensional space
|
22
|
+
class Line2dCanon
|
23
|
+
attr_reader :x_coefficient
|
24
|
+
attr_reader :y_coefficient
|
25
|
+
attr_reader :free_coefficient
|
26
|
+
|
27
|
+
##
|
28
|
+
# Initializes with two objects of type Point
|
29
|
+
def initialize(point1, point2)
|
30
|
+
raise ArgumentError, 'You need 2 different points' if point1.x.equal?(point2.x) && point1.y.equal?(point2.y)
|
31
|
+
if point1.x.equal?(point2.x)
|
32
|
+
@x_coefficient = 1
|
33
|
+
@y_coefficient = 0
|
34
|
+
@free_coefficient = - point1.x
|
35
|
+
else
|
36
|
+
slope_point = (point2.y - point1.y) / (point2.x - point1.x)
|
37
|
+
@x_coefficient = -slope_point
|
38
|
+
@y_coefficient = 1
|
39
|
+
@free_coefficient = - point1.y + slope_point * point1.x
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Initializes with coefficients
|
44
|
+
def initialize_with_coefficients(a, b, c)
|
45
|
+
raise ArgumentError, 'All coefficients cannot be 0 ' if a.equal?(0) && b.equal?(0) && (c.equal?(0) || !c.equal?(0))
|
46
|
+
|
47
|
+
@x_coefficient = a
|
48
|
+
@y_coefficient = b
|
49
|
+
@free_coefficient = c
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Checks the point lies on the line or not
|
54
|
+
def point_is_on_line?(point)
|
55
|
+
((@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient) - 0.0).abs < 0.0001
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks if two lines are parallel
|
59
|
+
def parallel?(other_line)
|
60
|
+
@x_coefficient.equal?(other_line.x_coefficient) && @y_coefficient.equal?(other_line.y_coefficient)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Checks if two lines are intersecting
|
65
|
+
def intersecting?(other_line)
|
66
|
+
@x_coefficient != other_line.x_coefficient || @y_coefficient != other_line.y_coefficient
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Checks if two lines are perpendicular
|
71
|
+
def perpendicular?(other_line)
|
72
|
+
(@x_coefficient * other_line.x_coefficient).equal?(- @y_coefficient * other_line.y_coefficient)
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Checking if the point is on a segment
|
77
|
+
def check_point_on_segment(point)
|
78
|
+
(@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient) - 0.0 <= 0.0001
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Returns a point of intersection of two lines
|
83
|
+
# If not intersecting returns nil
|
84
|
+
def intersection_point(other_line)
|
85
|
+
return nil unless intersecting?(other_line)
|
86
|
+
|
87
|
+
divisor = @x_coefficient * other_line.y_coefficient - other_line.x_coefficient * @y_coefficient
|
88
|
+
x = (@y_coefficient * other_line.free_coefficient - other_line.y_coefficient * @free_coefficient) / divisor
|
89
|
+
y = (@free_coefficient * other_line.x_coefficient - other_line.free_coefficient * @x_coefficient) / divisor
|
90
|
+
Point.new(x, y)
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Returns distance between lines
|
95
|
+
def distance_to_line(other_line)
|
96
|
+
return 0 if intersecting?(other_line)
|
97
|
+
|
98
|
+
(@free_coefficient - other_line.free_coefficient).abs / Math.sqrt(@x_coefficient**2 + @y_coefficient**2)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# The distance from a point to a line on a plane
|
103
|
+
# return 0 if the equation does not define a line.
|
104
|
+
def distance_point_to_line(point)
|
105
|
+
return 0 if @x_coefficient.eql?(0) && @y_coefficient.eql?(0)
|
106
|
+
|
107
|
+
res = (@x_coefficient * point.x + @y_coefficient * point.y + @free_coefficient).abs
|
108
|
+
res / Math.sqrt(@x_coefficient**2 + @y_coefficient**2).to_f
|
109
|
+
end
|
110
|
+
##
|
111
|
+
# Check if array of points is on the same line
|
112
|
+
def array_of_points_is_on_line(array)
|
113
|
+
raise ArgumentError, 'Array is empty!' if array.length == 0
|
114
|
+
res = Array.new
|
115
|
+
for i in 0..array.size-1 do
|
116
|
+
res.push(point_is_on_line?(array[i]))
|
117
|
+
end
|
118
|
+
res
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# The distance between parallel lines
|
123
|
+
def distance_between_parallel_lines(other_line)
|
124
|
+
raise ArgumentError, 'Lines are not parallel' if !parallel?(other_line)
|
125
|
+
|
126
|
+
(other_line.free_coefficient - @free_coefficient).abs / Math.sqrt(@x_coefficient**2 + @y_coefficient**2)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Function for checking sign of number
|
132
|
+
def sign(integer)
|
133
|
+
integer >= 0 ? 1 : -1
|
134
|
+
end
|
135
|
+
# The distance from a point to a line on a plane
|
136
|
+
# The line is defined by two points
|
137
|
+
# https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
|
138
|
+
def distance_point_line2d(p1, p2, a)
|
139
|
+
line_segment_length = distance_point_to_point2d(p1, p2)
|
140
|
+
((p2.y - p1.y) * a.x - (p2.x - p1.x) * a.y + p2.x * p1.y - p2.y * p1.x).abs / (line_segment_length * 1.0)
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# The distance from a point to a line on a plane
|
145
|
+
# Normalized equation of the line
|
146
|
+
def distance_point_line_normalized2d(a, b, c, p)
|
147
|
+
(p.x * a + p.y * b - c).abs
|
148
|
+
end
|
149
|
+
|
150
|
+
def oriented_area(a, b, c)
|
151
|
+
a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Determines if a clockwise crawl is performed
|
156
|
+
# for defined order of points
|
157
|
+
def clockwise(a, b, c)
|
158
|
+
oriented_area(a, b, c).negative?
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Determines if a counter-clockwise crawl is
|
163
|
+
# performed for defined order of points
|
164
|
+
def counter_clockwise(a, b, c)
|
165
|
+
oriented_area(a, b, c).positive?
|
166
|
+
end
|
167
|
+
|
168
|
+
def not_polygon?(points)
|
169
|
+
points.empty? || points.size == 1 || points.size == 2
|
170
|
+
end
|
171
|
+
|
172
|
+
def put_point_in_part(part, point, direction)
|
173
|
+
direction = method(direction)
|
174
|
+
part.pop while part.size >= 2 && !direction.call(part[part.size - 2], part[part.size - 1], point)
|
175
|
+
part.push(point)
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# Returns an array containing points that are included
|
180
|
+
# in the minimal convex hull for a given array of points
|
181
|
+
# https://e-maxx.ru/algo/convex_hull_graham
|
182
|
+
def minimal_convex_hull_2d(points)
|
183
|
+
return points if not_polygon?(points)
|
184
|
+
|
185
|
+
points.sort_by! { |p| [p.x, p.y] }
|
186
|
+
first = points[0]
|
187
|
+
last = points.last
|
188
|
+
up = [first]
|
189
|
+
down = [first]
|
190
|
+
|
191
|
+
(1...points.size).each do |i|
|
192
|
+
point = points[i]
|
193
|
+
is_last = i == points.size - 1
|
194
|
+
put_point_in_part(up, point, :clockwise) if is_last || clockwise(first, point, last)
|
195
|
+
put_point_in_part(down, point, :counter_clockwise) if is_last || counter_clockwise(first, point, last)
|
196
|
+
end
|
197
|
+
up + down[1...-1]
|
198
|
+
end
|
199
|
+
|
200
|
+
def process_cf(line_equation, variable)
|
201
|
+
if line_equation.include?(variable)
|
202
|
+
before = line_equation.index('/') + 1
|
203
|
+
after = line_equation.index('=')
|
204
|
+
line_equation.slice(before..after).gsub('=', '').sub('*', '').gsub('(', '').gsub(')', '').to_f
|
205
|
+
else
|
206
|
+
0.0
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def cut_by_eq(line_equation)
|
211
|
+
line_equation.slice(line_equation.index('='), line_equation.length).sub('=', '')
|
212
|
+
end
|
213
|
+
|
214
|
+
def process_line_by_coordinates(line_equation, func)
|
215
|
+
copy_line = insert_eq(line_equation)
|
216
|
+
func = method(func)
|
217
|
+
res = []
|
218
|
+
res[0] = func.call(copy_line, 'x')
|
219
|
+
copy_line = cut_by_eq(copy_line)
|
220
|
+
res[1] = func.call(copy_line, 'y')
|
221
|
+
copy_line = cut_by_eq(copy_line)
|
222
|
+
res[2] = func.call(copy_line, 'z')
|
223
|
+
res
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
class VariablesOrderException < RuntimeError
|
229
|
+
end
|
230
|
+
|
231
|
+
def needed_variables_order?(before, after)
|
232
|
+
before < after
|
233
|
+
end
|
234
|
+
|
235
|
+
def process_free_member(line_equation, variable)
|
236
|
+
if line_equation.include?(variable)
|
237
|
+
before = line_equation.index(variable) + 1
|
238
|
+
after = line_equation.index('/')
|
239
|
+
|
240
|
+
throw VariablesOrderException unless needed_variables_order?(before, after)
|
241
|
+
|
242
|
+
line_equation.slice(before..after).gsub('/', '').to_f * -1
|
243
|
+
else
|
244
|
+
0.0
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
|
249
|
+
|
250
|
+
def vectors_product(v1, v2)
|
251
|
+
res = Array.new(3)
|
252
|
+
(0..2).each do |i|
|
253
|
+
res[i] = v1[(i + 1) % 3] * v2[(i + 2) % 3] - v1[(i + 2) % 3] * v2[(i + 1) % 3]
|
254
|
+
end
|
255
|
+
res
|
256
|
+
end
|
257
|
+
|
258
|
+
def vector_length(vector)
|
259
|
+
Math.sqrt(vector[0]**2 + vector[1]**2 + vector[2]**2)
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
|
264
|
+
# Closest pair of points_________________________
|
265
|
+
# find minimum distance between two points in set
|
266
|
+
def brute_min(points, current = Float::INFINITY)
|
267
|
+
return current if points.length < 2
|
268
|
+
|
269
|
+
head = points[0]
|
270
|
+
points.delete_at(0)
|
271
|
+
new_min = points.map { |x| distance_point_to_point2d(head, x)}.min
|
272
|
+
new_сurrent = [new_min, current].min
|
273
|
+
brute_min(points, new_сurrent)
|
274
|
+
end
|
275
|
+
|
276
|
+
def divide_min(points)
|
277
|
+
half = points.length / 2
|
278
|
+
points.sort_by! { |p| [p.x, p.y] }
|
279
|
+
minimum = [brute_min(points[0..half]), brute_min(points[half..points.length])].min
|
280
|
+
near_line = points.select { |x| x > half - minimum and x < half + minimum}
|
281
|
+
min([brute_min(near_line), minimum])
|
282
|
+
end
|
283
|
+
|
284
|
+
def insert_eq(line_equation)
|
285
|
+
line_equation.gsub(' ', '').insert(line_equation.length, '=')
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
|
data/lib/geometry3d.rb
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'geometry/figure'
|
4
|
+
|
5
|
+
module Silicium
|
6
|
+
|
7
|
+
module Geometry3d
|
8
|
+
##
|
9
|
+
# Represents a point as three coordinates
|
10
|
+
# in three-dimensional space
|
11
|
+
Point3d = Struct.new(:x, :y, :z)
|
12
|
+
|
13
|
+
##
|
14
|
+
# Calculates the distance from given points in three-dimensional space
|
15
|
+
def distance_point_to_point3d(a, b)
|
16
|
+
Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2 + (b.z - a.z)**2)
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Class represents a plane as equation Ax + By + Cz+D = 0
|
21
|
+
# in two-dimensional space
|
22
|
+
class Plane3d
|
23
|
+
attr_reader :x_coefficient
|
24
|
+
attr_reader :y_coefficient
|
25
|
+
attr_reader :z_coefficient
|
26
|
+
attr_reader :free_coefficient
|
27
|
+
|
28
|
+
# Initializes with three objects of type Point
|
29
|
+
def initialize(point1, point2, point3)
|
30
|
+
vector1 = Vector3d.new(point1)
|
31
|
+
norm = vector1.norm_vector(point2, point3)
|
32
|
+
@x_coefficient = norm.x
|
33
|
+
@y_coefficient = norm.y
|
34
|
+
@z_coefficient = norm.z
|
35
|
+
@free_coefficient = -point1.x * norm.x + (-point1.y * norm.y) + (-point1.z * norm.z)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Initializes with coefficients
|
40
|
+
def initialize_with_coefficients(a, b, c, d)
|
41
|
+
raise ArgumentError, 'All coefficients cannot be 0 ' if a.equal?(0) && b.equal?(0) && c.equal?(0) && (d.equal?(0) || !d.equal?(0))
|
42
|
+
|
43
|
+
@x_coefficient = a
|
44
|
+
@y_coefficient = b
|
45
|
+
@z_coefficient = c
|
46
|
+
@free_coefficient = d
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# check if the points isn't on the same line
|
51
|
+
def point_is_on_line?(point1, point2, point3)
|
52
|
+
check_p1 = @x_coefficient * point1.x + @y_coefficient * point1.y + @z_coefficient * point1.z + @free_coefficient
|
53
|
+
check_p2 = @x_coefficient * point2.x + @y_coefficient * point2.y + @z_coefficient * point2.z + @free_coefficient
|
54
|
+
check_p3 = @x_coefficient * point3.x + @y_coefficient * point3.y + @z_coefficient * point3.z + @free_coefficient
|
55
|
+
check_p1.equal?(0) && check_p2.equal?(0) && check_p3.equal?(0)
|
56
|
+
end
|
57
|
+
|
58
|
+
# check if the point isn't on the plane
|
59
|
+
def point_is_on_plane?(point)
|
60
|
+
(@x_coefficient * point.x + @y_coefficient * point.y + @z_coefficient * point.z + @free_coefficient).equal?(0)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Checks if two planes are parallel in 3-dimensional space
|
64
|
+
def parallel?(other_plane)
|
65
|
+
v1 = Vector3d.new(Point3d.new(@x_coefficient, @y_coefficient, @z_coefficient))
|
66
|
+
v2 = Vector3d.new(Point3d.new(other_plane.x_coefficient, other_plane.y_coefficient, other_plane.z_coefficient))
|
67
|
+
v1.collinear?(v2)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Checks if two planes are intersecting in 3-dimensional space
|
72
|
+
def intersecting?(other_plane)
|
73
|
+
check_x = @x_coefficient != other_plane.x_coefficient
|
74
|
+
check_y = @y_coefficient != other_plane.y_coefficient
|
75
|
+
check_z = @z_coefficient != other_plane.z_coefficient
|
76
|
+
check_x || check_y || check_z
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Checks if two planes are perpendicular
|
81
|
+
def perpendicular?(other_plane)
|
82
|
+
check_x = @x_coefficient * other_plane.x_coefficient
|
83
|
+
check_y = @y_coefficient * other_plane.y_coefficient
|
84
|
+
check_z = @z_coefficient * other_plane.z_coefficient
|
85
|
+
(check_x + check_y + check_z).equal?(0)
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# The distance between parallel planes
|
90
|
+
def distance_between_parallel_planes(other_plane)
|
91
|
+
raise 'Planes are not parallel' if !parallel?(other_plane)
|
92
|
+
|
93
|
+
free = (other_plane.free_coefficient - @free_coefficient).abs
|
94
|
+
free / sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# The distance from a point to a plane
|
99
|
+
#
|
100
|
+
def distance_point_to_plane(point)
|
101
|
+
norm = 1 / Math.sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
|
102
|
+
(@x_coefficient * norm * point.x + @y_coefficient * norm * point.y +
|
103
|
+
@z_coefficient * norm * point.z + @free_coefficient * norm).abs
|
104
|
+
end
|
105
|
+
end
|
106
|
+
##
|
107
|
+
# Class represents vector
|
108
|
+
# in three-dimensional space
|
109
|
+
class Vector3d
|
110
|
+
attr_reader :x
|
111
|
+
attr_reader :y
|
112
|
+
attr_reader :z
|
113
|
+
|
114
|
+
##
|
115
|
+
# Initializes with one objects of type Point3d
|
116
|
+
# 2nd point is (0,0,0)
|
117
|
+
def initialize(point)
|
118
|
+
@x = point.x
|
119
|
+
@y = point.y
|
120
|
+
@z = point.z
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Checks if vector is zero vector
|
125
|
+
def zero_vector?
|
126
|
+
(@x.eql?(0) && @y.eql?(0) && @z.eql?(0)).eql?(true) ? true : false
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Returns length of the vector
|
131
|
+
def length
|
132
|
+
Math.sqrt(@x**2 + @y**2 + @z**2)
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Add one vector to another
|
137
|
+
def addition!(other_vector)
|
138
|
+
@x += other_vector.x
|
139
|
+
@y += other_vector.y
|
140
|
+
@z += other_vector.z
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Sub one vector from another
|
145
|
+
def subtraction!(other_vector)
|
146
|
+
@x -= other_vector.x
|
147
|
+
@y -= other_vector.y
|
148
|
+
@z -= other_vector.z
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Mult vector by number
|
153
|
+
def multiplication_by_number!(r)
|
154
|
+
@x *= r
|
155
|
+
@y *= r
|
156
|
+
@z *= r
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Returns scalar multiplication of 2 vectors
|
161
|
+
def scalar_multiplication(other_vector)
|
162
|
+
x * other_vector.x + y * other_vector.y + z * other_vector.z
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Returns cos between two vectors
|
167
|
+
def cos_between_vectors(other_vector)
|
168
|
+
scalar_multiplication(other_vector) / (length * other_vector.length).to_f
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Returns vector multiplication of 2 vectors
|
173
|
+
def vector_multiplication(other_vector)
|
174
|
+
x = @y * other_vector.z - @z * other_vector.y
|
175
|
+
y = @z * other_vector.x - @x * other_vector.z
|
176
|
+
z = @x * other_vector.y - @y * other_vector.x
|
177
|
+
Vector3d.new(Point3d.new(x, y, z))
|
178
|
+
end
|
179
|
+
|
180
|
+
##
|
181
|
+
# Find normal vector
|
182
|
+
##
|
183
|
+
# vector mult
|
184
|
+
def norm_vector(point2, point3)
|
185
|
+
point1 = Point3d.new(@x, @y, @z)
|
186
|
+
# checking if the points isn't on the same line
|
187
|
+
# finding vector between points 1 and 2 ;1 and 3
|
188
|
+
vector12 = Vector3d.new(Point3d.new(point2.x - point1.x, point2.y - point1.y, point2.z - point1.z))
|
189
|
+
vector13 = Vector3d.new(Point3d.new(point3.x - point1.x, point3.y - point1.y, point3.z - point1.z))
|
190
|
+
# vector13=vector1.scalar_multiplication(vector3)
|
191
|
+
x = vector12.y * vector13.z - vector12.z * vector13.y
|
192
|
+
y = -(vector12.x * vector13.z - vector12.z * vector13.x)
|
193
|
+
z = vector12.x * vector13.y - vector12.y * vector13.x
|
194
|
+
Vector3d.new(Point3d.new(x, y, z))
|
195
|
+
end
|
196
|
+
|
197
|
+
##
|
198
|
+
# Function for checking sign of number
|
199
|
+
def sign(integer)
|
200
|
+
integer >= 0 ? 1 : -1
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# help function for collinear function
|
205
|
+
def help_check(vector2, x, y, z)
|
206
|
+
check1 = x * sign(vector2.x) * sign(@x) == y * sign(vector2.y) * sign(@y)
|
207
|
+
check2 = x * sign(vector2.x) * sign(@x) == z * sign(vector2.z) * sign(@z)
|
208
|
+
check3 = z * sign(vector2.z) * sign(@z) == y * sign(vector2.y) * sign(@y)
|
209
|
+
check1 && check2 && check3
|
210
|
+
end
|
211
|
+
##
|
212
|
+
# helps to divide correctly
|
213
|
+
def helper(value1, value2)
|
214
|
+
result = 0
|
215
|
+
if value1 > value2
|
216
|
+
result = value1 / value2
|
217
|
+
else
|
218
|
+
result = value2 / value1
|
219
|
+
end
|
220
|
+
result
|
221
|
+
end
|
222
|
+
|
223
|
+
# Check if two vectors are collinear
|
224
|
+
def collinear?(vector2)
|
225
|
+
x1 = (vector2.x).abs
|
226
|
+
y1 = (vector2.y).abs
|
227
|
+
z1 = (vector2.z).abs
|
228
|
+
x = helper(x1,@x.abs)
|
229
|
+
y = helper(y1,@y.abs)
|
230
|
+
z = helper(z1,@z.abs)
|
231
|
+
help_check(vector2, x, y, z)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
##
|
236
|
+
# Creates an array- directing vector in three-dimensional space .
|
237
|
+
# The equation is specified in the canonical form.
|
238
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
239
|
+
#
|
240
|
+
# Important: mandatory order of variables: x, y, z
|
241
|
+
def directing_vector3d(line_equation)
|
242
|
+
process_line_by_coordinates(line_equation, :process_cf)
|
243
|
+
end
|
244
|
+
|
245
|
+
##
|
246
|
+
# Creates an array of coordinates of the point ([x, y, z] on the line
|
247
|
+
# given by the equation in the canonical form.
|
248
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
249
|
+
#
|
250
|
+
# Important: mandatory order of variables: x, y, z
|
251
|
+
def height_point_3d(line_equation)
|
252
|
+
process_line_by_coordinates(line_equation, :process_free_member)
|
253
|
+
end
|
254
|
+
|
255
|
+
##
|
256
|
+
# Calculates the distance from a point given by a Point3d structure
|
257
|
+
# to a straight line given by a canonical equation.
|
258
|
+
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
|
259
|
+
#
|
260
|
+
# Important: mandatory order of variables: x, y, z
|
261
|
+
def point_to_line_distance_3d(point, line_eq)
|
262
|
+
dir_vector = directing_vector3d(line_eq)
|
263
|
+
line_point = height_point_3d(line_eq)
|
264
|
+
height_vector = [line_point[0] - point.x, line_point[1] - point.y, line_point[2] - point.z]
|
265
|
+
|
266
|
+
height_on_dir = vectors_product(height_vector, dir_vector)
|
267
|
+
vector_length(height_on_dir) / vector_length(dir_vector)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|