Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add static mesh, new shapes, dynamic color and variable render resolution #47

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5463457
Add static rendering
phohenberger Jun 3, 2024
8e74a75
Fix record video and add static vector field
phohenberger Jun 3, 2024
146f260
Fix screen shot and remove old code
phohenberger Jun 4, 2024
bc59c94
Fix record_mesh_trajectory for static mesh
phohenberger Jun 4, 2024
e65befe
Fix static_mesh bug
phohenberger Jun 10, 2024
6d72213
Add variable resolution and size
phohenberger Jun 12, 2024
402b57d
Add most open3d base shapes
phohenberger Jun 12, 2024
03e4de6
Add shapes to __init__.py
phohenberger Jun 12, 2024
6027a9f
Fix box shape
phohenberger Jun 12, 2024
9c47384
Adapt to typo in open3D
phohenberger Jun 12, 2024
a0ad74b
Fix spp argument
phohenberger Jun 13, 2024
604f999
Fix typo
phohenberger Jun 13, 2024
a052fa9
Skip vector of length zero
phohenberger Jun 13, 2024
b32f67c
Fix typos and cone parameters
phohenberger Jun 13, 2024
13ccae4
Merge pull request #1 from phohenberger/add_shapes
phohenberger Jun 13, 2024
6dcd617
Merge pull request #2 from phohenberger/resolution_and_spp
phohenberger Jun 13, 2024
c523b7d
Merge pull request #3 from phohenberger/static_mesh
phohenberger Jun 13, 2024
18dbbe6
Fix bug for negative direction
phohenberger Jun 20, 2024
a0e9b76
Move mesh creation to parent class
phohenberger Jun 28, 2024
74c4547
Fix import path
phohenberger Jun 28, 2024
d6adfa6
Update remaining mesh
phohenberger Jul 2, 2024
447fa7a
Add dynamic mesh coloring
phohenberger Jul 6, 2024
d64daca
Unify function names
phohenberger Jul 7, 2024
c4c396e
Merge pull request #4 from phohenberger/dynamic_color
phohenberger Jul 10, 2024
ab5f5e5
Update tests and fix function naming
phohenberger Jul 10, 2024
d1e63e9
Add examples for vector_field, dynamic_color and new shapes
phohenberger Jul 10, 2024
fb840e9
Remove dynamic_color flag
phohenberger Jul 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CI/unit_tests/mesh/test_cylinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_build_cylinder(self):
-------
Test if a sphere mesh is constructed correctly.
"""
cylinder = self.cylinder.create_mesh(
cylinder = self.cylinder.instantiate_mesh(
starting_position=np.array([1, 1, 1]),
starting_orientation=np.array([1, 1, 1]),
)
Expand Down
2 changes: 1 addition & 1 deletion CI/unit_tests/mesh/test_sphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def test_build_sphere(self):
-------
Test if a sphere mesh is constructed correctly.
"""
sphere = self.sphere.create_mesh(starting_position=np.array([1, 1, 1]))
sphere = self.sphere.instantiate_mesh(starting_position=np.array([1, 1, 1]))
self.assertEqual(sphere.has_vertex_normals(), True)
self.assertEqual(type(sphere), o3d.geometry.TriangleMesh)
np.testing.assert_almost_equal(sphere.get_center(), [1.0, 1.0, 1.0])
123 changes: 123 additions & 0 deletions examples/all_shapes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"""
ZnVis: A Zincwarecode package.
License
-------
This program and the accompanying materials are made available under the terms
of the Eclipse Public License v2.0 which accompanies this distribution, and is
available at https://www.eclipse.org/legal/epl-v20.html
SPDX-License-Identifier: EPL-2.0
Copyright Contributors to the Zincwarecode Project.
Contact Information
-------------------
email: [email protected]
github: https://github.com/zincware
web: https://zincwarecode.com/
Citation
--------
If you use this module please cite us with:

Summary
-------
Tutorial script to visualize simple spheres over a random trajectory.
"""

import numpy as np

import znvis as vis

if __name__ == "__main__":
"""
Run the all shapes example.
"""

