Module protkit.geometry.math
Implements class Math
to perform various mathematical operations. These mathematical
operations include vector operations, such as calculating the magnitude, dot product,
cross product, Euclidean distance, angle and dihedral angle between vectors.
The class is meant to be used as a utility class and is not meant to be instantiated. It is unaware of the context in which it is used and does not have any dependencies on other classes or modules in the protkit package.
Expand source code
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Authors: Fred Senekal (FS)
# Contact: fred@silicogenesis.com
# License: GPLv3
"""
Implements class `Math` to perform various mathematical operations. These mathematical
operations include vector operations, such as calculating the magnitude, dot product,
cross product, Euclidean distance, angle and dihedral angle between vectors.
The class is meant to be used as a utility class and is not meant to be instantiated.
It is unaware of the context in which it is used and does not have any dependencies
on other classes or modules in the protkit package.
"""
import math
from typing import Tuple
class Math:
@staticmethod
def magnitude(x: float, y: float, z: float) -> float:
"""
Calculates the magnitude of a vector.
Args:
x (float): The x-coordinate of the vector.
y (float): The y-coordinate of the vector.
z (float): The z-coordinate of the vector.
Returns:
float: The magnitude of the vector.
"""
return math.sqrt(x * x + y * y + z * z)
@staticmethod
def dot_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float:
"""
Calculates the dot product of two vectors.
Args:
x1 (float): The x-coordinate of the first vector.
y1 (float): The y-coordinate of the first vector.
z1 (float): The z-coordinate of the first vector.
x2 (float): The x-coordinate of the second vector.
y2 (float): The y-coordinate of the second vector.
z2 (float): The z-coordinate of the second vector.
Returns:
float: The dot product of the two vectors.
"""
return x1 * x2 + y1 * y2 + z1 * z2
@staticmethod
def cross_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> Tuple[float, float, float]:
"""
Calculates the cross product of two vectors.
Args:
x1 (float): The x-coordinate of the first vector.
y1 (float): The y-coordinate of the first vector.
z1 (float): The z-coordinate of the first vector.
x2 (float): The x-coordinate of the second vector.
y2 (float): The y-coordinate of the second vector.
z2 (float): The z-coordinate of the second vector.
Returns:
Tuple[float, float, float]: The cross product of the two vectors.
"""
return y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2
@staticmethod
def euclidean_distance(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float:
"""
Calculates the Euclidean distance between two points.
Args:
x1 (float): The x-coordinate of the first point.
y1 (float): The y-coordinate of the first point.
z1 (float): The z-coordinate of the first point.
x2 (float): The x-coordinate of the second point.
y2 (float): The y-coordinate of the second point.
z2 (float): The z-coordinate of the second point.
Returns:
float: The distance between the two points.
"""
dx = x1 - x2
dy = y1 - y2
dz = z1 - z2
return math.sqrt(dx * dx + dy * dy + dz * dz)
@staticmethod
def vector_angle(x1: float, y1: float, z1: float,
x2: float, y2: float, z2: float) -> float:
"""
Calculates the angle between two vectors.
Args:
x1 (float): The x-coordinate of the first vector.
y1 (float): The y-coordinate of the first vector.
z1 (float): The z-coordinate of the first vector.
x2 (float): The x-coordinate of the second vector.
y2 (float): The y-coordinate of the second vector.
z2 (float): The z-coordinate of the second vector.
Returns:
float: The angle in degrees between the two vectors.
"""
# Calculate the dot product of the vectors
dot_product = Math.dot_product(x1, y1, z1, x2, y2, z2)
# Calculate the magnitude of the vectors
mag_u = Math.magnitude(x1, y1, z1)
mag_v = Math.magnitude(x2, y2, z2)
# Calculate the cosine of the angle
cos_angle = dot_product / (mag_u * mag_v)
# Edge cases
if cos_angle > 1:
cos_angle = 1
elif cos_angle < -1:
cos_angle = -1
angle_radians = math.acos(cos_angle)
angle = math.degrees(angle_radians)
return angle
@staticmethod
def angle(x1: float, y1: float, z1: float,
x2: float, y2: float, z2: float,
x3: float, y3: float, z3: float) -> float:
"""
Calculates the angle between three points.
Args:
x1 (float): The x-coordinate of the first point.
y1 (float): The y-coordinate of the first point.
z1 (float): The z-coordinate of the first point.
x2 (float): The x-coordinate of the second point.
y2 (float): The y-coordinate of the second point.
z2 (float): The z-coordinate of the second point.
x3 (float): The x-coordinate of the third point.
y3 (float): The y-coordinate of the third point.
z3 (float): The z-coordinate of the third point.
Returns:
float: The angle in degrees between the three points.
"""
# Calculate the vectors between the points
ux = x1 - x2
uy = y1 - y2
uz = z1 - z2
vx = x3 - x2
vy = y3 - y2
vz = z3 - z2
return Math.vector_angle(ux, uy, uz, vx, vy, vz)
@staticmethod
def dihedral_angle(x1: float, y1: float, z1: float,
x2: float, y2: float, z2: float,
x3: float, y3: float, z3: float,
x4: float, y4: float, z4: float) -> float:
"""
Calculates the dihedral angle between four points.
Args:
x1 (float): The x-coordinate of the first point.
y1 (float): The y-coordinate of the first point.
z1 (float): The z-coordinate of the first point.
x2 (float): The x-coordinate of the second point.
y2 (float): The y-coordinate of the second point.
z2 (float): The z-coordinate of the second point.
x3 (float): The x-coordinate of the third point.
y3 (float): The y-coordinate of the third point.
z3 (float): The z-coordinate of the third point.
x4 (float): The x-coordinate of the fourth point.
y4 (float): The y-coordinate of the fourth point.
z4 (float): The z-coordinate of the fourth point.
Returns:
float: The dihedral angle in degrees between the four points.
"""
# Calculate the vectors between the points
ux, uy, uz = x2 - x1, y2 - y1, z2 - z1
vx, vy, vz = x3 - x2, y3 - y2, z3 - z2
wx, wy, wz = x4 - x3, y4 - y3, z4 - z3
# Calculate the normal vectors
n1x, n1y, n1z = Math.cross_product(ux, uy, uz, vx, vy, vz)
n2x, n2y, n2z = Math.cross_product(vx, vy, vz, wx, wy, wz)
# Calculate the dot products
angle_deg = Math.vector_angle(n1x, n1y, n1z, n2x, n2y, n2z)
# Calculate the sign of the dihedral angle
v_cross_x, vcross_y, vcross_z = Math.cross_product(n1x, n1y, n1z, n2x, n2y, n2z)
dot_uvwx = Math.dot_product(v_cross_x, vcross_y, vcross_z, vx, vy, vz)
if dot_uvwx < 0:
angle_deg = -angle_deg
return angle_deg
Classes
class Math
-
Expand source code
class Math: @staticmethod def magnitude(x: float, y: float, z: float) -> float: """ Calculates the magnitude of a vector. Args: x (float): The x-coordinate of the vector. y (float): The y-coordinate of the vector. z (float): The z-coordinate of the vector. Returns: float: The magnitude of the vector. """ return math.sqrt(x * x + y * y + z * z) @staticmethod def dot_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the dot product of two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: float: The dot product of the two vectors. """ return x1 * x2 + y1 * y2 + z1 * z2 @staticmethod def cross_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> Tuple[float, float, float]: """ Calculates the cross product of two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: Tuple[float, float, float]: The cross product of the two vectors. """ return y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2 @staticmethod def euclidean_distance(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the Euclidean distance between two points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. Returns: float: The distance between the two points. """ dx = x1 - x2 dy = y1 - y2 dz = z1 - z2 return math.sqrt(dx * dx + dy * dy + dz * dz) @staticmethod def vector_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the angle between two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: float: The angle in degrees between the two vectors. """ # Calculate the dot product of the vectors dot_product = Math.dot_product(x1, y1, z1, x2, y2, z2) # Calculate the magnitude of the vectors mag_u = Math.magnitude(x1, y1, z1) mag_v = Math.magnitude(x2, y2, z2) # Calculate the cosine of the angle cos_angle = dot_product / (mag_u * mag_v) # Edge cases if cos_angle > 1: cos_angle = 1 elif cos_angle < -1: cos_angle = -1 angle_radians = math.acos(cos_angle) angle = math.degrees(angle_radians) return angle @staticmethod def angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float) -> float: """ Calculates the angle between three points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. x3 (float): The x-coordinate of the third point. y3 (float): The y-coordinate of the third point. z3 (float): The z-coordinate of the third point. Returns: float: The angle in degrees between the three points. """ # Calculate the vectors between the points ux = x1 - x2 uy = y1 - y2 uz = z1 - z2 vx = x3 - x2 vy = y3 - y2 vz = z3 - z2 return Math.vector_angle(ux, uy, uz, vx, vy, vz) @staticmethod def dihedral_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float, x4: float, y4: float, z4: float) -> float: """ Calculates the dihedral angle between four points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. x3 (float): The x-coordinate of the third point. y3 (float): The y-coordinate of the third point. z3 (float): The z-coordinate of the third point. x4 (float): The x-coordinate of the fourth point. y4 (float): The y-coordinate of the fourth point. z4 (float): The z-coordinate of the fourth point. Returns: float: The dihedral angle in degrees between the four points. """ # Calculate the vectors between the points ux, uy, uz = x2 - x1, y2 - y1, z2 - z1 vx, vy, vz = x3 - x2, y3 - y2, z3 - z2 wx, wy, wz = x4 - x3, y4 - y3, z4 - z3 # Calculate the normal vectors n1x, n1y, n1z = Math.cross_product(ux, uy, uz, vx, vy, vz) n2x, n2y, n2z = Math.cross_product(vx, vy, vz, wx, wy, wz) # Calculate the dot products angle_deg = Math.vector_angle(n1x, n1y, n1z, n2x, n2y, n2z) # Calculate the sign of the dihedral angle v_cross_x, vcross_y, vcross_z = Math.cross_product(n1x, n1y, n1z, n2x, n2y, n2z) dot_uvwx = Math.dot_product(v_cross_x, vcross_y, vcross_z, vx, vy, vz) if dot_uvwx < 0: angle_deg = -angle_deg return angle_deg
Static methods
def angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float) ‑> float
-
Calculates the angle between three points.
Args
x1
:float
- The x-coordinate of the first point.
y1
:float
- The y-coordinate of the first point.
z1
:float
- The z-coordinate of the first point.
x2
:float
- The x-coordinate of the second point.
y2
:float
- The y-coordinate of the second point.
z2
:float
- The z-coordinate of the second point.
x3
:float
- The x-coordinate of the third point.
y3
:float
- The y-coordinate of the third point.
z3
:float
- The z-coordinate of the third point.
Returns
float
- The angle in degrees between the three points.
Expand source code
@staticmethod def angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float) -> float: """ Calculates the angle between three points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. x3 (float): The x-coordinate of the third point. y3 (float): The y-coordinate of the third point. z3 (float): The z-coordinate of the third point. Returns: float: The angle in degrees between the three points. """ # Calculate the vectors between the points ux = x1 - x2 uy = y1 - y2 uz = z1 - z2 vx = x3 - x2 vy = y3 - y2 vz = z3 - z2 return Math.vector_angle(ux, uy, uz, vx, vy, vz)
def cross_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) ‑> Tuple[float, float, float]
-
Calculates the cross product of two vectors.
Args
x1
:float
- The x-coordinate of the first vector.
y1
:float
- The y-coordinate of the first vector.
z1
:float
- The z-coordinate of the first vector.
x2
:float
- The x-coordinate of the second vector.
y2
:float
- The y-coordinate of the second vector.
z2
:float
- The z-coordinate of the second vector.
Returns
Tuple[float, float, float]
- The cross product of the two vectors.
Expand source code
@staticmethod def cross_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> Tuple[float, float, float]: """ Calculates the cross product of two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: Tuple[float, float, float]: The cross product of the two vectors. """ return y1 * z2 - z1 * y2, z1 * x2 - x1 * z2, x1 * y2 - y1 * x2
def dihedral_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float, x4: float, y4: float, z4: float) ‑> float
-
Calculates the dihedral angle between four points.
Args
x1
:float
- The x-coordinate of the first point.
y1
:float
- The y-coordinate of the first point.
z1
:float
- The z-coordinate of the first point.
x2
:float
- The x-coordinate of the second point.
y2
:float
- The y-coordinate of the second point.
z2
:float
- The z-coordinate of the second point.
x3
:float
- The x-coordinate of the third point.
y3
:float
- The y-coordinate of the third point.
z3
:float
- The z-coordinate of the third point.
x4
:float
- The x-coordinate of the fourth point.
y4
:float
- The y-coordinate of the fourth point.
z4
:float
- The z-coordinate of the fourth point.
Returns
float
- The dihedral angle in degrees between the four points.
Expand source code
@staticmethod def dihedral_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float, x3: float, y3: float, z3: float, x4: float, y4: float, z4: float) -> float: """ Calculates the dihedral angle between four points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. x3 (float): The x-coordinate of the third point. y3 (float): The y-coordinate of the third point. z3 (float): The z-coordinate of the third point. x4 (float): The x-coordinate of the fourth point. y4 (float): The y-coordinate of the fourth point. z4 (float): The z-coordinate of the fourth point. Returns: float: The dihedral angle in degrees between the four points. """ # Calculate the vectors between the points ux, uy, uz = x2 - x1, y2 - y1, z2 - z1 vx, vy, vz = x3 - x2, y3 - y2, z3 - z2 wx, wy, wz = x4 - x3, y4 - y3, z4 - z3 # Calculate the normal vectors n1x, n1y, n1z = Math.cross_product(ux, uy, uz, vx, vy, vz) n2x, n2y, n2z = Math.cross_product(vx, vy, vz, wx, wy, wz) # Calculate the dot products angle_deg = Math.vector_angle(n1x, n1y, n1z, n2x, n2y, n2z) # Calculate the sign of the dihedral angle v_cross_x, vcross_y, vcross_z = Math.cross_product(n1x, n1y, n1z, n2x, n2y, n2z) dot_uvwx = Math.dot_product(v_cross_x, vcross_y, vcross_z, vx, vy, vz) if dot_uvwx < 0: angle_deg = -angle_deg return angle_deg
def dot_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) ‑> float
-
Calculates the dot product of two vectors.
Args
x1
:float
- The x-coordinate of the first vector.
y1
:float
- The y-coordinate of the first vector.
z1
:float
- The z-coordinate of the first vector.
x2
:float
- The x-coordinate of the second vector.
y2
:float
- The y-coordinate of the second vector.
z2
:float
- The z-coordinate of the second vector.
Returns
float
- The dot product of the two vectors.
Expand source code
@staticmethod def dot_product(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the dot product of two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: float: The dot product of the two vectors. """ return x1 * x2 + y1 * y2 + z1 * z2
def euclidean_distance(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) ‑> float
-
Calculates the Euclidean distance between two points.
Args
x1
:float
- The x-coordinate of the first point.
y1
:float
- The y-coordinate of the first point.
z1
:float
- The z-coordinate of the first point.
x2
:float
- The x-coordinate of the second point.
y2
:float
- The y-coordinate of the second point.
z2
:float
- The z-coordinate of the second point.
Returns
float
- The distance between the two points.
Expand source code
@staticmethod def euclidean_distance(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the Euclidean distance between two points. Args: x1 (float): The x-coordinate of the first point. y1 (float): The y-coordinate of the first point. z1 (float): The z-coordinate of the first point. x2 (float): The x-coordinate of the second point. y2 (float): The y-coordinate of the second point. z2 (float): The z-coordinate of the second point. Returns: float: The distance between the two points. """ dx = x1 - x2 dy = y1 - y2 dz = z1 - z2 return math.sqrt(dx * dx + dy * dy + dz * dz)
def magnitude(x: float, y: float, z: float) ‑> float
-
Calculates the magnitude of a vector.
Args
x
:float
- The x-coordinate of the vector.
y
:float
- The y-coordinate of the vector.
z
:float
- The z-coordinate of the vector.
Returns
float
- The magnitude of the vector.
Expand source code
@staticmethod def magnitude(x: float, y: float, z: float) -> float: """ Calculates the magnitude of a vector. Args: x (float): The x-coordinate of the vector. y (float): The y-coordinate of the vector. z (float): The z-coordinate of the vector. Returns: float: The magnitude of the vector. """ return math.sqrt(x * x + y * y + z * z)
def vector_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) ‑> float
-
Calculates the angle between two vectors.
Args
x1
:float
- The x-coordinate of the first vector.
y1
:float
- The y-coordinate of the first vector.
z1
:float
- The z-coordinate of the first vector.
x2
:float
- The x-coordinate of the second vector.
y2
:float
- The y-coordinate of the second vector.
z2
:float
- The z-coordinate of the second vector.
Returns
float
- The angle in degrees between the two vectors.
Expand source code
@staticmethod def vector_angle(x1: float, y1: float, z1: float, x2: float, y2: float, z2: float) -> float: """ Calculates the angle between two vectors. Args: x1 (float): The x-coordinate of the first vector. y1 (float): The y-coordinate of the first vector. z1 (float): The z-coordinate of the first vector. x2 (float): The x-coordinate of the second vector. y2 (float): The y-coordinate of the second vector. z2 (float): The z-coordinate of the second vector. Returns: float: The angle in degrees between the two vectors. """ # Calculate the dot product of the vectors dot_product = Math.dot_product(x1, y1, z1, x2, y2, z2) # Calculate the magnitude of the vectors mag_u = Math.magnitude(x1, y1, z1) mag_v = Math.magnitude(x2, y2, z2) # Calculate the cosine of the angle cos_angle = dot_product / (mag_u * mag_v) # Edge cases if cos_angle > 1: cos_angle = 1 elif cos_angle < -1: cos_angle = -1 angle_radians = math.acos(cos_angle) angle = math.degrees(angle_radians) return angle