def pca(points, pvalue=.95, c='c', alpha=0.5, pcaAxes=False, legend=None): ''' Show the oriented PCA ellipsoid that contains fraction pvalue of points. axes = True, show the 3 PCA semi axes Extra info is stored in actor.sphericity, actor.va, actor.vb, actor.vc (sphericity = 1 for a perfect sphere) ''' try: from scipy.stats import f except: vc.printc("Error in ellipsoid(): scipy not installed. Skip.",1) return None if isinstance(points, vtk.vtkActor): points=vu.coordinates(points) if len(points) == 0: return None P = np.array(points, ndmin=2, dtype=float) cov = np.cov(P, rowvar=0) # covariance matrix U, s, R = np.linalg.svd(cov) # singular value decomposition p, n = s.size, P.shape[0] fppf = f.ppf(pvalue, p, n-p)*(n-1)*p*(n+1)/n/(n-p) # f % point function ua,ub,uc = np.sqrt(s*fppf)*2 # semi-axes (largest first) center = np.mean(P, axis=0) # centroid of the hyperellipsoid sphericity = ( ((ua-ub)/(ua+ub))**2 + ((ua-uc)/(ua+uc))**2 + ((ub-uc)/(ub+uc))**2 )/3. *4. elliSource = vtk.vtkSphereSource() elliSource.SetThetaResolution(48) elliSource.SetPhiResolution(48) matri = vtk.vtkMatrix4x4() matri.DeepCopy((R[0][0] *ua, R[1][0] *ub, R[2][0] *uc, center[0], R[0][1] *ua, R[1][1] *ub, R[2][1] *uc, center[1], R[0][2] *ua, R[1][2] *ub, R[2][2] *uc, center[2], 0,0,0,1)) vtra = vtk.vtkTransform() vtra.SetMatrix(matri) ftra = vtk.vtkTransformFilter() ftra.SetTransform(vtra) ftra.SetInputConnection(elliSource.GetOutputPort()) ftra.Update() actor_elli = vu.makeActor(ftra.GetOutput(), c, alpha, legend=legend) actor_elli.GetProperty().BackfaceCullingOn() actor_elli.GetProperty().SetInterpolationToPhong() if pcaAxes: axs = [] for ax in ([1,0,0], [0,1,0], [0,0,1]): l = vtk.vtkLineSource() l.SetPoint1([0,0,0]) l.SetPoint2(ax) l.Update() t = vtk.vtkTransformFilter() t.SetTransform(vtra) vu.setInput(t, l.GetOutput()) t.Update() axs.append(vu.makeActor(t.GetOutput(), c, alpha)) finact = vu.makeAssembly([actor_elli]+axs, legend=legend) else : finact = actor_elli setattr(finact, 'sphericity', sphericity) setattr(finact, 'va', ua) setattr(finact, 'vb', ub) setattr(finact, 'vc', uc) return finact
def line(p0, p1=None, lw=1, tube=False, dotted=False, c='r', alpha=1., legend=None): '''Build the line segment between points p0 and p1. if p0 is a list of points returns the line connecting them. if tube=True, lines are rendered as tubes of radius lw ''' #detect if user is passing a list of points: if vu.isSequence(p0[0]): ppoints = vtk.vtkPoints() # Generate the polyline poly = vtk.vtkPolyData() for i in range(len(p0)): p = p0[i] ppoints.InsertPoint(i, p[0], p[1], p[2]) lines = vtk.vtkCellArray() # Create the polyline. lines.InsertNextCell(len(p0)) for i in range(len(p0)): lines.InsertCellPoint(i) poly.SetPoints(ppoints) poly.SetLines(lines) else: # or just 2 points to link lineSource = vtk.vtkLineSource() lineSource.SetPoint1(p0) lineSource.SetPoint2(p1) lineSource.Update() poly = lineSource.GetOutput() if tube: tuf = vtk.vtkTubeFilter() tuf.SetNumberOfSides(12) #tuf.CappingOn() vu.setInput(tuf, poly) tuf.SetRadius(lw) tuf.Update() poly = tuf.GetOutput() actor = vu.makeActor(poly, c, alpha, legend=legend) actor.GetProperty().SetInterpolationToPhong() else: actor = vu.makeActor(poly, c, alpha, legend=legend) actor.GetProperty().SetLineWidth(lw) if dotted: actor.GetProperty().SetLineStipplePattern(0xf0f0) actor.GetProperty().SetLineStippleRepeatFactor(1) setattr(actor, 'base', np.array(p0)) setattr(actor, 'top', np.array(p1)) return actor
def cone(pos=[0, 0, 0], r=1, height=1, axis=[0, 0, 1], c='dg', alpha=1, legend=None, texture=None, res=48): ''' Build a cone of specified radius r and height, centered at pos. ''' con = vtk.vtkConeSource() con.SetResolution(res) con.SetRadius(r) con.SetHeight(height) con.SetDirection(axis) con.Update() actor = vu.makeActor(con.GetOutput(), c, alpha, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) v = vu.norm(axis) * height / 2 setattr(actor, 'base', pos - v) setattr(actor, 'top', pos + v) return actor
def align(source, target, iters=100, rigid=False, legend=None): ''' Return a copy of source actor which is aligned to target actor through vtkIterativeClosestPointTransform() method. The core of the algorithm is to match each vertex in one surface with the closest surface point on the other, then apply the transformation that modify one surface to best match the other (in the least-square sense). [**Example1**](https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/align1.py) [**Example2**](https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/align2.py) ''' source = vu.polydata(source) target = vu.polydata(target) icp = vtk.vtkIterativeClosestPointTransform() icp.SetSource(source) icp.SetTarget(target) icp.SetMaximumNumberOfIterations(iters) if rigid: icp.GetLandmarkTransform().SetModeToRigidBody() icp.StartByMatchingCentroidsOn() icp.Update() icpTransformFilter = vtk.vtkTransformPolyDataFilter() vu.setInput(icpTransformFilter, source) icpTransformFilter.SetTransform(icp) icpTransformFilter.Update() poly = icpTransformFilter.GetOutput() actor = vu.makeActor(poly, legend=legend) if hasattr(source, 'GetProperty'): actor.SetProperty(source.GetProperty()) setattr(actor, 'transform', icp.GetLandmarkTransform()) return actor
def booleanOperation(actor1, actor2, operation='plus', c=None, alpha=1, wire=False, bc=None, edges=False, legend=None, texture=None): '''Volumetric union, intersection and subtraction of surfaces [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/boolean.py) ''' try: bf = vtk.vtkBooleanOperationPolyDataFilter() except AttributeError: vc.printc('Boolean operation only possible for vtk version >= 8', c='r') return None poly1 = vu.polydata(actor1, True) poly2 = vu.polydata(actor2, True) if operation.lower() == 'plus': bf.SetOperationToUnion() elif operation.lower() == 'intersect': bf.SetOperationToIntersection() elif operation.lower() == 'minus': bf.SetOperationToDifference() bf.ReorientDifferenceCellsOn() if vu.vtkMV: bf.SetInputData(0, poly1) bf.SetInputData(1, poly2) else: bf.SetInputConnection(0, poly1.GetProducerPort()) bf.SetInputConnection(1, poly2.GetProducerPort()) bf.Update() actor = vu.makeActor(bf.GetOutput(), c, alpha, wire, bc, edges, legend, texture) return actor
def loadFile(filename, c, alpha, wire, bc, edges, legend, texture, smoothing, threshold, connectivity, scaling): '''Load a file of various formats.''' fl = filename.lower() if legend is True: legend = os.path.basename(filename) if fl.endswith('.xml') or fl.endswith( '.xml.gz'): # Fenics tetrahedral file actor = loadDolfin(filename, c, alpha, wire, bc, edges, legend) elif fl.endswith('.neutral') or fl.endswith( '.neu'): # neutral tetrahedral file actor = loadNeutral(filename, c, alpha, wire, bc, edges, legend) elif fl.endswith('.gmsh'): # gmesh file actor = loadGmesh(filename, c, alpha, wire, bc, edges, legend) elif fl.endswith('.pcd'): # PCL point-cloud format actor = loadPCD(filename, c, alpha, legend) elif fl.endswith('.3ds'): # PCL point-cloud format actor = load3DS(filename, legend) elif fl.endswith('.tif') or fl.endswith('.slc'): # tiff stack or slc img = loadImageData(filename) actor = vu.makeIsosurface(img, c, alpha, wire, bc, edges, legend, texture, smoothing, threshold, connectivity, scaling) elif fl.endswith('.png') or fl.endswith('.jpg') or fl.endswith('.jpeg'): actor = load2Dimage(filename, alpha) else: poly = loadPolyData(filename) if not poly: vc.printc('Unable to load', filename, c=1) return None actor = vu.makeActor(poly, c, alpha, wire, bc, edges, legend, texture) if fl.endswith('.txt') or fl.endswith('.xyz'): actor.GetProperty().SetPointSize(4) setattr(actor, 'filename', filename) return actor
def lines(plist0, plist1=None, lw=1, dotted=False, c='r', alpha=1, legend=None): '''Build the line segments between two lists of points plist0 and plist1. plist0 can be also passed in the form [[point1, point2], ...] ''' if plist1 is not None: plist0 = list(zip(plist0, plist1)) polylns = vtk.vtkAppendPolyData() for twopts in plist0: lineSource = vtk.vtkLineSource() lineSource.SetPoint1(twopts[0]) lineSource.SetPoint2(twopts[1]) polylns.AddInputConnection(lineSource.GetOutputPort()) polylns.Update() actor = vu.makeActor(polylns.GetOutput(), c, alpha, legend=legend) actor.GetProperty().SetLineWidth(lw) if dotted: actor.GetProperty().SetLineStipplePattern(0xf0f0) actor.GetProperty().SetLineStippleRepeatFactor(1) return actor
def points(plist, c='b', tags=[], r=5, alpha=1, legend=None): ''' Build a vtkActor for a list of points. c can be a list of [R,G,B] colors of same length as plist If tags (a list of strings) is specified, is displayed along with the points. ''' if len(plist) == 0: return None if vu.isSequence(c) and vu.isSequence(c[0]): return _colorPoints(plist, c, r, alpha, legend) src = vtk.vtkPointSource() src.SetNumberOfPoints(len(plist)) src.Update() pd = src.GetOutput() if len(plist) == 1: #passing just one point pd.GetPoints().SetPoint(0, [0, 0, 0]) else: for i, p in enumerate(plist): pd.GetPoints().SetPoint(i, p) actor = vu.makeActor(pd, c, alpha) actor.GetProperty().SetPointSize(r) if len(plist) == 1: actor.SetPosition(plist[0]) if legend: setattr(actor, 'legend', legend) return actor
def loadFile(filename, c, alpha, wire, bc, edges, legend, texture, smoothing, threshold, connectivity, scaling): fl = filename.lower() if legend is True: legend = os.path.basename(filename) if '.xml' in fl or '.xml.gz' in fl: # Fenics tetrahedral mesh file actor = loadXml(filename, c, alpha, wire, bc, edges, legend) elif '.neutral' in fl: # neutral tetrahedral mesh file actor = loadNeutral(filename, c, alpha, wire, bc, edges, legend) elif '.gmsh' in fl: # gmesh file actor = loadGmesh(filename, c, alpha, wire, bc, edges, legend) elif '.pcd' in fl: # PCL point-cloud format actor = loadPCD(filename, c, alpha, legend) elif '.tif' in fl or '.slc' in fl: # tiff stack or slc actor = loadVolume(filename, c, alpha, wire, bc, edges, legend, texture, smoothing, threshold, connectivity, scaling) elif '.png' in fl or '.jpg' in fl or '.jpeg' in fl: # regular image actor = load2Dimage(filename, alpha) else: poly = loadPoly(filename) if not poly: vc.printc(('Unable to load', filename), c=1) return False actor = vu.makeActor(poly, c, alpha, wire, bc, edges, legend, texture) if '.txt' in fl or '.xyz' in fl: actor.GetProperty().SetPointSize(4) return actor
def recoSurface(points, bins=256, c='gold', alpha=1, wire=False, bc='t', edges=False, legend=None): ''' Surface reconstruction from sparse points. ''' if isinstance(points, vtk.vtkActor): points = vu.coordinates(points) N = len(points) if N < 50: print('recoSurface: Use at least 50 points.') return None points = np.array(points) ptsSource = vtk.vtkPointSource() ptsSource.SetNumberOfPoints(N) ptsSource.Update() vpts = ptsSource.GetOutput().GetPoints() for i, p in enumerate(points): vpts.SetPoint(i, p) polyData = ptsSource.GetOutput() distance = vtk.vtkSignedDistance() f = 0.1 x0, x1, y0, y1, z0, z1 = polyData.GetBounds() distance.SetBounds(x0 - (x1 - x0) * f, x1 + (x1 - x0) * f, y0 - (y1 - y0) * f, y1 + (y1 - y0) * f, z0 - (z1 - z0) * f, z1 + (z1 - z0) * f) if polyData.GetPointData().GetNormals(): distance.SetInputData(polyData) vu.setInput(distance, polyData) else: normals = vtk.vtkPCANormalEstimation() vu.setInput(normals, polyData) normals.SetSampleSize(int(N / 50)) normals.SetNormalOrientationToGraphTraversal() distance.SetInputConnection(normals.GetOutputPort()) print('Recalculating normals for', N, 'points, sample size=', int(N / 50)) radius = vu.diagonalSize(polyData) / bins * 5 distance.SetRadius(radius) distance.SetDimensions(bins, bins, bins) distance.Update() print('Calculating mesh from points with R =', radius) surface = vtk.vtkExtractSurface() surface.SetRadius(radius * .99) surface.HoleFillingOn() surface.ComputeNormalsOff() surface.ComputeGradientsOff() surface.SetInputConnection(distance.GetOutputPort()) surface.Update() return vu.makeActor(surface.GetOutput(), c, alpha, wire, bc, edges, legend)
def loadRectilinearGrid(filename): # not tested '''Load a vtkRectilinearGrid object from file and return a vtkActor.''' reader = vtk.vtkRectilinearGridReader() reader.SetFileName(filename) reader.Update() gf = vtk.vtkRectilinearGridGeometryFilter() gf.SetInputConnection(reader.GetOutputPort()) gf.Update() return vu.makeActor(gf.GetOutput())
def spline(points, smooth=0.5, degree=2, s=2, c='b', alpha=1., nodes=False, legend=None, res=20): ''' Return a vtkActor for a spline that doesnt necessarly pass exactly throught all points. Options: smooth, smoothing factor: 0 = interpolate points exactly, 1 = average point positions degree = degree of the spline (1<degree<5) nodes = True shows also original the points [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/tutorial.py) ![rspline](https://user-images.githubusercontent.com/32848391/35976041-15781de8-0cdf-11e8-997f-aeb725bc33cc.png) ''' try: from scipy.interpolate import splprep, splev except ImportError: vc.printc( 'Warning: ..scipy not installed, using vtkCardinalSpline instead.', c=5) return _vtkspline(points, s, c, alpha, nodes, legend, res) Nout = len(points)*res # Number of points on the spline points = np.array(points) minx, miny, minz = np.min(points, axis=0) maxx, maxy, maxz = np.max(points, axis=0) maxb = max(maxx-minx, maxy-miny, maxz-minz) smooth *= maxb/2 # must be in absolute units x, y, z = points[:, 0], points[:, 1], points[:, 2] tckp, _ = splprep([x, y, z], task=0, s=smooth, k=degree) # find the knots # evaluate spline, including interpolated points: xnew, ynew, znew = splev(np.linspace(0, 1, Nout), tckp) ppoints = vtk.vtkPoints() # Generate the polyline for the spline profileData = vtk.vtkPolyData() for i in range(Nout): ppoints.InsertPoint(i, xnew[i], ynew[i], znew[i]) lines = vtk.vtkCellArray() # Create the polyline lines.InsertNextCell(Nout) for i in range(Nout): lines.InsertCellPoint(i) profileData.SetPoints(ppoints) profileData.SetLines(lines) actline = vu.makeActor(profileData, c=c, alpha=alpha, legend=legend) actline.GetProperty().SetLineWidth(s) if nodes: actnodes = vs.points(points, r=5, c=c, alpha=alpha) ass = vu.makeAssembly([actline, actnodes], legend=legend) return ass else: return actline
def loadNeutral(filename, c, alpha, wire, bc, edges, legend): '''Reads a Neutral tetrahedral file format''' if not os.path.exists(filename): vc.printc(('Error in loadNeutral: Cannot find', filename), c=1) return None coords, connectivity = convertNeutral2Xml(filename) poly = buildPolyData(coords, connectivity, indexOffset=0) return vu.makeActor(poly, c, alpha, wire, bc, edges, legend)
def arrow(startPoint, endPoint, c, s=None, alpha=1, legend=None, texture=None, res=12, rwSize=None): '''Build a 3D arrow from startPoint to endPoint of section size s, expressed as the fraction of the window size. If s=None the arrow is scaled proportionally to its length.''' axis = np.array(endPoint) - np.array(startPoint) length = np.linalg.norm(axis) if not length: return None axis = axis / length theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) arr = vtk.vtkArrowSource() arr.SetShaftResolution(res) arr.SetTipResolution(res) if s: sz = 0.02 arr.SetTipRadius(sz) arr.SetShaftRadius(sz / 1.75) arr.SetTipLength(sz * 15) arr.Update() t = vtk.vtkTransform() t.RotateZ(phi * 57.3) t.RotateY(theta * 57.3) t.RotateY(-90) #put it along Z if s: w, h = rwSize sz = (w + h) / 2 * s t.Scale(length, sz, sz) else: t.Scale(length, length, length) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, arr.GetOutput()) tf.SetTransform(t) tf.Update() actor = vu.makeActor(tf.GetOutput(), c, alpha, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(startPoint) actor.DragableOff() actor.PickableOff() setattr(actor, 'base', np.array(startPoint)) setattr(actor, 'top', np.array(endPoint)) return actor
def boundaries(actor, c='p', lw=5, legend=None): '''Build a copy of actor that shows the boundary lines of its surface.''' fe = vtk.vtkFeatureEdges() vu.setInput(fe, vu.polydata(actor)) fe.BoundaryEdgesOn() fe.FeatureEdgesOn() fe.ManifoldEdgesOn() fe.NonManifoldEdgesOn() fe.ColoringOff() fe.Update() bactor = vu.makeActor(fe.GetOutput(), c=c, alpha=1, legend=legend) bactor.GetProperty().SetLineWidth(lw) return bactor
def loadStructuredPoints(filename): '''Load a vtkStructuredPoints object from file and return a vtkActor. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/volumetric/readStructuredPoints.py) ![atomp2](https://user-images.githubusercontent.com/32848391/48198462-3b393700-e359-11e8-8272-670bd5f2db42.jpg) ''' reader = vtk.vtkStructuredPointsReader() reader.SetFileName(filename) reader.Update() gf = vtk.vtkImageDataGeometryFilter() gf.SetInputConnection(reader.GetOutputPort()) gf.Update() return vu.makeActor(gf.GetOutput())
def arrows(startPoints, endPoints=None, c='r', s=None, alpha=1, legend=None, res=8, rwSize=None): '''Build arrows between two lists of points startPoints and endPoints. startPoints can be also passed in the form [[point1, point2], ...] ''' if endPoints is not None: startPoints = list(zip(startPoints, endPoints)) polyapp = vtk.vtkAppendPolyData() for twopts in startPoints: startPoint, endPoint = twopts axis = np.array(endPoint) - np.array(startPoint) length = np.linalg.norm(axis) if not length: return None axis = axis / length theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) arr = vtk.vtkArrowSource() arr.SetShaftResolution(res) arr.SetTipResolution(res) if s: sz = 0.02 arr.SetTipRadius(sz) arr.SetShaftRadius(sz / 1.75) arr.SetTipLength(sz * 15) t = vtk.vtkTransform() t.Translate(startPoint) ### t.RotateZ(phi * 57.3) t.RotateY(theta * 57.3) t.RotateY(-90) #put it along Z if s: w, h = rwSize sz = (w + h) / 2 * s t.Scale(length, sz, sz) else: t.Scale(length, length, length) tf = vtk.vtkTransformPolyDataFilter() tf.SetInputConnection(arr.GetOutputPort()) tf.SetTransform(t) polyapp.AddInputConnection(tf.GetOutputPort()) polyapp.Update() actor = vu.makeActor(polyapp.GetOutput(), c, alpha, legend=legend) return actor
def delaunay2D(plist, tol=None, c='gold', alpha=0.5, wire=False, bc=None, edges=False, legend=None, texture=None): ''' Create a mesh from points in the XY plane. ''' src = vtk.vtkPointSource() src.SetNumberOfPoints(len(plist)) src.Update() pd = src.GetOutput() for i,p in enumerate(plist): pd.GetPoints().SetPoint(i, p) delny = vtk.vtkDelaunay2D() vu.setInput(delny, pd) if tol: delny.SetTolerance(tol) delny.Update() return vu.makeActor(delny.GetOutput(), c, alpha, wire, bc, edges, legend, texture)
def boundaries(actor, c='p', lw=5, legend=None): '''Build a copy of actor that shows the boundary lines of its surface. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/tutorial.py) ''' fe = vtk.vtkFeatureEdges() vu.setInput(fe, vu.polydata(actor)) fe.BoundaryEdgesOn() fe.FeatureEdgesOn() fe.ManifoldEdgesOn() fe.NonManifoldEdgesOn() fe.ColoringOff() fe.Update() bactor = vu.makeActor(fe.GetOutput(), c=c, alpha=1, legend=legend) bactor.GetProperty().SetLineWidth(lw) return bactor
def surfaceIntersection(actor1, actor2, tol=1e-06, lw=3, c=None, alpha=1, legend=None): '''Intersect 2 surfaces and return a line actor''' try: bf = vtk.vtkIntersectionPolyDataFilter() except AttributeError: vc.printc('surfaceIntersection only possible for vtk version > 6','r') return None poly1 = vu.polydata(actor1, True) poly2 = vu.polydata(actor2, True) bf.SetInputData(0, poly1) bf.SetInputData(1, poly2) bf.Update() if c is None: c = actor1.GetProperty().GetColor() actor = vu.makeActor(bf.GetOutput(), c, alpha, 0, legend=legend) actor.GetProperty().SetLineWidth(lw) return actor
def hyperboloid(pos=[0, 0, 0], a2=1, value=0.5, height=1, axis=[0, 0, 1], c='magenta', alpha=1, legend=None, texture=None, res=50): ''' Build a hyperboloid of specified aperture a2 and height, centered at pos. ''' q = vtk.vtkQuadric() q.SetCoefficients(2, 2, -1 / a2, 0, 0, 0, 0, 0, 0, 0) #F(x,y,z) = a0*x^2 + a1*y^2 + a2*z^2 # + a3*x*y + a4*y*z + a5*x*z # + a6*x + a7*y + a8*z +a9 sample = vtk.vtkSampleFunction() sample.SetSampleDimensions(res, res, res) sample.SetImplicitFunction(q) contours = vtk.vtkContourFilter() contours.SetInputConnection(sample.GetOutputPort()) contours.GenerateValues(1, value, value) contours.Update() axis = np.array(axis) / np.linalg.norm(axis) theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) t = vtk.vtkTransform() t.PostMultiply() t.RotateY(theta * 57.3) t.RotateZ(phi * 57.3) t.Scale(1, 1, height) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, contours.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = vu.makeActor(pd, c=c, alpha=alpha, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.GetMapper().ScalarVisibilityOff() actor.SetPosition(pos) return actor
def ring(pos=[0, 0, 0], r=1, thickness=0.1, axis=[0, 0, 1], c='khaki', alpha=1, wire=False, legend=None, texture=None, res=30): ''' Build a torus of specified outer radius r internal radius thickness, centered at pos. ''' rs = vtk.vtkParametricTorus() rs.SetRingRadius(r) rs.SetCrossSectionRadius(thickness) pfs = vtk.vtkParametricFunctionSource() pfs.SetParametricFunction(rs) pfs.SetUResolution(res * 3) pfs.SetVResolution(res) pfs.Update() nax = np.linalg.norm(axis) if nax: axis = np.array(axis) / nax theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) t = vtk.vtkTransform() t.PostMultiply() t.RotateY(theta * 57.3) t.RotateZ(phi * 57.3) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, pfs.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = vu.makeActor(pd, c=c, alpha=alpha, wire=wire, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) return actor
def helix(startPoint=[0, 0, 0], endPoint=[1, 1, 1], coils=20, r=None, thickness=None, c='grey', alpha=1, legend=None, texture=None): ''' Build a spring actor of specified nr of coils between startPoint and endPoint ''' diff = endPoint - np.array(startPoint) length = np.linalg.norm(diff) if not length: return None if not r: r = length / 20 trange = np.linspace(0, length, num=50 * coils) om = 6.283 * (coils - .5) / length pts = [[r * np.cos(om * t), r * np.sin(om * t), t] for t in trange] pts = [[0, 0, 0]] + pts + [[0, 0, length]] diff = diff / length theta = np.arccos(diff[2]) phi = np.arctan2(diff[1], diff[0]) sp = vu.polydata(line(pts), False) t = vtk.vtkTransform() t.RotateZ(phi * 57.3) t.RotateY(theta * 57.3) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, sp) tf.SetTransform(t) tf.Update() tuf = vtk.vtkTubeFilter() tuf.SetNumberOfSides(12) tuf.CappingOn() vu.setInput(tuf, tf.GetOutput()) if not thickness: thickness = r / 10 tuf.SetRadius(thickness) tuf.Update() poly = tuf.GetOutput() actor = vu.makeActor(poly, c, alpha, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(startPoint) setattr(actor, 'base', np.array(startPoint)) setattr(actor, 'top', np.array(endPoint)) return actor
def _vtkspline(points, s, c, alpha, nodes, legend, res): numberOfOutputPoints = len(points)*res # Number of points on the spline numberOfInputPoints = len(points) # One spline for each direction. aSplineX = vtk.vtkCardinalSpline() # interpolate the x values aSplineY = vtk.vtkCardinalSpline() # interpolate the y values aSplineZ = vtk.vtkCardinalSpline() # interpolate the z values inputPoints = vtk.vtkPoints() for i in range(0, numberOfInputPoints): x = points[i][0] y = points[i][1] z = points[i][2] aSplineX.AddPoint(i, x) aSplineY.AddPoint(i, y) aSplineZ.AddPoint(i, z) inputPoints.InsertPoint(i, x, y, z) inputData = vtk.vtkPolyData() inputData.SetPoints(inputPoints) points = vtk.vtkPoints() profileData = vtk.vtkPolyData() for i in range(0, numberOfOutputPoints): t = (numberOfInputPoints-1.)/(numberOfOutputPoints-1.)*i x, y, z = aSplineX.Evaluate( t), aSplineY.Evaluate(t), aSplineZ.Evaluate(t) points.InsertPoint(i, x, y, z) lines = vtk.vtkCellArray() # Create the polyline. lines.InsertNextCell(numberOfOutputPoints) for i in range(0, numberOfOutputPoints): lines.InsertCellPoint(i) profileData.SetPoints(points) profileData.SetLines(lines) actline = vu.makeActor(profileData, c=c, alpha=alpha, legend=legend) actline.GetProperty().SetLineWidth(s) actline.GetProperty().SetInterpolationToPhong() if nodes: pts = vu.coordinates(inputData) actnodes = vs.points(pts, r=s*1.5, c=c, alpha=alpha) ass = vu.makeAssembly([actline, actnodes], legend=legend) return ass else: return actline
def ellipsoid(pos=[0, 0, 0], axis1=[1, 0, 0], axis2=[0, 2, 0], axis3=[0, 0, 3], c='c', alpha=1, legend=None, texture=None, res=24): """ Build a 3D ellipsoid centered at position pos. Axis1 and axis2 are only used to define sizes and one azimuth angle """ elliSource = vtk.vtkSphereSource() elliSource.SetThetaResolution(res) elliSource.SetPhiResolution(res) elliSource.Update() l1 = np.linalg.norm(axis1) l2 = np.linalg.norm(axis2) l3 = np.linalg.norm(axis3) axis1 = np.array(axis1) / l1 axis2 = np.array(axis2) / l2 axis3 = np.array(axis3) / l3 angle = np.arcsin(np.dot(axis1, axis2)) theta = np.arccos(axis3[2]) phi = np.arctan2(axis3[1], axis3[0]) t = vtk.vtkTransform() t.PostMultiply() t.Scale(l1, l2, l3) t.RotateX(angle * 57.3) t.RotateY(theta * 57.3) t.RotateZ(phi * 57.3) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, elliSource.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = vu.makeActor(pd, c=c, alpha=alpha, legend=legend, texture=texture) actor.GetProperty().BackfaceCullingOn() actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) return actor
def sphere(pos=[0, 0, 0], r=1, c='r', alpha=1, wire=False, legend=None, texture=None, res=24): '''Build a sphere at position pos of radius r.''' ss = vtk.vtkSphereSource() ss.SetRadius(r) ss.SetThetaResolution(res) ss.SetPhiResolution(res) ss.Update() pd = ss.GetOutput() actor = vu.makeActor(pd, c, alpha, wire, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) return actor
def extractLargestRegion(actor, legend=None): '''Keep only the largest connected part of a mesh and discard all the smaller pieces. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/largestregion.py) ''' conn = vtk.vtkConnectivityFilter() conn.SetExtractionModeToLargestRegion() conn.ScalarConnectivityOff() poly = vu.polydata(actor, True) vu.setInput(conn, poly) conn.Update() epoly = conn.GetOutput() if legend is True and hasattr(actor, 'legend'): legend = actor.legend eact = vu.makeActor(epoly, legend) pr = vtk.vtkProperty() pr.DeepCopy(actor.GetProperty()) eact.SetProperty(pr) return eact
def delaunay2D(plist, tol=None, c='gold', alpha=0.5, wire=False, bc=None, edges=False, legend=None, texture=None): ''' Create a mesh from points in the XY plane. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/delaunay2d.py) ''' src = vtk.vtkPointSource() src.SetNumberOfPoints(len(plist)) src.Update() pd = src.GetOutput() for i, p in enumerate(plist): pd.GetPoints().SetPoint(i, p) delny = vtk.vtkDelaunay2D() vu.setInput(delny, pd) if tol: delny.SetTolerance(tol) delny.Update() return vu.makeActor(delny.GetOutput(), c, alpha, wire, bc, edges, legend, texture)
def plane(pos=[0, 0, 0], normal=[0, 0, 1], sx=1, sy=None, c='g', bc='darkgreen', alpha=1, legend=None, texture=None): ''' Draw a plane of size sx and sy oriented perpendicular to vector normal and so that it passes through point pos. ''' if sy is None: sy = sx ps = vtk.vtkPlaneSource() ps.SetResolution(1, 1) tri = vtk.vtkTriangleFilter() tri.SetInputConnection(ps.GetOutputPort()) tri.Update() poly = tri.GetOutput() axis = np.array(normal) / np.linalg.norm(normal) theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) t = vtk.vtkTransform() t.PostMultiply() t.Scale(sx, sy, 1) t.RotateY(theta * 57.3) t.RotateZ(phi * 57.3) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, poly) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = vu.makeActor(pd, c=c, bc=bc, alpha=alpha, legend=legend, texture=texture) actor.SetPosition(pos) actor.PickableOff() return actor
def probePlane(img, origin=(0, 0, 0), normal=(1, 0, 0)): ''' Takes a vtkImageData and probes its scalars on a plane. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/volumetric/probePlane.py) (https://user-images.githubusercontent.com/32848391/48198461-3aa0a080-e359-11e8-8c29-18f287f105e6.jpg) ''' plane = vtk.vtkPlane() plane.SetOrigin(origin) plane.SetNormal(normal) planeCut = vtk.vtkCutter() planeCut.SetInputData(img) planeCut.SetCutFunction(plane) planeCut.Update() cutActor = vu.makeActor(planeCut.GetOutput(), c=None) # ScalarVisibilityOn cutMapper = cutActor.GetMapper() cutMapper.SetScalarRange(img.GetPointData().GetScalars().GetRange()) return cutActor