material_1 = vis.Material(colour=np.array([30, 144, 255]) / 255, alpha=0.9)
# Define the sphere.
trajectory = np.random.uniform(-10, 10, (10, 1, 3))
mesh = vis.Sphere(radius=2.0, material=material_1, resolution=30)
particle = vis.Particle(name="Sphere", mesh=mesh, position=trajectory)

material_2 = vis.Material(colour=np.array([255, 140, 0]) / 255, alpha=1.0)
# Define the cylinder.
trajectory_2 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_2 = vis.Cylinder(radius=1.0,
height=2.0,
split=1,
material=material_2,
resolution=30)
particle_2 = vis.Particle(name="Cylinder", mesh=mesh_2, position=trajectory_2)

material_3 = vis.Material(colour=np.array([100, 255, 130]) / 255, alpha=1.0)
# Define the icosahedron.
trajectory_3 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_3 = vis.Icosahedron(radius=2.0, material=material_3)
particle_3 = vis.Particle(name="Icosahedron", mesh=mesh_3, position=trajectory_3)

material_4 = vis.Material(colour=np.array([255, 200, 50]) / 255, alpha=1.0)
# Define the torus.
trajectory_4 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_4 = vis.Torus(torus_radius=1.0,
tube_radius=0.5,
tubular_resolution=30,
radial_resolution=30,
material=material_4)
particle_4 = vis.Particle(name="Torus", mesh=mesh_4, position=trajectory_4)

material_5 = vis.Material(colour=np.array([250, 50, 20]) / 255, alpha=1.0)
# Define the mobius loop.
trajectory_5 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_5 = vis.MobiusLoop(twists=3,
radius=2,
flatness=1,
width=2, scale=1,
length_split=200,
width_split=200,
material=material_5)
particle_5 = vis.Particle(name="MobiusLoop", mesh=mesh_5, position=trajectory_5)

material_6 = vis.Material(colour=np.array([255, 90, 255]) / 255, alpha=1.0)
# Define the octahedron.
trajectory_6 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_6 = vis.Octahedron(radius=2.0, material=material_6)
particle_6 = vis.Particle(name="Octahedron", mesh=mesh_6, position=trajectory_6)

material_7 = vis.Material(colour=np.array([255, 220, 100]) / 255, alpha=1.0)
# Define the tetrahedron.
trajectory_7 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_7 = vis.Tetrahedron(radius=2.0, material=material_7)
particle_7 = vis.Particle(name="Tetrahedron", mesh=mesh_7, position=trajectory_7)

material_8 = vis.Material(colour=np.array([255, 200, 240]) / 255, alpha=1.0)
# Define the arrow.
trajectory_8 = np.random.uniform(-10, 10, (10, 1, 3))
direction_8 = np.random.uniform(-1, 1, (10, 1, 3))
mesh_8 = vis.Arrow(scale=2, material=material_8, resolution=30)
particle_8 = vis.Particle(name="Arrow",
mesh=mesh_8,
position=trajectory_8,
director=direction_8)

material_9 = vis.Material(colour=np.array([150, 255, 230]) / 255, alpha=1.0)
# Define the box.
trajectory_9 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_9 = vis.Box(width=1, height=3, depth=0.5, material=material_9)
particle_9 = vis.Particle(name="BoxMesh", mesh=mesh_9, position=trajectory_9)

material_10 = vis.Material(colour=np.array([255, 10, 100]) / 255, alpha=1.0)
# Define the cone.
trajectory_10 = np.random.uniform(-10, 10, (10, 1, 3))
mesh_10 = vis.Cone(radius=1.0, height=2.0, material=material_10, resolution=30)
particle_10 = vis.Particle(name="Cone", mesh=mesh_10, position=trajectory_10)

particle_list = [particle, particle_2, particle_3, particle_4, particle_5,
particle_6, particle_7, particle_8, particle_9, particle_10]

# Create a bounding box
bounding_box = vis.BoundingBox(
center=np.array([0, 0, 0]), box_size=np.array([20, 20, 20])
)

