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: vio.printc("Error in ellipsoid(): scipy not installed. Skip.", 1) return None 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 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 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 subdivide(actor, N=1, method=0, legend=None): ''' Increase the number of points in actor surface N = number of subdivisions method = 0, Loop method = 1, Linear method = 2, Adaptive method = 3, Butterfly ''' triangles = vtk.vtkTriangleFilter() vu.setInput(triangles, vu.polydata(actor)) triangles.Update() originalMesh = triangles.GetOutput() if method == 0: sdf = vtk.vtkLoopSubdivisionFilter() elif method == 1: sdf = vtk.vtkLinearSubdivisionFilter() elif method == 2: sdf = vtk.vtkAdaptiveSubdivisionFilter() elif method == 3: sdf = vtk.vtkButterflySubdivisionFilter() else: vio.printc('Error in subdivide: unknown method.', 'r') exit(1) if method != 2: sdf.SetNumberOfSubdivisions(N) vu.setInput(sdf, originalMesh) sdf.Update() out = sdf.GetOutput() if legend is None and hasattr(actor, 'legend'): legend = actor.legend sactor = vu.makeActor(out, legend=legend) sactor.GetProperty().SetOpacity(actor.GetProperty().GetOpacity()) sactor.GetProperty().SetColor(actor.GetProperty().GetColor()) sactor.GetProperty().SetRepresentation( actor.GetProperty().GetRepresentation()) return sactor
def grid(pos=[0, 0, 0], normal=[0, 0, 1], s=10, c='g', bc='darkgreen', lw=1, alpha=1, wire=True, legend=None, texture=None, res=10): '''Return a grid plane''' ps = vtk.vtkPlaneSource() ps.SetResolution(res, res) ps.SetCenter(np.array(pos) / s) ps.SetNormal(normal) ps.Update() actor = vu.makeActor(ps.GetOutput(), c=c, bc=bc, alpha=alpha, legend=legend, texture=texture) if wire: actor.GetProperty().SetRepresentationToWireframe() actor.GetProperty().SetLineWidth(lw) actor.SetScale(s, s, s) actor.PickableOff() 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 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''' try: bf = vtk.vtkBooleanOperationPolyDataFilter() except AttributeError: vio.printc('Boolean operation only possible for vtk version >= 8', '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 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: print('Recalculating normals for', N, 'points') normals = vtk.vtkPCANormalEstimation() vu.setInput(normals, polyData) normals.SetSampleSize(int(N / 50)) normals.SetNormalOrientationToGraphTraversal() distance.SetInputConnection(normals.GetOutputPort()) 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 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. 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 ''' try: from scipy.interpolate import splprep, splev except ImportError: vio.printc( 'Warning: ..scipy not installed, using vtkCardinalSpline instead.', 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=s * 1.5, c=c, alpha=alpha) ass = vu.makeAssembly([actline, actnodes], legend=legend) return ass else: return actline
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 cutPlane(actor, origin=(0, 0, 0), normal=(1, 0, 0), showcut=True): ''' Takes actor and cuts it with the plane defined by a point and a normal. showcut = shows the cut away part as thin wireframe showline = marks with a thick line the cut ''' plane = vtk.vtkPlane() plane.SetOrigin(origin) plane.SetNormal(normal) poly = vu.polydata(actor) clipper = vtk.vtkClipPolyData() vu.setInput(clipper, poly) clipper.SetClipFunction(plane) clipper.GenerateClippedOutputOn() clipper.SetValue(0.) clipper.Update() if hasattr(actor, 'GetProperty'): alpha = actor.GetProperty().GetOpacity() c = actor.GetProperty().GetColor() bf = actor.GetBackfaceProperty() else: alpha = 1 c = 'gold' bf = None leg = None if hasattr(actor, 'legend'): leg = actor.legend clipActor = vu.makeActor(clipper.GetOutput(), c=c, alpha=alpha, legend=leg) clipActor.SetBackfaceProperty(bf) acts = [clipActor] if showcut: cpoly = clipper.GetClippedOutput() restActor = vu.makeActor(cpoly, c=c, alpha=0.05, wire=1) acts.append(restActor) if len(acts) > 1: asse = vu.makeAssembly(acts) return asse else: return clipActor
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 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.makePolyData(pts) 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 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 _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 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 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: vio.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 align(source, target, iters=100, legend=None): ''' Return a copy of source actor which is aligned to target actor through vtkIterativeClosestPointTransform() method. ''' sprop = source.GetProperty() source = vu.polydata(source) target = vu.polydata(target) icp = vtk.vtkIterativeClosestPointTransform() icp.SetSource(source) icp.SetTarget(target) icp.SetMaximumNumberOfIterations(iters) 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) actor.SetProperty(sprop) setattr(actor, 'transform', icp.GetLandmarkTransform()) return actor
def box(pos=[0, 0, 0], length=1, width=2, height=3, normal=(0, 0, 1), c='g', alpha=1, wire=False, legend=None, texture=None): '''Build a box of dimensions x=length, y=width and z=height oriented along vector normal''' src = vtk.vtkCubeSource() src.SetXLength(length) src.SetYLength(width) src.SetZLength(height) src.Update() poly = src.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.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, alpha, wire, legend=legend, texture=texture) actor.SetPosition(pos) 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 fxy(z='sin(3*x)*log(x-y)/3', x=[0, 3], y=[0, 3], zlimits=[None, None], showNan=True, zlevels=10, wire=False, c='b', bc='aqua', alpha=1, legend=True, texture=None, res=100): ''' Build a surface representing the 3D function specified as a string or as a reference to an external function. Red points indicate where the function does not exist (showNan). zlevels will draw the specified number of z-levels contour lines. Examples: vp = plotter.vtkPlotter() vp.fxy('sin(3*x)*log(x-y)/3') or def z(x,y): return math.sin(x*y) vp.fxy(z) # or equivalently: vp.fxy(lambda x,y: math.sin(x*y)) ''' if isinstance(z, str): try: z = z.replace('math.', '').replace('np.', '') namespace = locals() code = "from math import*\ndef zfunc(x,y): return " + z exec(code, namespace) z = namespace['zfunc'] except: vio.printc('Syntax Error in fxy()', 1) return None ps = vtk.vtkPlaneSource() ps.SetResolution(res, res) ps.SetNormal([0, 0, 1]) ps.Update() poly = ps.GetOutput() dx = x[1] - x[0] dy = y[1] - y[0] todel, nans = [], [] if zlevels: tf = vtk.vtkTriangleFilter() vu.setInput(tf, poly) tf.Update() poly = tf.GetOutput() for i in range(poly.GetNumberOfPoints()): px, py, _ = poly.GetPoint(i) xv = (px + .5) * dx + x[0] yv = (py + .5) * dy + y[0] try: zv = z(xv, yv) poly.GetPoints().SetPoint(i, [xv, yv, zv]) except: todel.append(i) nans.append([xv, yv, 0]) if len(todel): cellIds = vtk.vtkIdList() poly.BuildLinks() for i in todel: poly.GetPointCells(i, cellIds) for j in range(cellIds.GetNumberOfIds()): poly.DeleteCell(cellIds.GetId(j)) #flag cell poly.RemoveDeletedCells() cl = vtk.vtkCleanPolyData() vu.setInput(cl, poly) cl.Update() poly = cl.GetOutput() if not poly.GetNumberOfPoints(): vio.printc('Function is not real in the domain', 1) return vtk.vtkActor() if zlimits[0]: a = cutPlane(poly, (0, 0, zlimits[0]), (0, 0, 1), False) poly = vu.polydata(a) if zlimits[1]: a = cutPlane(poly, (0, 0, zlimits[1]), (0, 0, -1), False) poly = vu.polydata(a) if c is None: elev = vtk.vtkElevationFilter() vu.setInput(elev, poly) elev.Update() poly = elev.GetOutput() actor = vu.makeActor(poly, c=c, bc=bc, alpha=alpha, wire=wire, legend=legend, texture=texture) acts = [actor] if zlevels: elevation = vtk.vtkElevationFilter() vu.setInput(elevation, poly) bounds = poly.GetBounds() elevation.SetLowPoint(0, 0, bounds[4]) elevation.SetHighPoint(0, 0, bounds[5]) elevation.Update() bcf = vtk.vtkBandedPolyDataContourFilter() vu.setInput(bcf, elevation.GetOutput()) bcf.SetScalarModeToValue() bcf.GenerateContourEdgesOn() bcf.GenerateValues(zlevels, elevation.GetScalarRange()) bcf.Update() zpoly = bcf.GetContourEdgesOutput() zbandsact = vu.makeActor(zpoly, c='k', alpha=alpha) zbandsact.GetProperty().SetLineWidth(1.5) acts.append(zbandsact) if showNan and len(todel): bb = actor.GetBounds() zm = (bb[4] + bb[5]) / 2 nans = np.array(nans) + [0, 0, zm] nansact = vs.points(nans, c='red', alpha=alpha / 2) acts.append(nansact) if len(acts) > 1: asse = vu.makeAssembly(acts) return asse else: return actor
def cylinder(pos=[0, 0, 0], r=1, height=1, axis=[0, 0, 1], c='teal', wire=0, alpha=1, edges=False, legend=None, texture=None, res=24): ''' Build a cylinder of specified height and radius r, centered at pos. If pos is a list of 2 points, e.g. pos=[v1,v2], build a cylinder with base centered at v1 and top at v2. ''' if vu.isSequence(pos[0]): # assume user is passing pos=[base, top] base = np.array(pos[0]) top = np.array(pos[1]) pos = (base + top) / 2 height = np.linalg.norm(top - base) axis = top - base axis = vu.norm(axis) else: axis = vu.norm(axis) base = pos - axis * height / 2 top = pos + axis * height / 2 cyl = vtk.vtkCylinderSource() cyl.SetResolution(res) cyl.SetRadius(r) cyl.SetHeight(height) cyl.Update() theta = np.arccos(axis[2]) phi = np.arctan2(axis[1], axis[0]) t = vtk.vtkTransform() t.PostMultiply() t.RotateX(90) #put it along Z t.RotateY(theta * 57.3) t.RotateZ(phi * 57.3) tf = vtk.vtkTransformPolyDataFilter() vu.setInput(tf, cyl.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = vu.makeActor(pd, c, alpha, wire, edges=edges, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) setattr(actor, 'base', base) setattr(actor, 'top', top) return actor