def get_plane( self, pos=None, norm=None, plane=None, sx=None, sy=None, color="lightgray", alpha=0.25, **kwargs, ): """ Returns a plane going through a point at pos, oriented orthogonally to the vector norm and of width and height sx, sy. :param pos: 3-tuple or list with x,y,z, coords of point the plane goes through :param norm: 3-tuple with plane's normal vector (optional) :param sx, sy: int, width and height of the plane :param plane: "sagittal", "horizontal", or "frontal" :param color, alpha: plane color and transparency """ axes_pairs = dict(sagittal=(0, 1), horizontal=(2, 0), frontal=(2, 1)) if pos is None: pos = self.root.centerOfMass() try: norm = norm or self.space.plane_normals[plane] except KeyError: # pragma: no cover raise ValueError( # pragma: no cover f"Could not find normals for plane {plane}. Atlas space provides these normals: {self.space.plane_normals}" # pragma: no cover ) # Get plane width and height idx_pair = ( axes_pairs[plane] if plane is not None else axes_pairs["horizontal"] ) bounds = self.root.bounds() root_bounds = [ [bounds[0], bounds[1]], [bounds[2], bounds[3]], [bounds[4], bounds[5]], ] wh = [float(np.diff(root_bounds[i])) for i in idx_pair] if sx is None: sx = wh[0] if sy is None: sy = wh[1] # return plane return Actor( Plane(pos=pos, normal=norm, sx=sx, sy=sy, c=color, alpha=alpha), name=f"Plane at {pos} norm: {norm}", br_class="plane", )
def get_plane_at_point( self, pos=None, norm=None, plane=None, sx=None, sy=None, color="lightgray", alpha=0.25, **kwargs, ): """ Returns a plane going through a point at pos, oriented orthogonally to the vector norm and of width and height sx, sy. :param pos: 3-tuple or list with x,y,z, coords of point the plane goes through :param norm: 3-tuple with plane's normal vector (optional) :param sx, sy: int, width and height of the plane :param plane: "sagittal", "horizontal", or "frontal" :param color, alpha: plane color and transparency """ axes_pairs = dict(sagittal=(0, 1), horizontal=(2, 0), frontal=(2, 1)) # Get position if pos is None: pos = self._root_midpoint elif not isinstance(pos, (list, tuple)) or not len(pos) == 3: raise ValueError(f"Invalid pos argument: {pos}") # Get normal if one is not given if norm is None: try: norm = self.space.plane_normals[plane] except KeyError: raise ValueError( f"Could not find normals for plane {plane}. Atlas space {self.space} provides these normals: {self.spacel.plane_normals}" ) # Get plane width and height idx_pair = ( axes_pairs[plane] if plane is not None else axes_pairs["horizontal"] ) wh = [float(np.diff(self._root_bounds[i])) * 1.2 for i in idx_pair] if sx is None: sx = wh[0] if sy is None: sy = wh[1] # return plane return Plane(pos=pos, normal=norm, sx=sx, sy=sy, c=color, alpha=alpha)
from vedo import Plotter, Plane, datadir vp = Plotter() cow = vp.load(datadir + "cow.vtk", c="grey").scale(4).rotateX(-90) vp += Plane(pos=[0, -3.6, 0], normal=[0, 1, 0], sx=20).texture("grass") vp.show(viewup='y', interactive=0) # vp.light() returns a vtkLight object with focal Point, fp, to mesh cow # fp can also be explicitly set as fp=[x,y,z] l = vp.addLight(pos=[-6, 6, 6], focalPoint=cow, deg=12, showsource=1) # can be switched on/off this way #l.SwitchOff() vp.show(interactive=1)
import trimesh import numpy as np from vedo import show, Plane, printc, download # load the mesh from filename, file objects are also supported f = download( 'https://github.com/mikedh/trimesh/raw/master/models/featuretype.STL') mesh = trimesh.load_mesh(f) # get a single cross section of the mesh txt = 'cross section of the mesh' mslice = mesh.section(plane_origin=mesh.centroid, plane_normal=[0, 0, 1]) pl = Plane(mesh.centroid, normal=[0, 0, 1], sx=6, sy=4, alpha=0.3) slice_2D, to_3D = mslice.to_planar() # show objects on N=2 non-synced renderers: show([(mesh, pl), (slice_2D, txt)], N=2, sharecam=False, axes=True) # if we wanted to take a bunch of parallel slices, like for a 3D printer # we can do that easily with the section_multiplane method # we're going to slice the mesh into evenly spaced chunks along z # this takes the (2,3) bounding box and slices it into [minz, maxz] z_extents = mesh.bounds[:, 2] # slice every .125 model units (eg, inches) z_levels = np.arange(*z_extents, step=0.125) # find a bunch of parallel cross sections sections = mesh.section_multiplane(plane_origin=mesh.bounds[0], plane_normal=[0, 0, 1],
"""Forward kinematics: hover the mouse to drag the chain""" from vedo import Plotter, versor, Plane, Line n = 15 # number of points l = 3 # length of one segment def move(evt): if not evt.actor: return coords = line.points() coords[0] = evt.picked3d for i in range(1, n): v = versor(coords[i] - coords[i - 1]) coords[i] = coords[i - 1] + v * l line.points(coords) # update positions nodes.points(coords) plt.render() plt = Plotter() plt.addCallback("mouse move", move) surf = Plane(sx=60, sy=60) line = Line([l * n / 2, 0], [-l * n / 2, 0], res=n, lw=12) nodes = line.clone().c('red3').pointSize(15) plt.show(surf, line, nodes, __doc__, zoom=1.3).close()