Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
80 changes: 67 additions & 13 deletions fury/actor/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ def actor_from_primitive(
smooth=False,
enable_picking=True,
repeat_primitive=True,
have_tiled_verts=False,
wireframe=False,
wireframe_thickness=1.0,
):
Expand Down Expand Up @@ -384,6 +385,9 @@ def actor_from_primitive(
repeat_primitive : bool, optional
Whether to repeat the primitive for each center. If False,
only one instance of the primitive is created at the first center.
have_tiled_verts : bool, optional
If True, vertices are already tiled (one set per center) and should
not be duplicated again inside ``repeat_primitive``.
wireframe : bool, optional
Whether to render the mesh as a wireframe.
wireframe_thickness : float, optional
Expand All @@ -404,6 +408,7 @@ def actor_from_primitive(
directions=directions,
colors=colors,
scales=scales,
have_tiled_verts=have_tiled_verts,
)
big_vertices, big_faces, big_colors, _ = res

Expand Down Expand Up @@ -476,17 +481,21 @@ def arrow(
The orientation vector of the arrow.
colors : ndarray, shape (N, 3) or (N, 4) or tuple (3,) or tuple (4,), optional
RGB or RGBA (for opacity) R, G, B, and A should be in the range [0, 1].
height : float, optional
The total height of the arrow, including the shaft and tip.
height : float or ndarray, shape (N,), optional
The total height of the arrow, including the shaft and tip. A single
value applies to all arrows, while an array specifies a value per arrow.
resolution : int, optional
The number of divisions along the arrow's circular cross-sections.
Higher values produce smoother arrows.
tip_length : float, optional
The length of the arrowhead tip relative to the total height.
tip_radius : float, optional
The radius of the arrowhead tip.
shaft_radius : float, optional
The radius of the arrow shaft.
tip_length : float or ndarray, shape (N,), optional
The length of the arrowhead tip relative to the total height. A single
value applies to all arrows, while an array specifies a value per arrow.
tip_radius : float or ndarray, shape (N,), optional
The radius of the arrowhead tip. A single value applies to all arrows,
while an array specifies a value per arrow.
shaft_radius : float or ndarray, shape (N,), optional
The radius of the arrow shaft. A single value applies to all arrows,
while an array specifies a value per arrow.
scales : ndarray, shape (N, 3) or tuple (3,) or float, optional
The size of the arrow in each dimension. If a single value is
provided, the same size will be used for all arrows.
Expand Down Expand Up @@ -518,13 +527,57 @@ def arrow(
>>> show_manager.start()
"""

vertices, faces = fp.prim_arrow(
height=height,
n_centers = len(centers)
height_arr = fp._normalize_geom_param(height, n_centers, "height")
tip_length_arr = fp._normalize_geom_param(tip_length, n_centers, "tip_length")
tip_radius_arr = fp._normalize_geom_param(tip_radius, n_centers, "tip_radius")
shaft_radius_arr = fp._normalize_geom_param(shaft_radius, n_centers, "shaft_radius")

# Fast path: all uniform
if (
np.all(height_arr == height_arr[0])
and np.all(tip_length_arr == tip_length_arr[0])
and np.all(tip_radius_arr == tip_radius_arr[0])
and np.all(shaft_radius_arr == shaft_radius_arr[0])
):
vertices, faces = fp.prim_arrow(
height=height_arr[0],
resolution=resolution,
tip_length=tip_length_arr[0],
tip_radius=tip_radius_arr[0],
shaft_radius=shaft_radius_arr[0],
)
return actor_from_primitive(
vertices,
faces,
centers=centers,
colors=colors,
scales=scales,
directions=directions,
opacity=opacity,
material=material,
enable_picking=enable_picking,
)

# Slow path: per-instance geometry
_, faces = fp.prim_arrow(
height=height_arr[0],
resolution=resolution,
tip_length=tip_length,
tip_radius=tip_radius,
shaft_radius=shaft_radius,
tip_length=tip_length_arr[0],
tip_radius=tip_radius_arr[0],
shaft_radius=shaft_radius_arr[0],
)
all_verts = [
fp.prim_arrow(
height=height_arr[i],
resolution=resolution,
tip_length=tip_length_arr[i],
tip_radius=tip_radius_arr[i],
shaft_radius=shaft_radius_arr[i],
)[0]
for i in range(n_centers)
]
vertices = np.concatenate(all_verts)
return actor_from_primitive(
vertices,
faces,
Expand All @@ -535,6 +588,7 @@ def arrow(
opacity=opacity,
material=material,
enable_picking=enable_picking,
have_tiled_verts=True,
)


Expand Down
76 changes: 69 additions & 7 deletions fury/actor/curved.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,9 @@ def cylinder(
Cylinder positions.
colors : ndarray, shape (N, 3) or (N, 4) or tuple (3,) or tuple (4,), optional
RGB or RGBA (for opacity) R, G, B, and A should be in the range [0, 1].
height : float, optional
The height of the cylinder.
height : float or ndarray, shape (N,), optional
The height of the cylinder. A single value applies to all cylinders,
while an array specifies a height for each cylinder individually.
sectors : int, optional
The number of divisions around the cylinder's circumference.
Higher values produce smoother cylinders.
Expand Down Expand Up @@ -369,10 +370,40 @@ def cylinder(
>>> show_manager = window.ShowManager(scene=scene, size=(600, 600))
>>> show_manager.start()
"""
n_centers = len(centers)
radii_arr = fp._normalize_geom_param(radii, n_centers, "radii")
height_arr = fp._normalize_geom_param(height, n_centers, "height")

# Fast path: all uniform
if np.all(radii_arr == radii_arr[0]) and np.all(height_arr == height_arr[0]):
vertices, faces = fp.prim_cylinder(
radius=radii_arr[0], height=height_arr[0], sectors=sectors, capped=capped
)
return actor_from_primitive(
vertices,
faces,
centers=centers,
colors=colors,
scales=scales,
directions=directions,
opacity=opacity,
material=material,
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
)

vertices, faces = fp.prim_cylinder(
radius=radii, height=height, sectors=sectors, capped=capped
# Slow path: per-instance geometry
_, faces = fp.prim_cylinder(
radius=radii_arr[0], height=height_arr[0], sectors=sectors, capped=capped
)
all_verts = [
fp.prim_cylinder(
radius=radii_arr[i], height=height_arr[i], sectors=sectors, capped=capped
)[0]
for i in range(n_centers)
]
vertices = np.concatenate(all_verts)
return actor_from_primitive(
vertices,
faces,
Expand All @@ -385,6 +416,7 @@ def cylinder(
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
have_tiled_verts=True,
)


Expand All @@ -411,8 +443,9 @@ def cone(
Cone positions.
colors : ndarray, shape (N, 3) or (N, 4) or tuple (3,) or tuple (4,), optional
RGB or RGBA (for opacity) R, G, B, and A should be in the range [0, 1].
height : float, optional
The height of the cone.
height : float or ndarray, shape (N,), optional
The height of the cone. A single value applies to all cones,
while an array specifies a height for each cone individually.
sectors : int, optional
The number of divisions around the cone's circumference.
Higher values produce smoother cones.
Expand Down Expand Up @@ -455,8 +488,36 @@ def cone(
>>> show_manager = window.ShowManager(scene=scene, size=(600, 600))
>>> show_manager.start()
"""
n_centers = len(centers)
radii_arr = fp._normalize_geom_param(radii, n_centers, "radii")
height_arr = fp._normalize_geom_param(height, n_centers, "height")

# Fast path: all uniform
if np.all(radii_arr == radii_arr[0]) and np.all(height_arr == height_arr[0]):
vertices, faces = fp.prim_cone(
radius=radii_arr[0], height=height_arr[0], sectors=sectors
)
return actor_from_primitive(
vertices,
faces,
centers=centers,
colors=colors,
scales=scales,
directions=directions,
opacity=opacity,
material=material,
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
)

vertices, faces = fp.prim_cone(radius=radii, height=height, sectors=sectors)
# Slow path: per-instance geometry
_, faces = fp.prim_cone(radius=radii_arr[0], height=height_arr[0], sectors=sectors)
all_verts = [
fp.prim_cone(radius=radii_arr[i], height=height_arr[i], sectors=sectors)[0]
for i in range(n_centers)
]
vertices = np.concatenate(all_verts)
return actor_from_primitive(
vertices,
faces,
Expand All @@ -469,6 +530,7 @@ def cone(
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
have_tiled_verts=True,
)


Expand Down
79 changes: 71 additions & 8 deletions fury/actor/planar.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,32 @@ def disk(
>>> show_manager = window.ShowManager(scene=scene, size=(600, 600))
>>> show_manager.start()
"""
n_centers = len(centers)
radii_arr = fp._normalize_geom_param(radii, n_centers, "radii")

# Fast path: all uniform
if np.all(radii_arr == radii_arr[0]):
vertices, faces = fp.prim_disk(radius=radii_arr[0], sectors=sectors)
return actor_from_primitive(
vertices,
faces,
centers=centers,
colors=colors,
scales=scales,
directions=directions,
opacity=opacity,
material=material,
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
)

vertices, faces = fp.prim_disk(radius=radii, sectors=sectors)
# Slow path: per-instance geometry
_, faces = fp.prim_disk(radius=radii_arr[0], sectors=sectors)
all_verts = [
fp.prim_disk(radius=radii_arr[i], sectors=sectors)[0] for i in range(n_centers)
]
vertices = np.concatenate(all_verts)
return actor_from_primitive(
vertices,
faces,
Expand All @@ -258,6 +282,7 @@ def disk(
enable_picking=enable_picking,
wireframe=wireframe,
wireframe_thickness=wireframe_thickness,
have_tiled_verts=True,
)


Expand Down Expand Up @@ -706,10 +731,12 @@ def ring(
----------
centers : ndarray, shape (N, 3)
Ring positions.
inner_radius : float, optional
The inner radius of the ring (radius of the hole).
outer_radius : float, optional
The outer radius of the ring.
inner_radius : float or ndarray, shape (N,), optional
The inner radius of the ring (radius of the hole). A single value
applies to all rings, while an array specifies a value per ring.
outer_radius : float or ndarray, shape (N,), optional
The outer radius of the ring. A single value applies to all rings,
while an array specifies a value per ring.
radial_segments : int, optional
Number of segments along the radial direction.
circumferential_segments : int, optional
Expand Down Expand Up @@ -748,12 +775,47 @@ def ring(
>>> show_manager = window.ShowManager(scene=scene, size=(600, 600))
>>> show_manager.start()
"""
vertices, faces = fp.prim_ring(
inner_radius=inner_radius,
outer_radius=outer_radius,
n_centers = len(centers)
inner_arr = fp._normalize_geom_param(inner_radius, n_centers, "inner_radius")
outer_arr = fp._normalize_geom_param(outer_radius, n_centers, "outer_radius")

# Fast path: all uniform – single primitive, no tiling needed
if np.all(inner_arr == inner_arr[0]) and np.all(outer_arr == outer_arr[0]):
vertices, faces = fp.prim_ring(
inner_radius=inner_arr[0],
outer_radius=outer_arr[0],
radial_segments=radial_segments,
circumferential_segments=circumferential_segments,
)
return actor_from_primitive(
vertices,
faces,
centers=centers,
colors=colors,
scales=scales,
directions=directions,
opacity=opacity,
material=material,
enable_picking=enable_picking,
)

# Slow path: per-instance geometry
_, faces = fp.prim_ring(
inner_radius=inner_arr[0],
outer_radius=outer_arr[0],
radial_segments=radial_segments,
circumferential_segments=circumferential_segments,
)
all_verts = [
fp.prim_ring(
inner_radius=inner_arr[i],
outer_radius=outer_arr[i],
radial_segments=radial_segments,
circumferential_segments=circumferential_segments,
)[0]
for i in range(n_centers)
]
vertices = np.concatenate(all_verts)
return actor_from_primitive(
vertices,
faces,
Expand All @@ -764,6 +826,7 @@ def ring(
opacity=opacity,
material=material,
enable_picking=enable_picking,
have_tiled_verts=True,
)


Expand Down
Loading