@@ -446,8 +446,7 @@ def marker(
446446 RGB or RGBA values in the range [0, 1].
447447 marker : str or MarkerShape, optional
448448 The shape of the marker.
449- Options are "●": "circle", "+": "plus", "x": "cross", "♥": "heart",
450- "✳": "asterix".
449+ Options are "circle", "plus", "cross", "heart", "asterix".
451450 edge_color : str or tuple or Color, optional
452451 The color of line marking the edge of the markers.
453452 edge_width : float, optional
@@ -756,113 +755,6 @@ def ring(
756755 centers = np .asarray (centers )
757756 n_centers = len (centers )
758757
759- def _as_per_center (values , * , value_name , cast = None ):
760- """Normalize scalar or 1D input to per-center values.
761-
762- Parameters
763- ----------
764- values : float or int or ndarray
765- Scalar-like or one-dimensional input values.
766- value_name : str
767- Name of the parameter, used in error messages.
768- cast : type, optional
769- Optional dtype constructor used to cast the output values.
770-
771- Returns
772- -------
773- ndarray
774- One-dimensional array with one value per center.
775- """
776- arr = np .asarray (values )
777- if arr .ndim == 0 :
778- arr = np .full (n_centers , arr .item ())
779- elif arr .ndim == 1 and arr .size == 1 :
780- arr = np .full (n_centers , arr .item ())
781- elif arr .ndim == 1 and arr .size == n_centers :
782- pass
783- else :
784- raise ValueError (
785- f"{ value_name } size should be 1 or equal to the numbers of centers"
786- )
787-
788- if cast is not None :
789- arr = arr .astype (cast )
790- return arr
791-
792- def _color_at (values , idx ):
793- """Return color for one center from scalar-like or per-center colors.
794-
795- Parameters
796- ----------
797- values : tuple or list or ndarray
798- Either one color (RGB/RGBA) or one color per center.
799- idx : int
800- Center index.
801-
802- Returns
803- -------
804- ndarray
805- Color values for one center.
806- """
807- arr = np .asarray (values )
808- if arr .ndim == 1 and arr .size in (3 , 4 ):
809- return arr
810- if arr .ndim == 2 and arr .shape [0 ] in (1 , n_centers ):
811- return arr [0 ] if arr .shape [0 ] == 1 else arr [idx ]
812- raise ValueError ("colors size should be 1 or equal to the numbers of centers" )
813-
814- def _direction_at (values , idx ):
815- """Return direction for one center from scalar-like or per-center input.
816-
817- Parameters
818- ----------
819- values : tuple or list or ndarray
820- Either one direction or one direction per center.
821- idx : int
822- Center index.
823-
824- Returns
825- -------
826- ndarray
827- Direction vector for one center.
828- """
829- arr = np .asarray (values )
830- if arr .ndim == 1 and arr .size == 3 :
831- return arr
832- if arr .ndim == 2 and arr .shape [0 ] in (1 , n_centers ):
833- return arr [0 ] if arr .shape [0 ] == 1 else arr [idx ]
834- raise ValueError (
835- "directions size should be 1 or equal to the numbers of centers"
836- )
837-
838- def _scale_at (values , idx ):
839- """Return scale for one center from scalar-like or per-center scales.
840-
841- Parameters
842- ----------
843- values : float or tuple or ndarray
844- Either one scale, one XYZ scale, or one scale per center.
845- idx : int
846- Center index.
847-
848- Returns
849- -------
850- float or ndarray
851- Scale value(s) for one center.
852- """
853- arr = np .asarray (values )
854- if arr .ndim == 0 :
855- return arr .item ()
856- if arr .ndim == 1 and arr .size == 1 :
857- return arr .item ()
858- if arr .ndim == 1 and arr .size == 3 :
859- return arr
860- if arr .ndim == 1 and arr .size == n_centers :
861- return arr [idx ]
862- if arr .ndim == 2 and arr .shape [0 ] in (1 , n_centers ) and arr .shape [1 ] == 3 :
863- return arr [0 ] if arr .shape [0 ] == 1 else arr [idx ]
864- raise ValueError ("scales size should be 1 or equal to the numbers of centers" )
865-
866758 if n_centers == 0 :
867759 vertices = np .empty ((0 , 3 ), dtype = np .float32 )
868760 faces = np .empty ((0 , 3 ), dtype = np .int32 )
@@ -906,75 +798,61 @@ def _scale_at(values, idx):
906798 enable_picking = enable_picking ,
907799 )
908800
909- inner_radius_arr = _as_per_center (
910- inner_radius , value_name = "inner_radius" , cast = np .float64
911- )
912- outer_radius_arr = _as_per_center (
913- outer_radius , value_name = "outer_radius" , cast = np .float64
914- )
915- radial_segments_arr = _as_per_center (
916- radial_segments , value_name = "radial_segments" , cast = np .int64
917- )
918- circumferential_segments_arr = _as_per_center (
919- circumferential_segments ,
920- value_name = "circumferential_segments" ,
921- cast = np .int64 ,
922- )
801+ # Per-instance ring parameters -- each ring may have different topology,
802+ # so we generate each mesh separately and concatenate.
803+ ring_params = {
804+ "inner_radius" : np .atleast_1d (np .asarray (inner_radius )),
805+ "outer_radius" : np .atleast_1d (np .asarray (outer_radius )),
806+ "radial_segments" : np .atleast_1d (np .asarray (radial_segments )),
807+ "circumferential_segments" : np .atleast_1d (np .asarray (circumferential_segments )),
808+ }
809+ for name , arr in ring_params .items ():
810+ if arr .size not in (1 , n_centers ):
811+ raise ValueError (
812+ f"{ name } size should be 1 or equal to the numbers of centers"
813+ )
814+
815+ inner_radius_arr = ring_params ["inner_radius" ]
816+ outer_radius_arr = ring_params ["outer_radius" ]
817+ radial_segments_arr = ring_params ["radial_segments" ]
818+ circumferential_segments_arr = ring_params ["circumferential_segments" ]
923819
924820 all_vertices = []
925821 all_faces = []
926- all_colors = []
927822 face_offset = 0
928823
929824 for idx in range (n_centers ):
930- vertices , faces = fp .prim_ring (
825+ verts , tri = fp .prim_ring (
931826 inner_radius = float (inner_radius_arr [idx ]),
932827 outer_radius = float (outer_radius_arr [idx ]),
933828 radial_segments = int (radial_segments_arr [idx ]),
934829 circumferential_segments = int (circumferential_segments_arr [idx ]),
935830 )
936831
937- vertices = vertices .copy ()
938-
939- # Scale
940- vertices *= _scale_at (scales , idx )
941-
942- # Rotate according to direction
943- dirs = _direction_at (directions , idx )
944- dir_abs = np .linalg .norm (dirs )
945- if dir_abs :
946- normal = np .array ([1.0 , 0.0 , 0.0 ])
947- dirs = dirs / dir_abs
948- v = np .cross (normal , dirs )
949- c = np .dot (normal , dirs )
950-
951- vmat = np .array ([[0 , - v [2 ], v [1 ]], [v [2 ], 0 , - v [0 ]], [- v [1 ], v [0 ], 0 ]])
952-
953- if c == - 1.0 :
954- rotation_matrix = - np .eye (3 , dtype = np .float64 )
955- else :
956- h = 1 / (1 + c )
957- rotation_matrix = (
958- np .eye (3 , dtype = np .float64 ) + vmat + (vmat .dot (vmat ) * h )
959- )
960- else :
961- rotation_matrix = np .identity (3 )
962-
963- vertices = np .dot (rotation_matrix [:3 , :3 ], vertices .T ).T
964-
965832 # Translate to center
966- vertices += centers [idx ]
833+ verts = verts + centers [idx ]
967834
968- all_vertices .append (vertices )
969- all_faces .append (faces + face_offset )
970- color_i = _color_at (colors , idx )
971- all_colors .append (np .repeat (color_i [np .newaxis , :], len (vertices ), axis = 0 ))
972-
973- face_offset += len (vertices )
835+ all_vertices .append (verts )
836+ all_faces .append (tri + face_offset )
837+ face_offset += len (verts )
974838
975839 big_vertices = np .concatenate (all_vertices , axis = 0 )
976840 big_faces = np .concatenate (all_faces , axis = 0 )
977- big_colors = np .concatenate (all_colors , axis = 0 )
841+
842+ # Expand colors to per-vertex
843+ colors_arr = np .asarray (colors )
844+ if colors_arr .ndim == 1 and colors_arr .size in (3 , 4 ):
845+ big_colors = np .tile (colors_arr , (len (big_vertices ), 1 ))
846+ elif colors_arr .ndim == 2 and colors_arr .shape [0 ] == n_centers :
847+ per_ring_sizes = [len (v ) for v in all_vertices ]
848+ big_colors = np .concatenate (
849+ [np .tile (colors_arr [i ], (per_ring_sizes [i ], 1 )) for i in range (n_centers )],
850+ axis = 0 ,
851+ )
852+ else :
853+ big_colors = np .tile (
854+ np .asarray ([1 , 1 , 1 ], dtype = np .float32 ), (len (big_vertices ), 1 )
855+ )
978856
979857 obj = actor_from_primitive (
980858 big_vertices ,
0 commit comments