def align(source, target, iters=100, rigid=False, legend=None): ''' Return a copy of source actor which is aligned to target actor through vtkIterativeClosestPointTransform class. 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) ''' if isinstance(source, Actor): source = source.polydata() if isinstance(target, Actor): target = target.polydata() icp = vtk.vtkIterativeClosestPointTransform() icp.SetSource(source) icp.SetTarget(target) icp.SetMaximumNumberOfIterations(iters) if rigid: icp.GetLandmarkTransform().SetModeToRigidBody() icp.StartByMatchingCentroidsOn() icp.Update() icpTransformFilter = vtk.vtkTransformPolyDataFilter() icpTransformFilter.SetInputData(source) icpTransformFilter.SetTransform(icp) icpTransformFilter.Update() poly = icpTransformFilter.GetOutput() actor = Actor(poly, legend=legend) actor.info['transform'] = icp.GetLandmarkTransform() return actor
def _colorPoints(plist, cols, r, alpha): n = len(plist) if n > len(cols): colors.printc("~times Error: mismatch in colorPoints()", n, len(cols), c=1) exit() if n != len(cols): colors.printc("~lightning Warning: mismatch in colorPoints()", n, len(cols)) src = vtk.vtkPointSource() src.SetNumberOfPoints(n) src.Update() vgf = vtk.vtkVertexGlyphFilter() vgf.SetInputData(src.GetOutput()) vgf.Update() pd = vgf.GetOutput() ucols = vtk.vtkUnsignedCharArray() ucols.SetNumberOfComponents(3) ucols.SetName("pointsRGB") for i in range(len(plist)): c = np.array(colors.getColor(cols[i])) * 255 ucols.InsertNextTuple3(c[0], c[1], c[2]) pd.GetPoints().SetData(numpy_to_vtk(plist, deep=True)) pd.GetPointData().SetScalars(ucols) actor = Actor(pd, c, alpha) actor.mapper.ScalarVisibilityOn() actor.GetProperty().SetInterpolationToFlat() actor.GetProperty().SetPointSize(r) settings.collectable_actors.append(actor) return actor
def tube(points, r=1, c='r', alpha=1, legend=None, res=12): '''Build a tube of radius `r` along line defined by a set of points. .. hint:: Example: `ribbon.py <https://github.com/marcomusy/vtkplotter/blob/master/examples/basic/ribbon.py>`_ .. image:: https://user-images.githubusercontent.com/32848391/50738851-be9bcb00-11d8-11e9-80ee-bd73c1c29c06.jpg ''' ppoints = vtk.vtkPoints() # Generate the polyline ppoints.SetData(numpy_to_vtk(points, deep=True)) lines = vtk.vtkCellArray() # Create the polyline. lines.InsertNextCell(len(points)) for i in range(len(points)): lines.InsertCellPoint(i) poly = vtk.vtkPolyData() poly.SetPoints(ppoints) poly.SetLines(lines) tuf = vtk.vtkTubeFilter() tuf.SetNumberOfSides(res) tuf.SetInputData(poly) tuf.SetRadius(r) tuf.CappingOn() tuf.Update() poly = tuf.GetOutput() actor = Actor(poly, c, alpha, legend=legend) actor.GetProperty().SetInterpolationToPhong() actor.base = np.array(points[0]) actor.top = np.array(points[-1]) return actor
def lines(plist0, plist1=None, lw=1, c='r', alpha=1, dotted=False, legend=None): ''' Build the line segments between two lists of points `plist0` and `plist1`. `plist0` can be also passed in the form ``[[point1, point2], ...]``. .. hint:: Example: `fitspheres2.py <https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/fitspheres2.py>`_ ''' 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 = Actor(polylns.GetOutput(), c, alpha, legend=legend) actor.GetProperty().SetLineWidth(lw) if dotted: actor.GetProperty().SetLineStipplePattern(0xf0f0) actor.GetProperty().SetLineStippleRepeatFactor(1) 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 = Actor(con.GetOutput(), c, alpha, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) v = utils.norm(axis) * height / 2 actor.base = pos - v actor.top = pos + v return actor
def procrustes(sources, rigid=False, legend=None): ''' Return an Assembly of aligned source actors with the vtkProcrustesAlignmentFilter class. Assembly is normalized in space. Takes N set of points and aligns them in a least-squares sense to their mutual mean. The algorithm is iterated until convergence, as the mean must be recomputed after each alignment. ''' group = vtk.vtkMultiBlockDataGroupFilter() for source in sources: if sources[0].N() != source.N(): vc.printc('Procrustes error in align():' , c=1) vc.printc(' sources have different nr of points', c=1) exit(0) group.AddInputData(source.polydata()) procrustes = vtk.vtkProcrustesAlignmentFilter() procrustes.StartFromCentroidOn() procrustes.SetInputConnection(group.GetOutputPort()) if rigid: procrustes.GetLandmarkTransform().SetModeToRigidBody() procrustes.Update() acts = [] for i in range(len(sources)): poly = procrustes.GetOutput().GetBlock(i) actor = Actor(poly) actor.SetProperty(sources[i].GetProperty()) acts.append(actor) assem = Assembly(acts, legend=legend) assem.info['transform'] = procrustes.GetLandmarkTransform() return assem
def Lines(plist0, plist1=None, lw=1, c="r", alpha=1, dotted=False): """ Build the line segments between two lists of points `plist0` and `plist1`. `plist0` can be also passed in the form ``[[point1, point2], ...]``. |lines| .. hint:: |fitspheres2.py|_ """ 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 = Actor(polylns.GetOutput(), c, alpha) actor.GetProperty().SetLineWidth(lw) if dotted: actor.GetProperty().SetLineStipplePattern(0xF0F0) actor.GetProperty().SetLineStippleRepeatFactor(1) return actor
def Torus(pos=(0, 0, 0), r=1, thickness=0.1, axis=(0, 0, 1), c="khaki", alpha=1, res=30): """ Build a torus of specified outer radius `r` internal radius `thickness`, centered at `pos`. .. hint:: |gas| |gas.py|_ """ 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(np.rad2deg(theta)) t.RotateZ(np.rad2deg(phi)) tf = vtk.vtkTransformPolyDataFilter() tf.SetInputData(pfs.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = Actor(pd, c, alpha) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) settings.collectable_actors.append(actor) return actor
def loadDolfin(filename, exterior=False): """Reads a `Fenics/Dolfin` file format (.xml or .xdmf). Return an ``Actor(vtkActor)`` object.""" import sys if sys.version_info[0] < 3: return _loadDolfin_old(filename) import dolfin if filename.lower().endswith('.xdmf'): f = dolfin.XDMFFile(filename) m = dolfin.Mesh() f.read(m) else: m = dolfin.Mesh(filename) bm = dolfin.BoundaryMesh(m, "exterior") if exterior: poly = utils.buildPolyData(bm.coordinates(), bm.cells(), fast=True) else: polyb = utils.buildPolyData(bm.coordinates(), bm.cells(), fast=True) polym = utils.buildPolyData(m.coordinates(), m.cells(), fast=True) app = vtk.vtkAppendPolyData() app.AddInputData(polym) app.AddInputData(polyb) app.Update() poly = app.GetOutput() return Actor(poly).lw(0.1)
def Disc( pos=(0, 0, 0), r1=0.5, r2=1, c="coral", alpha=1, res=12, resphi=None, ): """ Build a 2D disc of internal radius `r1` and outer radius `r2`, oriented perpendicular to `normal`. |Disk| """ ps = vtk.vtkDiskSource() ps.SetInnerRadius(r1) ps.SetOuterRadius(r2) ps.SetRadialResolution(res) if not resphi: resphi = 6 * res ps.SetCircumferentialResolution(resphi) ps.Update() actor = Actor(ps.GetOutput(), c, alpha).flat() actor.SetPosition(pos) settings.collectable_actors.append(actor) return actor
def loadNeutral(filename): """Reads a `Neutral` tetrahedral file format. Return an ``Actor(vtkActor)`` object.""" f = open(filename, "r") lines = f.readlines() f.close() ncoords = int(lines[0]) coords = [] for i in range(1, ncoords + 1): x, y, z = lines[i].split() coords.append([float(x), float(y), float(z)]) ntets = int(lines[ncoords + 1]) idolf_tets = [] for i in range(ncoords + 2, ncoords + ntets + 2): text = lines[i].split() v0, v1, v2, v3 = int(text[1])-1, int(text[2])-1, int(text[3])-1, int(text[4])-1 # p0, p1, p2, p3 = np.array(coords[v1]), np.array(coords[v0]), coords[v3], coords[v2] # d10 = p1-p0 # d21 = p2-p1 # dc = np.cross(d10, d21) # print(np.dot(dc,p3-p0)) idolf_tets.append([v0, v1, v2, v3]) poly = utils.buildPolyData(coords, idolf_tets) return Actor(poly)
def tube(points, r=1, c='r', alpha=1, legend=None, res=12): '''Build a tube of radius r along line defined py points.''' ppoints = vtk.vtkPoints() # Generate the polyline ppoints.SetData(numpy_to_vtk(points, deep=True)) lines = vtk.vtkCellArray() # Create the polyline. lines.InsertNextCell(len(points)) for i in range(len(points)): lines.InsertCellPoint(i) poly = vtk.vtkPolyData() poly.SetPoints(ppoints) poly.SetLines(lines) tuf = vtk.vtkTubeFilter() tuf.SetNumberOfSides(res) tuf.SetInputData(poly) tuf.SetRadius(r) tuf.CappingOn() tuf.Update() poly = tuf.GetOutput() actor = Actor(poly, c, alpha, legend=legend) actor.GetProperty().SetInterpolationToPhong() actor.base = np.array(points[0]) actor.top = np.array(points[-1]) return actor
def booleanOperation(actor1, actor2, operation='plus', c=None, alpha=1, wire=False, bc=None, 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 = actor1.polydata(True) poly2 = actor2.polydata(True) if operation.lower() == 'plus': bf.SetOperationToUnion() elif operation.lower() == 'intersect': bf.SetOperationToIntersection() elif operation.lower() == 'minus': bf.SetOperationToDifference() bf.ReorientDifferenceCellsOn() bf.SetInputData(0, poly1) bf.SetInputData(1, poly2) bf.Update() actor = Actor(bf.GetOutput(), c, alpha, wire, bc, legend, texture) return actor
def loadGmesh(filename): """Reads a `gmesh` file format. Return an ``Actor(vtkActor)`` object.""" f = open(filename, "r") lines = f.readlines() f.close() nnodes = 0 index_nodes = 0 for i, line in enumerate(lines): if "$Nodes" in line: index_nodes = i + 1 nnodes = int(lines[index_nodes]) break node_coords = [] for i in range(index_nodes + 1, index_nodes + 1 + nnodes): cn = lines[i].split() node_coords.append([float(cn[1]), float(cn[2]), float(cn[3])]) nelements = 0 index_elements = 0 for i, line in enumerate(lines): if "$Elements" in line: index_elements = i + 1 nelements = int(lines[index_elements]) break elements = [] for i in range(index_elements + 1, index_elements + 1 + nelements): ele = lines[i].split() elements.append([int(ele[-3]), int(ele[-2]), int(ele[-1])]) poly = utils.buildPolyData(node_coords, elements, indexOffset=1) return Actor(poly)
def Plane(pos=(0, 0, 0), normal=(0, 0, 1), sx=1, sy=None, c="g", alpha=1, texture=None): """ Draw a plane of size `sx` and `sy` oriented perpendicular to vector `normal` and so that it passes through point `pos`. |Plane| """ 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(np.rad2deg(theta)) t.RotateZ(np.rad2deg(phi)) tf = vtk.vtkTransformPolyDataFilter() tf.SetInputData(poly) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = Actor(pd, c, alpha, texture=texture) actor.SetPosition(pos) settings.collectable_actors.append(actor) return actor
def _colorPoints(plist, cols, r, alpha, legend): n = len(plist) if n > len(cols): colors.printc("Mismatch in colorPoints()", n, len(cols), c=1) exit() if n != len(cols): colors.printc("Warning: mismatch in colorPoints()", n, len(cols)) src = vtk.vtkPointSource() src.SetNumberOfPoints(n) src.Update() vertexFilter = vtk.vtkVertexGlyphFilter() vertexFilter.SetInputData(src.GetOutput()) vertexFilter.Update() pd = vertexFilter.GetOutput() ucols = vtk.vtkUnsignedCharArray() ucols.SetNumberOfComponents(3) ucols.SetName("RGB") for i, p in enumerate(plist): c = np.array(colors.getColor(cols[i])) * 255 ucols.InsertNextTuple3(c[0], c[1], c[2]) pd.GetPoints().SetData(numpy_to_vtk(plist, deep=True)) pd.GetPointData().SetScalars(ucols) mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(pd) mapper.ScalarVisibilityOn() actor = Actor() #vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetInterpolationToFlat() actor.GetProperty().SetOpacity(alpha) actor.GetProperty().SetPointSize(r) return actor
def _loadFile(filename, c, alpha, wire, bc, legend, texture, smoothing, threshold, connectivity): 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, legend) elif fl.endswith('.neutral') or fl.endswith( '.neu'): # neutral tetrahedral file actor = loadNeutral(filename, c, alpha, wire, bc, legend) elif fl.endswith('.gmsh'): # gmesh file actor = loadGmesh(filename, c, alpha, wire, bc, 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') or fl.endswith('.vti'): # tiff stack or slc or vti img = loadImageData(filename) actor = utils.isosurface(img, c, alpha, wire, bc, legend, texture, smoothing, threshold, connectivity) elif fl.endswith('.png') or fl.endswith('.jpg') or fl.endswith('.jpeg'): actor = load2Dimage(filename, alpha) else: poly = loadPolyData(filename) if not poly: colors.printc('Unable to load', filename, c=1) return None actor = Actor(poly, c, alpha, wire, bc, legend, texture) if fl.endswith('.txt') or fl.endswith('.xyz'): actor.GetProperty().SetPointSize(4) actor.filename = filename return actor
def recoSurface(points, bins=256, c='gold', alpha=1, wire=False, bc='t', legend=None): ''' Surface reconstruction from sparse points. [**Example**](https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/recosurface.py) ![reco](https://user-images.githubusercontent.com/32848391/46817107-b3263880-cd7e-11e8-985d-f5d158992f0c.png) ''' if isinstance(points, vtk.vtkActor): points = points.coordinates() 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) else: normals = vtk.vtkPCANormalEstimation() normals.SetInputData(polyData) normals.SetSampleSize(int(N/50)) normals.SetNormalOrientationToGraphTraversal() distance.SetInputConnection(normals.GetOutputPort()) print('Recalculating normals for', N, 'points, sample size=', int(N/50)) b = polyData.GetBounds() diagsize = np.sqrt((b[1]-b[0])**2 + (b[3]-b[2])**2 + (b[5]-b[4])**2) radius = diagsize/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 Actor(surface.GetOutput(), c, alpha, wire, bc, legend)
def loadGeoJSON(filename): """Load GeoJSON files.""" if filename.endswith('.gz'): filename = gunzip(filename) jr = vtk.vtkGeoJSONReader() jr.SetFileName(filename) jr.Update() return Actor(jr.GetOutput())
def ribbon(line1, line2, c='m', alpha=1, legend=None, res=(200, 5)): '''Connect two lines to generate the surface inbetween.''' if isinstance(line1, Actor): line1 = line1.coordinates() if isinstance(line2, Actor): line2 = line2.coordinates() ppoints1 = vtk.vtkPoints() # Generate the polyline1 ppoints1.SetData(numpy_to_vtk(line1, deep=True)) lines1 = vtk.vtkCellArray() lines1.InsertNextCell(len(line1)) for i in range(len(line1)): lines1.InsertCellPoint(i) poly1 = vtk.vtkPolyData() poly1.SetPoints(ppoints1) poly1.SetLines(lines1) ppoints2 = vtk.vtkPoints() # Generate the polyline2 ppoints2.SetData(numpy_to_vtk(line2, deep=True)) lines2 = vtk.vtkCellArray() lines2.InsertNextCell(len(line2)) for i in range(len(line2)): lines2.InsertCellPoint(i) poly2 = vtk.vtkPolyData() poly2.SetPoints(ppoints2) poly2.SetLines(lines2) # build the lines lines1 = vtk.vtkCellArray() lines1.InsertNextCell(poly1.GetNumberOfPoints()) for i in range(poly1.GetNumberOfPoints()): lines1.InsertCellPoint(i) polygon1 = vtk.vtkPolyData() polygon1.SetPoints(ppoints1) polygon1.SetLines(lines1) lines2 = vtk.vtkCellArray() lines2.InsertNextCell(poly2.GetNumberOfPoints()) for i in range(poly2.GetNumberOfPoints()): lines2.InsertCellPoint(i) polygon2 = vtk.vtkPolyData() polygon2.SetPoints(ppoints2) polygon2.SetLines(lines2) mergedPolyData = vtk.vtkAppendPolyData() mergedPolyData.AddInputData(polygon1) mergedPolyData.AddInputData(polygon2) mergedPolyData.Update() rsf = vtk.vtkRuledSurfaceFilter() rsf.CloseSurfaceOff() rsf.SetRuledModeToResample() rsf.SetResolution(res[0], res[1]) rsf.SetInputData(mergedPolyData.GetOutput()) rsf.Update() return Actor(rsf.GetOutput(), c=c, alpha=alpha, legend=legend)
def cylinder(pos=[0, 0, 0], r=1, height=1, axis=[0, 0, 1], c='teal', wire=0, alpha=1, 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. [**Example1**](https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/gyroscope1.py) [**Example2**](https://github.com/marcomusy/vtkplotter/blob/master/examples/advanced/turing.py) ''' if utils.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 = utils.norm(axis) else: axis = utils.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() tf.SetInputData(cyl.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() actor = Actor(pd, c, alpha, wire, legend=legend, texture=texture) actor.GetProperty().SetInterpolationToPhong() actor.SetPosition(pos) actor.base = base actor.top = top return actor
def loadUnStructuredGrid(filename): # not tested '''Load a ``vtkunStructuredGrid`` object from file and return a ``Actor(vtkActor)`` object.''' reader = vtk.vtkUnstructuredGridReader() reader.SetFileName(filename) reader.Update() gf = vtk.vtkUnstructuredGridGeometryFilter() gf.SetInputConnection(reader.GetOutputPort()) gf.Update() return Actor(gf.GetOutput())
def disc(pos=[0, 0, 0], normal=[0, 0, 1], r1=0.5, r2=1, c='coral', bc='darkgreen', lw=1, alpha=1, legend=None, texture=None, res=12): ''' Build a 2D disc of internal radius `r1` and outer radius `r2`, oriented perpendicular to `normal`. ''' ps = vtk.vtkDiskSource() ps.SetInnerRadius(r1) ps.SetOuterRadius(r2) ps.SetRadialResolution(res) ps.SetCircumferentialResolution(res * 6) # ~2pi ps.Update() 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() tf.SetInputData(ps.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(pd) actor = Actor() # vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetColor(colors.getColor(c)) # check if color string contains a float, in this case ignore alpha al = colors._getAlpha(c) if al: alpha = al actor.GetProperty().SetOpacity(alpha) actor.GetProperty().SetLineWidth(lw) actor.GetProperty().SetInterpolationToFlat() if bc: # defines a specific color for the backface backProp = vtk.vtkProperty() backProp.SetDiffuseColor(colors.getColor(bc)) backProp.SetOpacity(alpha) actor.SetBackfaceProperty(backProp) if texture: actor.texture(texture) actor.SetPosition(pos) return actor
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 Actor(gf.GetOutput())
def Arrows(startPoints, endPoints=None, s=None, scale=1, c="r", alpha=1, res=12): """ Build arrows between two lists of points `startPoints` and `endPoints`. `startPoints` can be also passed in the form ``[[point1, point2], ...]``. A dolfin ``Mesh`` that was deformed/modified by a function can be passed together as inputs. :param float s: cross-section size of the arrow :param float scale: apply a rescaling factor to the length """ 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 length: 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: sz = 800.0 * s t.Scale(length * scale, sz * scale, sz * scale) else: t.Scale(length * scale, length * scale, length * scale) tf = vtk.vtkTransformPolyDataFilter() tf.SetInputConnection(arr.GetOutputPort()) tf.SetTransform(t) polyapp.AddInputConnection(tf.GetOutputPort()) polyapp.Update() actor = Actor(polyapp.GetOutput(), c, alpha) settings.collectable_actors.append(actor) return actor
def loadNeutral(filename, c='gold', alpha=1, wire=False, bc=None, legend=None): '''Reads a Neutral tetrahedral file format''' if not os.path.exists(filename): colors.printc('Error in loadNeutral: Cannot find', filename, c=1) return None coords, connectivity = convertNeutral2Xml(filename) poly = buildPolyData(coords, connectivity, indexOffset=0) return Actor(poly, c, alpha, wire, bc, legend)
def Disc( pos=(0, 0, 0), normal=(0, 0, 1), r1=0.5, r2=1, c="coral", bc="darkgreen", lw=1, alpha=1, res=12, resphi=None, ): """ Build a 2D disc of internal radius `r1` and outer radius `r2`, oriented perpendicular to `normal`. |Disk| """ ps = vtk.vtkDiskSource() ps.SetInnerRadius(r1) ps.SetOuterRadius(r2) ps.SetRadialResolution(res) if not resphi: resphi = 6 * res ps.SetCircumferentialResolution(resphi) ps.Update() 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(np.rad2deg(theta)) t.RotateZ(np.rad2deg(phi)) tf = vtk.vtkTransformPolyDataFilter() tf.SetInputData(ps.GetOutput()) tf.SetTransform(t) tf.Update() pd = tf.GetOutput() mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(pd) actor = Actor() # vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetColor(colors.getColor(c)) actor.GetProperty().SetOpacity(alpha) actor.GetProperty().SetLineWidth(lw) actor.GetProperty().SetInterpolationToFlat() if bc: # defines a specific color for the backface backProp = vtk.vtkProperty() backProp.SetDiffuseColor(colors.getColor(bc)) backProp.SetOpacity(alpha) actor.SetBackfaceProperty(backProp) actor.SetPosition(pos) settings.collectable_actors.append(actor) return actor
def load(inputobj, c='gold', alpha=1, wire=False, bc=None, legend=True, texture=None, smoothing=None, threshold=None, connectivity=False): ''' Returns a ``vtkActor`` from reading a file, directory or ``vtkPolyData``. :param c: color in RGB format, hex, symbol or name :param alpha: transparency (0=invisible) :param wire: show surface as wireframe :param bc: backface color of internal surface :param legend: text to show on legend, True picks filename :param texture: any png/jpg file can be used as texture For volumetric data (tiff, slc, vti files): :param smoothing: gaussian filter to smooth vtkImageData :param threshold: value to draw the isosurface :param connectivity: if True only keeps the largest portion of the polydata ''' if isinstance(inputobj, vtk.vtkPolyData): a = Actor(inputobj, c, alpha, wire, bc, legend, texture) if inputobj and inputobj.GetNumberOfPoints() == 0: colors.printc('Warning: actor has zero points.', c=5) return a acts = [] if isinstance(legend, int): legend = bool(legend) if isinstance(inputobj, list): flist = inputobj else: import glob flist = sorted(glob.glob(inputobj)) for fod in flist: if os.path.isfile(fod): a = _loadFile(fod, c, alpha, wire, bc, legend, texture, smoothing, threshold, connectivity) acts.append(a) elif os.path.isdir(fod): acts = _loadDir(fod, c, alpha, wire, bc, legend, texture, smoothing, threshold, connectivity) if not len(acts): colors.printc('Error in load(): cannot find', inputobj, c=1) return None if len(acts) == 1: return acts[0] else: return acts
def polygon(pos=[0, 0, 0], normal=[0, 0, 1], nsides=6, r=1, c='coral', bc='darkgreen', lw=1, alpha=1, legend=None, texture=None, followcam=False, camera=None): ''' Build a 2D polygon of `nsides` of radius `r` oriented as `normal`. If ``followcam=True`` the polygon will always reorient itself to current camera. ''' ps = vtk.vtkRegularPolygonSource() ps.SetNumberOfSides(nsides) ps.SetRadius(r) ps.SetNormal(-np.array(normal)) ps.Update() tf = vtk.vtkTriangleFilter() tf.SetInputConnection(ps.GetOutputPort()) tf.Update() mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(tf.GetOutputPort()) if followcam: # follow cam actor = vtk.vtkFollower() actor.SetCamera(camera) if not camera: colors.printc('Warning: vtkCamera does not yet exist for polygon', c=5) else: actor = Actor() # vtk.vtkActor() actor.SetMapper(mapper) actor.GetProperty().SetColor(colors.getColor(c)) # check if color string contains a float, in this case ignore alpha al = colors._getAlpha(c) if al: alpha = al actor.GetProperty().SetOpacity(alpha) actor.GetProperty().SetLineWidth(lw) actor.GetProperty().SetInterpolationToFlat() if bc: # defines a specific color for the backface backProp = vtk.vtkProperty() backProp.SetDiffuseColor(colors.getColor(bc)) backProp.SetOpacity(alpha) actor.SetBackfaceProperty(backProp) if texture: actor.texture(texture) actor.SetPosition(pos) return actor
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() ppoints.SetData(numpy_to_vtk( list(zip(xnew, ynew, znew)), deep=True)) lines = vtk.vtkCellArray() # Create the polyline lines.InsertNextCell(Nout) for i in range(Nout): lines.InsertCellPoint(i) profileData.SetPoints(ppoints) profileData.SetLines(lines) actline = Actor(profileData, c=c, alpha=alpha, legend=legend) actline.GetProperty().SetLineWidth(s) if nodes: actnodes = vs.points(points, r=5, c=c, alpha=alpha) ass = Assembly([actline, actnodes], legend=legend) return ass else: return actline