KochSnowflake
VTKExamples/Python/Visualization/KochSnowflake
Description¶
This script draws a Koch snowflake using the VTK. The general idea is to exercise some of the components of a vtkPolyData to produce something interesting rather than a boring old cube. Not that I have anything against cubes. There is also a C++ version of this example: KochSnowflake.
Code¶
KochSnowflake.py
#!/usr/bin/env python # ----------------------------------------------------------------------------- # # Imports # # ----------------------------------------------------------------------------- # from math import pi, cos, sin, sqrt import vtk LEVEL = 6 # ----------------------------------------------------------------------------- # # Koch Snowflake as vtkPolyLine # # ----------------------------------------------------------------------------- # def as_polyline(points, level): # Use the points from the previous iteration to create the points of the next # level. There is an assumption on my part that the curve is traversed in a # counterclockwise fashion. If the initial triangle above is written to # describe clockwise motion, the points will face inward instead of outward. for i in range(level): temp = vtk.vtkPoints() # The first point of the previous vtkPoints is the first point of the next vtkPoints. temp.InsertNextPoint(*points.GetPoint(0)) # Iterate over "edges" in the vtkPoints for i in range(1, points.GetNumberOfPoints()): x0, y0, z0 = points.GetPoint(i - 1) x1, y1, z1 = points.GetPoint(i) t = sqrt((x1 - x0)**2 + (y1 - y0)**2) nx = (x1 - x0) / t # x-component of edge unit tangent ny = (y1 - y0) / t # y-component of edge unit tangent # the points describing the Koch snowflake edge temp.InsertNextPoint(x0 + nx * t / 3, y0 + ny * t / 3, 0.) temp.InsertNextPoint(x0 + nx * t / 2 + ny * t * sqrt(3) / 6, y0 + ny * t / 2 - nx * t * sqrt(3) / 6, 0.) temp.InsertNextPoint(x0 + nx * 2 * t / 3, y0 + ny * 2 * t / 3, 0.) temp.InsertNextPoint(x0 + nx * t, y0 + ny * t, 0.) points = temp # draw the outline lines = vtk.vtkCellArray() pl = vtk.vtkPolyLine() pl.GetPointIds().SetNumberOfIds(points.GetNumberOfPoints()) for i in range(points.GetNumberOfPoints()): pl.GetPointIds().SetId(i, i) lines.InsertNextCell(pl) # complete the polydata polydata = vtk.vtkPolyData() polydata.SetLines(lines) polydata.SetPoints(points) return polydata # ----------------------------------------------------------------------------- # # Koch Snowflake as collection of vtkTriangles # # ----------------------------------------------------------------------------- # def as_triangles(indices, cellarray, level, data): if len(indices) >= 3: stride = len(indices) // 4 indices.append(indices[-1] + 1) triangle = vtk.vtkTriangle() triangle.GetPointIds().SetId(0, indices[stride]) triangle.GetPointIds().SetId(1, indices[2 * stride]) triangle.GetPointIds().SetId(2, indices[3 * stride]) cellarray.InsertNextCell(triangle) data.InsertNextValue(level) as_triangles(indices[0: stride], cellarray, level + 1, data) as_triangles(indices[stride: 2 * stride], cellarray, level + 1, data) as_triangles(indices[2 * stride: 3 * stride], cellarray, level + 1, data) as_triangles(indices[3 * stride: -1], cellarray, level + 1, data) # ----------------------------------------------------------------------------- # # Main Method # # ----------------------------------------------------------------------------- # if __name__ == "__main__": # Initially, set up the points to be an equilateral triangle. Note that the # first point is the same as the last point to make this a closed curve when # I create the vtkPolyLine. points = vtk.vtkPoints() for i in range(4): points.InsertNextPoint(cos(2. * pi * i / 3), sin(2 * pi * i / 3.), 0.) outline_pd = as_polyline(points, LEVEL) # You have already gone through the trouble of putting the points in the # right places - so "all" you need todo now is to create polygons from the # points that are in the vtkPoints. # The points that are passed in, have an overlap of the beginning and the # end. For this next trick, I will need a list of the indices in the # vtkPoints. They're consecutive, so thats pretty straightforward. indices = [i for i in range(outline_pd.GetPoints().GetNumberOfPoints() + 1)] triangles = vtk.vtkCellArray() # Set this up for each of the initial sides, then call the recursive function. stride = (len(indices) - 1) // 3 # The cell data will allow us to color the triangles based on the level of # the iteration of the Koch snowflake. data = vtk.vtkIntArray() data.SetNumberOfComponents(0) data.SetName("Iteration Level") # This is the starting triangle. t = vtk.vtkTriangle() t.GetPointIds().SetId(0, 0) t.GetPointIds().SetId(1, stride) t.GetPointIds().SetId(2, 2 * stride) triangles.InsertNextCell(t) data.InsertNextValue(0) as_triangles(indices[0: stride + 1], triangles, 1, data) as_triangles(indices[stride: 2 * stride + 1], triangles, 1, data) as_triangles(indices[2 * stride: -1], triangles, 1, data) triangle_pd = vtk.vtkPolyData() triangle_pd.SetPoints(outline_pd.GetPoints()) triangle_pd.SetPolys(triangles) triangle_pd.GetCellData().SetScalars(data) # ---------------- # # rendering stuff # # ---------------- # outline_mapper = vtk.vtkPolyDataMapper() outline_mapper.SetInputData(outline_pd) lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(256) lut.SetHueRange(0.6, 0.6) lut.SetSaturationRange(0., 1.) lut.Build() triangle_mapper = vtk.vtkPolyDataMapper() triangle_mapper.SetInputData(triangle_pd) triangle_mapper.SetScalarRange(0.0, LEVEL) triangle_mapper.SetLookupTable(lut) outline_actor = vtk.vtkActor() outline_actor.SetMapper(outline_mapper) triangle_actor = vtk.vtkActor() triangle_actor.SetMapper(triangle_mapper) outline_ren = vtk.vtkRenderer() outline_ren.AddActor(outline_actor) outline_ren.SetViewport(0.0, 0.0, 0.5, 1.0) triangle_ren = vtk.vtkRenderer() triangle_ren.AddActor(triangle_actor) triangle_ren.SetViewport(0.5, 0.0, 1.0, 1.0) triangle_ren.SetActiveCamera(outline_ren.GetActiveCamera()) renw = vtk.vtkRenderWindow() renw.AddRenderer(outline_ren) renw.AddRenderer(triangle_ren) renw.SetSize(800, 400) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renw) outline_ren.ResetCamera() renw.Render() iren.Start()