lib/geometry3d.rb
# frozen_string_literal: true
require_relative 'geometry/figure'
module Silicium
module Geometry3d
##
# Represents a point as three coordinates
# in three-dimensional space
Point3d = Struct.new(:x, :y, :z)
##
# Calculates the distance from given points in three-dimensional space
def distance_point_to_point3d(a, b)
Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2 + (b.z - a.z)**2)
end
##
# Class represents a plane as equation Ax + By + Cz+D = 0
# in two-dimensional space
class Plane3d
attr_reader :x_coefficient
attr_reader :y_coefficient
attr_reader :z_coefficient
attr_reader :free_coefficient
# Initializes with three objects of type Point
def initialize(point1, point2, point3)
vector1 = Vector3d.new(point1)
norm = vector1.norm_vector(point2, point3)
@x_coefficient = norm.x
@y_coefficient = norm.y
@z_coefficient = norm.z
@free_coefficient = -point1.x * norm.x + (-point1.y * norm.y) + (-point1.z * norm.z)
end
##
# Initializes with coefficients
def initialize_with_coefficients(a, b, c, d)
raise ArgumentError, 'All coefficients cannot be 0 ' if a.equal?(0) && b.equal?(0) && c.equal?(0) && (d.equal?(0) || !d.equal?(0))
@x_coefficient = a
@y_coefficient = b
@z_coefficient = c
@free_coefficient = d
end
##
# check if the points isn't on the same line
def point_is_on_line?(point1, point2, point3)
check_p1 = @x_coefficient * point1.x + @y_coefficient * point1.y + @z_coefficient * point1.z + @free_coefficient
check_p2 = @x_coefficient * point2.x + @y_coefficient * point2.y + @z_coefficient * point2.z + @free_coefficient
check_p3 = @x_coefficient * point3.x + @y_coefficient * point3.y + @z_coefficient * point3.z + @free_coefficient
check_p1.equal?(0) && check_p2.equal?(0) && check_p3.equal?(0)
end
# check if the point isn't on the plane
def point_is_on_plane?(point)
(@x_coefficient * point.x + @y_coefficient * point.y + @z_coefficient * point.z + @free_coefficient).equal?(0)
end
# Checks if two planes are parallel in 3-dimensional space
def parallel?(other_plane)
v1 = Vector3d.new(Point3d.new(@x_coefficient, @y_coefficient, @z_coefficient))
v2 = Vector3d.new(Point3d.new(other_plane.x_coefficient, other_plane.y_coefficient, other_plane.z_coefficient))
v1.collinear?(v2)
end
##
# Checks if two planes are intersecting in 3-dimensional space
def intersecting?(other_plane)
check_x = @x_coefficient != other_plane.x_coefficient
check_y = @y_coefficient != other_plane.y_coefficient
check_z = @z_coefficient != other_plane.z_coefficient
check_x || check_y || check_z
end
##
# Checks if two planes are perpendicular
def perpendicular?(other_plane)
check_x = @x_coefficient * other_plane.x_coefficient
check_y = @y_coefficient * other_plane.y_coefficient
check_z = @z_coefficient * other_plane.z_coefficient
(check_x + check_y + check_z).equal?(0)
end
##
# The distance between parallel planes
def distance_between_parallel_planes(other_plane)
raise 'Planes are not parallel' if !parallel?(other_plane)
free = (other_plane.free_coefficient - @free_coefficient).abs
free / sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
end
##
# The distance from a point to a plane
#
def distance_point_to_plane(point)
norm = 1 / Math.sqrt(@x_coefficient**2 + @y_coefficient**2 + @z_coefficient**2)
(@x_coefficient * norm * point.x + @y_coefficient * norm * point.y +
@z_coefficient * norm * point.z + @free_coefficient * norm).abs
end
end
##
# Class represents vector
# in three-dimensional space
class Vector3d
attr_reader :x
attr_reader :y
attr_reader :z
##
# Initializes with one objects of type Point3d
# 2nd point is (0,0,0)
def initialize(point)
@x = point.x
@y = point.y
@z = point.z
end
##
# Checks if vector is zero vector
def zero_vector?
(@x.eql?(0) && @y.eql?(0) && @z.eql?(0)).eql?(true) ? true : false
end
##
# Returns length of the vector
def length
Math.sqrt(@x**2 + @y**2 + @z**2)
end
##
# Add one vector to another
def addition!(other_vector)
@x += other_vector.x
@y += other_vector.y
@z += other_vector.z
end
##
# Sub one vector from another
def subtraction!(other_vector)
@x -= other_vector.x
@y -= other_vector.y
@z -= other_vector.z
end
##
# Mult vector by number
def multiplication_by_number!(r)
@x *= r
@y *= r
@z *= r
end
##
# Returns scalar multiplication of 2 vectors
def scalar_multiplication(other_vector)
x * other_vector.x + y * other_vector.y + z * other_vector.z
end
##
# Returns cos between two vectors
def cos_between_vectors(other_vector)
scalar_multiplication(other_vector) / (length * other_vector.length).to_f
end
##
# Returns vector multiplication of 2 vectors
def vector_multiplication(other_vector)
x = @y * other_vector.z - @z * other_vector.y
y = @z * other_vector.x - @x * other_vector.z
z = @x * other_vector.y - @y * other_vector.x
Vector3d.new(Point3d.new(x, y, z))
end
##
# Find normal vector
##
# vector mult
def norm_vector(point2, point3)
point1 = Point3d.new(@x, @y, @z)
# checking if the points isn't on the same line
# finding vector between points 1 and 2 ;1 and 3
vector12 = Vector3d.new(Point3d.new(point2.x - point1.x, point2.y - point1.y, point2.z - point1.z))
vector13 = Vector3d.new(Point3d.new(point3.x - point1.x, point3.y - point1.y, point3.z - point1.z))
# vector13=vector1.scalar_multiplication(vector3)
x = vector12.y * vector13.z - vector12.z * vector13.y
y = -(vector12.x * vector13.z - vector12.z * vector13.x)
z = vector12.x * vector13.y - vector12.y * vector13.x
Vector3d.new(Point3d.new(x, y, z))
end
##
# Function for checking sign of number
def sign(integer)
integer >= 0 ? 1 : -1
end
##
# help function for collinear function
def help_check(vector2, x, y, z)
check1 = x * sign(vector2.x) * sign(@x) == y * sign(vector2.y) * sign(@y)
check2 = x * sign(vector2.x) * sign(@x) == z * sign(vector2.z) * sign(@z)
check3 = z * sign(vector2.z) * sign(@z) == y * sign(vector2.y) * sign(@y)
check1 && check2 && check3
end
##
# helps to divide correctly
def helper(value1, value2)
result = 0
if value1 > value2
result = value1 / value2
else
result = value2 / value1
end
result
end
# Check if two vectors are collinear
def collinear?(vector2)
x1 = (vector2.x).abs
y1 = (vector2.y).abs
z1 = (vector2.z).abs
x = helper(x1,@x.abs)
y = helper(y1,@y.abs)
z = helper(z1,@z.abs)
help_check(vector2, x, y, z)
end
end
##
# Creates an array- directing vector in three-dimensional space .
# The equation is specified in the canonical form.
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
#
# Important: mandatory order of variables: x, y, z
def directing_vector3d(line_equation)
process_line_by_coordinates(line_equation, :process_cf)
end
##
# Creates an array of coordinates of the point ([x, y, z] on the line
# given by the equation in the canonical form.
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
#
# Important: mandatory order of variables: x, y, z
def height_point_3d(line_equation)
process_line_by_coordinates(line_equation, :process_free_member)
end
##
# Calculates the distance from a point given by a Point3d structure
# to a straight line given by a canonical equation.
# Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51
#
# Important: mandatory order of variables: x, y, z
def point_to_line_distance_3d(point, line_eq)
dir_vector = directing_vector3d(line_eq)
line_point = height_point_3d(line_eq)
height_vector = [line_point[0] - point.x, line_point[1] - point.y, line_point[2] - point.z]
height_on_dir = vectors_product(height_vector, dir_vector)
vector_length(height_on_dir) / vector_length(dir_vector)
end
end
end