"""The module 'discrete_objects' defines coordinates and faces of objects."""
import numpy as np
from ddg.math.parametrizations import circle as circle_fct
[docs]def triangulated_faces(faces):
"""Triangulate faces using fan triangulation.
Parameters
----------
faces: numpy.ndarray of type int and shape (_, _) or (_, )
Indices of the faces as two dimensional array.
Returns
-------
numpy.ndarray of type int and shape (_, 3)
The resulting triangle faces.
"""
triangles = []
for face in faces:
for i in range(1, len(face) - 1):
triangle = face[0], face[i], face[i + 1]
triangles.append(triangle)
return np.array(triangles)
[docs]def tetrahedron_faces():
"""Generate faces of a tetrahedron as numpy.ndarray
The faces have type numpy.ndarray of shape (3,).
They consist of integers representing the adjacent vertices.
Returns
-------
faces : numpy.ndarray of shape (4, 3)
The faces of the tetrahedron
Examples
--------
>>> import ddg.math.discrete_objects as dis_obj
>>> tetra_faces = dis_obj.tetrahedron_faces()
>>> tetra_faces
array([[0, 1, 2],
[2, 3, 0],
[1, 3, 2],
[0, 3, 1]])
"""
faces = np.array([[0, 1, 2], [2, 3, 0], [1, 3, 2], [0, 3, 1]])
return faces
[docs]def tetrahedron_coordinates():
"""Generate coordinates of a tetrahedron as numpy.ndarray
The coordinates are in 3D space. The object is centered at the
origin, meaning at [0,0,0].
Returns
-------
coords : numpy.ndarray of shape (4, 3)
The coordinates of the tetrahedron
Examples
--------
>>> import ddg.math.discrete_objects as dis_obj
>>> tetra_coords = dis_obj.tetrahedron_coordinates()
>>> tetra_coords
array([[ 1, 1, 1],
[ 1, -1, -1],
[-1, 1, -1],
[-1, -1, 1]])
"""
coords = np.array([[1, 1, 1], [1, -1, -1], [-1, 1, -1], [-1, -1, 1]])
return coords
[docs]def cube_faces():
"""Generate faces of a cube as numpy.ndarray
The faces have type numpy.ndarray of shape (4,).
They consist of integers representing the adjacent vertices.
Returns
-------
faces : numpy.ndarray of shape (6, 4)
The faces of the cube
"""
faces = np.array(
[
[4, 5, 1, 0],
[6, 2, 1, 5],
[7, 3, 2, 6],
[4, 0, 3, 7],
[1, 2, 3, 0],
[7, 6, 5, 4],
]
)
return faces
[docs]def cube_coordinates():
"""Generate coordinates of a cube as numpy.ndarray
The coordinates are in 3D space. The object is centered at the
origin, meaning at [0,0,0].
Returns
-------
coords : numpy.ndarray of shape (8, 3)
The coordinates of the cube
"""
coords = np.array(
[
[-1, -1, -1],
[1, -1, -1],
[1, -1, 1],
[-1, -1, 1],
[-1, 1, -1],
[1, 1, -1],
[1, 1, 1],
[-1, 1, 1],
]
)
return coords
[docs]def octahedron_faces():
"""Generate faces of an octahedron as numpy.ndarray
The faces have type numpy.ndarray of shape (3,).
They consist of integers representing the adjacent vertices.
Returns
-------
faces : numpy.ndarray of shape (8, 3)
The faces of the octahedron
"""
faces = np.array(
[
[1, 5, 3],
[1, 3, 4],
[1, 2, 5],
[3, 5, 0],
[1, 4, 2],
[3, 0, 4],
[2, 0, 5],
[2, 4, 0],
]
)
return faces
[docs]def octahedron_coordinates():
"""Generate coordinates of an octahedron as numpy.ndarray
The coordinates are in 3D space. The object is centered at the
origin, meaning at [0,0,0].
Returns
-------
coords : numpy.ndarray of shape (6, 3)
The coordinates of the octahedron
"""
coords = np.array(
[[0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1], [1, 0, 0], [-1, 0, 0]]
)
return coords
[docs]def dodecahedron_faces():
"""Generate faces of a dodecahedron as numpy.ndarray
The faces have type numpy.ndarray of shape (5,).
They consist of integers representing the adjacent vertices.
Returns
-------
faces : numpy.ndarray of shape (12, 5)
The faces of the dodecahedron
"""
faces = np.array(
[
[10, 6, 19, 7, 11],
[11, 3, 17, 2, 10],
[7, 15, 13, 3, 11],
[19, 18, 5, 15, 7],
[6, 14, 4, 18, 19],
[6, 10, 2, 12, 14],
[3, 13, 1, 16, 17],
[17, 16, 0, 12, 2],
[5, 9, 1, 13, 15],
[18, 4, 8, 9, 5],
[1, 9, 8, 0, 16],
[12, 0, 8, 4, 14],
]
)
return faces
[docs]def dodecahedron_coordinates():
"""Generate coordinates of a dodecahedron as numpy.ndarray
The coordinates are in 3D space. The object is centered at the
origin, meaning at [0,0,0].
Returns
-------
coords : numpy.ndarray of shape (20, 3)
The coordinates of the dodecahedron
"""
p = (1 + np.sqrt(5)) / 2
coords = np.array(
[
[1, 1, 1],
[1, 1, -1],
[1, -1, 1],
[1, -1, -1],
[-1, 1, 1],
[-1, 1, -1],
[-1, -1, 1],
[-1, -1, -1],
[0, p, 1 / p],
[0, p, -1 / p],
[0, -p, 1 / p],
[0, -p, -1 / p],
[1 / p, 0, p],
[1 / p, 0, -p],
[-1 / p, 0, p],
[-1 / p, 0, -p],
[p, 1 / p, 0],
[p, -1 / p, 0],
[-p, 1 / p, 0],
[-p, -1 / p, 0],
]
)
return coords
[docs]def icosahedron_faces():
"""Generate faces of an icosahedron as numpy.ndarray
The faces have type numpy.ndarray of shape (3,).
They consist of integers representing the adjacent vertices.
Returns
-------
faces : numpy.ndarray of shape (20, 3)
The faces of the icosahedron
"""
faces = np.array(
[
[9, 4, 2],
[2, 11, 9],
[9, 5, 4],
[2, 4, 0],
[2, 6, 11],
[3, 9, 11],
[3, 5, 9],
[8, 4, 5],
[2, 0, 6],
[8, 0, 4],
[11, 6, 7],
[11, 7, 3],
[3, 1, 5],
[8, 5, 1],
[10, 6, 0],
[10, 0, 8],
[10, 7, 6],
[3, 7, 1],
[8, 1, 10],
[10, 1, 7],
]
)
return faces
[docs]def icosahedron_coordinates():
"""Generate coordinates of an icosahedron as numpy.ndarray
The coordinates are in 3D space. The object is centered at the
origin, meaning at [0,0,0].
Returns
-------
coords : numpy.ndarray of shape (12, 3)
The coordinates of the icosahedron
"""
p = (1 + np.sqrt(5)) / 2
coords = np.array(
[
[0, 1, p],
[0, 1, -p],
[0, -1, p],
[0, -1, -p],
[p, 0, 1],
[p, 0, -1],
[-p, 0, 1],
[-p, 0, -1],
[1, p, 0],
[1, -p, 0],
[-1, p, 0],
[-1, -p, 0],
]
)
return coords
[docs]def disc_face(resolution):
"""Generate the face of a disc as numpy.ndarray
A disc is a circle with an inscribed face.
The face has type numpy.ndarray of shape (`resolution`,).
It consists of integers representing the adjacent vertices.
Parameters
----------
resolution : int
The number of vertices of the disc
Returns
-------
face : numpy.ndarray of shape (1, `resolution`)
The face of the disc
"""
face = np.arange(resolution).reshape((1, resolution))
return face
[docs]def disc_coordinates(resolution, center=(0, 0, 0), normal=(0, 0, 1), radius=1):
"""Generate coordinates of a disc as numpy.ndarray
The coordinates are in 3D space. By default, the disc is centered at
[0,0,0].
Parameters
----------
resolution : int
The number of vertices of the disc
center : iterable (default=(0,0,0))
The center of the disc in 3D space.
normal : iterable (default=(0,0,1))
The normal vector of the disc.
radius : float (default=1)
The radius of the disc.
Returns
-------
coords : numpy.ndarray of shape (n, 3)
The coordinates of the disc where n is the resolution.
"""
t = np.linspace(0, 2 * np.pi, resolution, endpoint=False)
coords = [circle_fct(t[i], center, radius, normal) for i in range(resolution)]
return np.array(coords)
[docs]def cone_faces(resolution):
"""
Generate the face of a cone as numpy.ndarray.
The faces are of type numpy.ndarray with non-uniform lengths. They
consist of integers representing the adjacent vertices.
Parameters
----------
resolution : int
The resolution of the cone.
Returns
-------
numpy.ndarray of shape (n + 1, k)
The faces of the cone where n is the resolution and k varies.
Note that `dtype=object` because of k.
"""
tris = np.vstack(
(
np.arange(resolution),
np.append(np.arange(1, resolution), 0),
np.full(resolution, resolution),
)
)
faces = list(np.split(np.ravel(tris.T), resolution))
faces.insert(0, np.arange(resolution - 1, -1, -1))
return np.array(faces, dtype=object)
[docs]def cone_coordinates(
resolution, radius=1, length=1, center=(0, 0, 0), normal=(0, 0, 1)
):
"""
Generate coordinates of a cone as numpy.ndarray.
The coordinates are in 3D. By default, the cone's bottom is at [0,0,0] and
the cone points upwards.
Parameters
----------
resolution : int
The number of vertices.
radius : float (default=1)
The radius of the base of the cone.
length : float (default=1)
The length of the cone.
center : iterable (default=(0,0,0))
The center of the base.
normal : iterable (default=(0,0,1))
The normal of the cone's base.
Returns
-------
coords : numpy.ndarray of shape (n + 1, 3)
The coordinates of the cone where n is the resolution.
"""
center = np.array(center) + normal / np.linalg.norm(normal) * length / 2
t = np.linspace(0, 2 * np.pi, resolution, endpoint=False)
base_coordinates = np.array(
[
circle_fct(
t[i], (center[0], center[1], center[2] - length / 2), radius, normal
)
for i in range(resolution)
]
)
tip_coordinates = np.array(
[circle_fct(0, (center[0], center[1], center[2] + length / 2), 0, normal)]
)
return np.row_stack((base_coordinates, tip_coordinates))
[docs]def cylinder_faces(resolution):
"""Generate the faces of a cylinder as numpy.ndarray
The faces are of type numpy.ndarray with non-uniform lengths. They
consist of integers representing the adjacent vertices. The first face
is the bottom face, the second the top and the remaining faces
the side faces.
Parameters
----------
resolution : int
The resolution of the cylinder
Returns
-------
faces : numpy.ndarray of shape (n + 2, k)
The faces of the cylinder where n is the resolution and k varies.
Note that `dtype=object` because of k.
"""
# Generate bottom face
faces = [list(range(resolution - 1, -1, -1))]
# Generate top face
faces += [list(range(resolution, 2 * resolution))]
# Generate remaining faces
faces += [
[i, i + 1, i + 1 + resolution, i + resolution] for i in range(resolution - 1)
]
# Add last face separately because it breaks the formula
faces += [[resolution - 1, 0, resolution, 2 * resolution - 1]]
return np.array(faces, dtype=object)
[docs]def cylinder_coordinates(
resolution, top_radius=1, bot_radius=1, length=1, center=(0, 0, 0), normal=(0, 0, 1)
):
"""Generate coordinates of a cylinder as numpy.ndarray
The coordinates are in 3D. By default, the cylinder's bottom is at [0,0,0].
Parameters
----------
resolution : int
The number of vertices at each side.
top_radius : float
The radius of the top of the cylinder.
bot_radius : float
The radius of the bottom of the cylinder.
length : float
The length of the cylinder.
center : iterable (default=(0,0,0))
The center of the bottom of the cylinder.
normal : iterable (default=(0,0,1))
The normal of the cylinder's top and bottom faces.
Returns
-------
coords : numpy.ndarray of shape (2 * n, 3)
The coordinates of the cylinder where n is the resolution.
"""
center = np.array(center) + normal / np.linalg.norm(normal) * length / 2
t = np.linspace(0, 2 * np.pi, resolution, endpoint=False)
bottom_coordinates = np.array(
[
circle_fct(
t[i], (center[0], center[1], center[2] - length / 2), bot_radius, normal
)
for i in range(resolution)
]
)
top_coordinates = np.array(
[
circle_fct(
t[i], (center[0], center[1], center[2] + length / 2), top_radius, normal
)
for i in range(resolution)
]
)
return np.row_stack((bottom_coordinates, top_coordinates))
[docs]def arrow_faces(resolution):
"""Generate faces of an arrow as numpy.ndarray
The faces are of type numpy.ndarray with non-uniform lengths. They
consist of integers representing the adjacent vertices. First bottom
face, then the faces of the stick, then the faces of the base of
the tip and finally the faces of the tip.
Parameters
----------
resolution : int
The resolution of the arrow
Returns
-------
faces : numpy.ndarray of shape (3 * n + 1, k)
The faces of the arrow where n is the resolution and k varies.
Note that `dtype=object` because of k.
"""
# Generate bottom face
faces = [list(range(resolution - 1, -1, -1))]
# Generate faces of the stick
faces += [
[i, i + 1, i + 1 + resolution, i + resolution] for i in range(resolution - 1)
]
# Add last face of the stick
faces += [[resolution - 1, 0, resolution, 2 * resolution - 1]]
# Generate faces of base of tip
faces += [
[i + resolution, i + 1 + resolution, i + 1 + 2 * resolution, i + 2 * resolution]
for i in range(resolution - 1)
]
# Add last face of base of tip separately
faces += [[2 * resolution - 1, resolution, 2 * resolution, 3 * resolution - 1]]
# Generate faces of the tip
faces += [
[i + 2 * resolution, i + 1 + 2 * resolution, 3 * resolution]
for i in range(resolution - 1)
]
# Add last face of tip
faces += [[3 * resolution - 1, 2 * resolution, 3 * resolution]]
return np.array(faces, dtype=object)
[docs]def arrow_coordinates(resolution, heights=(0, 0.7, 0.7, 1), radii=(0.05, 0.05, 0.125)):
"""Generate coordinates of an arrow as numpy.ndarray
The coordinates are in 3D. By default, the arrow's bottom is
at [0,0,0] and it's head at [0,0,1].
Parameters
----------
resolution : int
The resolution of the arrow
heights : iterable (default=(0,0.7,0.7,1))
First element defines height of the bottom of the stick, the
second the height of the top of the stick, the third the
height of the base of the tip and the forth the height of
the tip of the head.
radii : iterable (default=(0.05,0.05,0.125))
First element defines the radius of the bottom of the stick,
second the radius of the top of the stick and the third the
radius of the base of the tip.
Returns
-------
coordinates : numpy.ndarray of shape (3 * n + 1, 3)
The coordinates of the arrow
"""
delta = np.linspace(0, 2 * np.pi, resolution, endpoint=False)
bottom_coordinates = np.column_stack(
(
np.cos(delta) * radii[0],
np.sin(delta) * radii[0],
np.ones(resolution) * heights[0],
)
)
top_coordinates = np.column_stack(
(
np.cos(delta) * radii[1],
np.sin(delta) * radii[1],
np.ones(resolution) * heights[1],
)
)
base_tip_coordinates = np.column_stack(
(
np.cos(delta) * radii[2],
np.sin(delta) * radii[2],
np.ones(resolution) * heights[2],
)
)
tip_coordinates = np.array([0, 0, heights[3]]).reshape((1, 3))
return np.row_stack(
(bottom_coordinates, top_coordinates, base_tip_coordinates, tip_coordinates)
)