# Construct the visualizer and run
visualizer = vis.Visualizer(
particles=particle_list, frame_rate=20, bounding_box=bounding_box
)
visualizer.run_visualization()
64 changes: 64 additions & 0 deletions examples/dynamic_coloring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
ZnVis: A Zincwarecode package.
License
-------
This program and the accompanying materials are made available under the terms
of the Eclipse Public License v2.0 which accompanies this distribution, and is
available at https://www.eclipse.org/legal/epl-v20.html
SPDX-License-Identifier: EPL-2.0
Copyright Contributors to the Zincwarecode Project.
Contact Information
-------------------
email: [email protected]
github: https://github.com/zincware
web: https://zincwarecode.com/
Citation
--------
If you use this module please cite us with:

Summary
-------
Tutorial script to visualize simple spheres over a random trajectory.
"""

import numpy as np

import znvis as vis

if __name__ == "__main__":
"""
Run the dynamic color example.
"""

# Create a color list (N_frames, N_particles, 3 (RGB))
# Basically give each particle a specified color for each frame
colours = np.tile([30, 144, 255], (100, 5, 1))
# Change the color of the first particle to red
colours[:, 0, 0] = np.linspace(30, 255, 100)
# Change the color of the second particle to green
colours[:, 1, 1] = np.linspace(144, 255, 100)
colours[:, 1, 2] = np.linspace(255, 30, 100)
# Change the color of the third particle to blue
colours[:, 2, 0] = np.linspace(30, 10, 100)
colours[:, 2, 1] = np.linspace(140, 90, 100)
# Change the color of the fourth particle to white
colours[:, 3, 0] = np.linspace(30, 255, 100)
colours[:, 3, 1] = np.linspace(144, 255, 100)
# Change the color of the fifth particle to black
colours[:, 4, 0] = np.linspace(30, 0, 100)
colours[:, 4, 1] = np.linspace(144, 0, 100)
colours[:, 4, 2] = np.linspace(255, 0, 100)

material_1 = vis.Material(colour=colours / 255, alpha=1.0)
# Define the first particle.
trajectory = np.random.uniform(-5, 5, (1, 5, 3))
trajectory = np.tile(trajectory, (100, 1, 1))
# Turn on dynamic coloring for the mesh
mesh = vis.Sphere(radius=2.0, resolution=20, material=material_1)
particle = vis.Particle(
name="Spheres", mesh=mesh, position=trajectory, smoothing=False
)

# Construct the visualizer and run
visualizer = vis.Visualizer(particles=[particle], frame_rate=20)
visualizer.run_visualization()
72 changes: 72 additions & 0 deletions examples/simple_vector_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
ZnVis: A Zincwarecode package.
License
-------
This program and the accompanying materials are made available under the terms
of the Eclipse Public License v2.0 which accompanies this distribution, and is
available at https://www.eclipse.org/legal/epl-v20.html
SPDX-License-Identifier: EPL-2.0
Copyright Contributors to the Zincwarecode Project.
Contact Information
-------------------
email: [email protected]
github: https://github.com/zincware
web: https://zincwarecode.com/
Citation
--------
If you use this module please cite us with:

Summary
-------
Tutorial script to visualize simple spheres over a random trajectory.
"""

import numpy as np

import znvis as vis

if __name__ == "__main__":
"""
Run the vector field example.
"""

# Build a grid
x_values = np.linspace(-10, 10, 21)
y_values = np.linspace(-10, 10, 21)
z_values = np.linspace(0, 0, 1)

grid = np.meshgrid(x_values, y_values, z_values)
grid = np.array(grid).T.reshape(-1, 3)
grid = np.tile(grid, (100, 1, 1))

# Define arrow mesh and insert in vector field
material = vis.Material(colour=np.array([30, 144, 255]) / 255, alpha=0.6)
mesh = vis.Arrow(scale=0.5, resolution=20, material=material)

directions = np.random.uniform(-1, 1, (100, 441, 3))
# confine the directions to be in the z = 0 plane
directions[:,:,2] = 0

vector_field = vis.VectorField(name="VectorField",
mesh=mesh,
position=grid,
direction=directions)

