Rename files
This commit is contained in:
176
networks/geometry/segment_tools.py
Normal file
176
networks/geometry/segment_tools.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
def parallel(segment, distance, normal=np.array([0, 1, 0])):
|
||||
"""Get parallel segment in 3D space at a distance.
|
||||
|
||||
Args:
|
||||
segment (np.array, np.array): start and end points of the segement.
|
||||
distance (int): distance between both segment. Thickness in the context of a line. Positive direction means left.
|
||||
|
||||
Returns:
|
||||
(np.array(), np.array()): parallel segment.
|
||||
|
||||
>>> parrallel(((0, 0, 0), (0, 0, 10)), 10))
|
||||
(array([-10., 0., 0.]), array([-10., 0., 10.]))
|
||||
"""
|
||||
return (orthogonal(segment[0], segment[1], distance, normal), orthogonal(segment[1], segment[0], -distance, normal))
|
||||
|
||||
|
||||
def normalized(vector):
|
||||
magnitude = np.linalg.norm(vector)
|
||||
if magnitude != 0:
|
||||
normalized_vector = vector / magnitude
|
||||
return normalized_vector
|
||||
else:
|
||||
return [0, 0, 0]
|
||||
|
||||
|
||||
def orthogonal(origin, point, distance, normal=np.array([0, 1, 0])):
|
||||
"""Get orthogonal point from a given one at the specified distance in 3D space with normal direction.
|
||||
|
||||
Args:
|
||||
origin (tuple or np.array): origin
|
||||
point (tuple or np.array): (point-origin) makes the first vector. Only the direction is used.
|
||||
distance (int): distance from the origin. Thickness in the context of a line. Positive direction means left.
|
||||
normal (list or np.array, optional): second vector. Defaults to the vertical [0, 1, 0].
|
||||
|
||||
Raises:
|
||||
ValueError: if vectors are not linearly independent.
|
||||
|
||||
Returns:
|
||||
np.array: (x y z)
|
||||
|
||||
>>> orthogonal((5, 5, 5), (150, 5, 5), 10)
|
||||
[ 5. 5. 15.]
|
||||
"""
|
||||
vector = np.subtract(point, origin)
|
||||
normalized_vector = normalized(vector)
|
||||
normalized_normal = normalized(normal)
|
||||
orthogonal = np.cross(normalized_vector, normalized_normal)
|
||||
|
||||
if np.array_equal(orthogonal, np.zeros((3,))):
|
||||
print(normalized_vector, normalized_normal, orthogonal, normal)
|
||||
print(origin, point, distance)
|
||||
raise ValueError("The input vectors are not linearly independent.")
|
||||
|
||||
orthogonal = np.add(np.multiply(orthogonal, distance), origin).astype(int)
|
||||
return orthogonal
|
||||
|
||||
|
||||
def discrete_segment(start_point, end_point, pixel_perfect=True):
|
||||
"""
|
||||
Calculate a line between two points in 3D space.
|
||||
|
||||
https://www.geeksforgeeks.org/bresenhams-algorithm-for-3-d-line-drawing/
|
||||
|
||||
Args:
|
||||
start_point (tuple): (x, y, z) First coordinates.
|
||||
end_point (tuple): (x, y, z) Second coordinates.
|
||||
pixel_perfect (bool, optional): If true, remove unnecessary coordinates connecting to other coordinates side by side, leaving only a diagonal connection. Defaults to True.
|
||||
|
||||
Returns:
|
||||
list: List of coordinates.
|
||||
"""
|
||||
(x1, y1, z1) = start_point
|
||||
(x2, y2, z2) = end_point
|
||||
x1, y1, z1, x2, y2, z2 = (
|
||||
round(x1),
|
||||
round(y1),
|
||||
round(z1),
|
||||
round(x2),
|
||||
round(y2),
|
||||
round(z2),
|
||||
)
|
||||
|
||||
points = []
|
||||
points.append((x1, y1, z1))
|
||||
dx = abs(x2 - x1)
|
||||
dy = abs(y2 - y1)
|
||||
dz = abs(z2 - z1)
|
||||
if x2 > x1:
|
||||
xs = 1
|
||||
else:
|
||||
xs = -1
|
||||
if y2 > y1:
|
||||
ys = 1
|
||||
else:
|
||||
ys = -1
|
||||
if z2 > z1:
|
||||
zs = 1
|
||||
else:
|
||||
zs = -1
|
||||
|
||||
# Driving axis is X-axis
|
||||
if dx >= dy and dx >= dz:
|
||||
p1 = 2 * dy - dx
|
||||
p2 = 2 * dz - dx
|
||||
while x1 != x2:
|
||||
x1 += xs
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
y1 += ys
|
||||
if not pixel_perfect:
|
||||
if points[-1][1] != y1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dx
|
||||
if p2 >= 0:
|
||||
z1 += zs
|
||||
if not pixel_perfect:
|
||||
if points[-1][2] != z1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dx
|
||||
p1 += 2 * dy
|
||||
p2 += 2 * dz
|
||||
|
||||
# Driving axis is Y-axis
|
||||
elif dy >= dx and dy >= dz:
|
||||
p1 = 2 * dx - dy
|
||||
p2 = 2 * dz - dy
|
||||
while y1 != y2:
|
||||
y1 += ys
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
x1 += xs
|
||||
if not pixel_perfect:
|
||||
if points[-1][0] != x1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dy
|
||||
if p2 >= 0:
|
||||
z1 += zs
|
||||
if not pixel_perfect:
|
||||
if points[-1][2] != z1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dy
|
||||
p1 += 2 * dx
|
||||
p2 += 2 * dz
|
||||
|
||||
# Driving axis is Z-axis
|
||||
else:
|
||||
p1 = 2 * dy - dz
|
||||
p2 = 2 * dx - dz
|
||||
while z1 != z2:
|
||||
z1 += zs
|
||||
points.append((x1, y1, z1))
|
||||
if p1 >= 0:
|
||||
y1 += ys
|
||||
if not pixel_perfect:
|
||||
if points[-1][1] != y1:
|
||||
points.append((x1, y1, z1))
|
||||
p1 -= 2 * dz
|
||||
if p2 >= 0:
|
||||
x1 += xs
|
||||
if not pixel_perfect:
|
||||
if points[-1][0] != x1:
|
||||
points.append((x1, y1, z1))
|
||||
p2 -= 2 * dz
|
||||
p1 += 2 * dy
|
||||
p2 += 2 * dx
|
||||
return points
|
||||
|
||||
|
||||
def middle_point(start_point, end_point):
|
||||
return (np.round((start_point[0] + end_point[0]) / 2.0).astype(int),
|
||||
np.round((start_point[1] + end_point[1]) / 2.0).astype(int),
|
||||
np.round((start_point[2] + end_point[2]) / 2.0).astype(int),
|
||||
)
|
||||
Reference in New Issue
Block a user