# Define particles
material_2 = vis.Material(colour=np.array([255, 140, 0]) / 255, alpha=1.0)
mesh_2 = vis.Sphere(radius=1.0, resolution=20, material=material_2)

trajectory_2 = np.random.uniform(-10, 10, (100, 1, 3))
# confine the particles to be in the z = 0 plane
trajectory_2[:,:,2] = 0

particle = vis.Particle(name="Spheres",
mesh=mesh_2,
position=trajectory_2,
smoothing=False)

# Construct the visualizer and run
visualizer = vis.Visualizer(particles=[particle],
vector_field=[vector_field],
frame_rate=20)
visualizer.run_visualization()
14 changes: 14 additions & 0 deletions znvis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
from znvis.mesh.cylinder import Cylinder
from znvis.mesh.sphere import Sphere
from znvis.mesh.arrow import Arrow
from znvis.mesh.box import Box
from znvis.mesh.cone import Cone
from znvis.mesh.tetrahedron import Tetrahedron
from znvis.mesh.octahedron import Octahedron
from znvis.mesh.icosahedron import Icosahedron
from znvis.mesh.torus import Torus
from znvis.mesh.mobius_loop import MobiusLoop
from znvis.particle.particle import Particle
from znvis.particle.vector_field import VectorField
from znvis.visualizer.visualizer import Visualizer
Expand All @@ -37,6 +44,13 @@
Particle.__name__,
Sphere.__name__,
Arrow.__name__,
Box.__name__,
Cone.__name__,
Tetrahedron.__name__,
Octahedron.__name__,
Icosahedron.__name__,
Torus.__name__,
MobiusLoop.__name__,
VectorField.__name__,
Visualizer.__name__,
Cylinder.__name__,
Expand Down
43 changes: 19 additions & 24 deletions znvis/mesh/arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
@dataclass
class Arrow(Mesh):
"""
A class to produce arrow meshes.
A class to produce arrow meshes. Arrow meshes are a special case and need to
overwrite the instantiate_mesh of the parent mesh class.

Attributes
----------
Expand All @@ -46,44 +47,38 @@ class Arrow(Mesh):
scale: float = 1.0
resolution: int = 10

def create_mesh(
self, starting_position: np.ndarray, direction: np.ndarray = None
def instantiate_mesh(
self, starting_position: np.ndarray, starting_orientation: np.ndarray = None
) -> o3d.geometry.TriangleMesh:
"""
Create a mesh object defined by the dataclass.
Create and correctly orient an arrow mesh. Overwrites the parent class
"""
mesh = self.create_mesh(starting_orientation)
mesh.compute_vertex_normals()
if starting_orientation is not None:
matrix = rotation_matrix(np.array([0, 0, 1]), starting_orientation)
mesh.rotate(matrix, center=(0, 0, 0))

Parameters
----------
starting_position : np.ndarray shape=(3,)
Starting position of the mesh.
direction : np.ndarray shape=(3,) (default = None)
Direction of the mesh.
# Translate the arrow to the starting position and center the origin
mesh.translate(starting_position.astype(float))

Returns
-------
mesh : o3d.geometry.TriangleMesh
"""
return mesh

def create_mesh(self, direction: np.ndarray) -> o3d.geometry.TriangleMesh:
"""
Creates an arrow mesh object.
"""
direction_length = np.linalg.norm(direction)

cylinder_radius = 0.06 * direction_length * self.scale
cylinder_height = 0.85 * direction_length * self.scale
cone_radius = 0.15 * direction_length * self.scale
cone_height = 0.15 * direction_length * self.scale

arrow = o3d.geometry.TriangleMesh.create_arrow(
return o3d.geometry.TriangleMesh.create_arrow(
cylinder_radius=cylinder_radius,
cylinder_height=cylinder_height,
cone_radius=cone_radius,
cone_height=cone_height,
resolution=self.resolution
)

arrow.compute_vertex_normals()
matrix = rotation_matrix(np.array([0, 0, 1]), direction)
arrow.rotate(matrix, center=(0, 0, 0))

# Translate the arrow to the starting position and center the origin
arrow.translate(starting_position.astype(float))

return arrow
Loading
Loading