Skip to content

Commit

Permalink
oolydata.py
Browse files Browse the repository at this point in the history
Contains a wrapper class of vtk's polydata. All constructed plots are
now based on this as it's much easier to use.

Added print flushing to BaseFigure.show() to try to get it to finish
printing before the render opens. It's not brilliant.

unicode_paths.py
Full support for non ascii characters in paths which vtk can't handle.
Uses a PathHandler class. This has been built into the screenshot
feature and the VTK STL reader.

MeshPlot.py
Updated to allow numpy-stl or vtk to try to read directly from a path.
The vtk reader has a hole in it somewhere and doesn't support every
file. Hence rabbit.stl test model is duplicated and rewritten as
rabbit2.stl. Hopefully at least one will work.
  • Loading branch information
bwoodsend committed Sep 1, 2019
1 parent f7c1479 commit 3cc8017
Show file tree
Hide file tree
Showing 14 changed files with 825 additions and 124 deletions.
3 changes: 2 additions & 1 deletion vtkplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@

from .plots.Arrow import arrow, quiver
from .plots.Lines import Lines as plot
from .plots.MeshPlot import MeshPlot as mesh_plot, mesh_plot_with_edge_scalars
from .plots.MeshPlot import MeshPlot as mesh_plot, mesh_plot_with_edge_scalars, NUMPY_STL_AVAILABLE
from .plots.Polygon import Polygon as polygon
from .plots.ScalarBar import ScalarBar as scalar_bar
from .plots.Scatter import scatter, Cursor as cursor
from .plots.Surface import Surface
from .plots.Text import Text as text
from .plots.Text3D import Text3D as text3d, annotate

Expand Down
8 changes: 5 additions & 3 deletions vtkplotlib/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


import numpy as np
import matplotlib.pylab as plt
import sys
import os
from pathlib2 import Path
Expand All @@ -36,10 +35,13 @@

STL_FOLDER = DATA_FOLDER / "models"

def get_rabbit_stl():
def get_rabbit_stl(two=sys.platform=="win32"):
folder = STL_FOLDER
print("This is not my rabbit file. See README.txt and LICENSE.txt in\n{}\nfor details.".format(folder))
return str(folder / "rabbit.stl")
if two:
return str(folder / "rabbit2.stl")
else:
return str(folder / "rabbit.stl")

ICONS_FOLDER = DATA_FOLDER / "icons"

Expand Down
Binary file added vtkplotlib/data/models/rabbit2.stl
Binary file not shown.
9 changes: 7 additions & 2 deletions vtkplotlib/figures/BaseFigure.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import print_function
from builtins import super

import numpy as np
Expand Down Expand Up @@ -51,9 +52,13 @@ def reset_camera(self):

def show(self, block=True):
# Try and force the console to finish displaying any preceeding print
# statements before VTK start is called and blocks everything. With
# statements before VTK start is called and blocks everything. Rather
# limited success.
print(end="", flush=True)
try:
# python 2 doesn't have flush
print(end="", flush=True)
except TypeError:
pass
sys.stdout.flush()
for attr in ("buffer", "_buffer"):
if hasattr(sys.stdout, attr):
Expand Down
32 changes: 18 additions & 14 deletions vtkplotlib/figures/figure_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,14 @@ def save_fig(path, magnifigation=1, pixels=None, fig="gcf"):
magnifigation:
An int or a (width, height) tuple of ints.
Set the image dimensions relative to the size of the render.
Set the image dimensions relative to the size of the render (window).
pixels:
An int or a (width, height) tuple of ints.
Set the image dimensions in pixels. If only one dimension is given
then it is the height and an aspect ration of 16:9 is used.
then it is the height and an aspect ration of 16:9 is used. Overides
`magnification` if given.
Note that VTK can only work with integer multiples of the render size
Expand Down Expand Up @@ -261,18 +262,21 @@ def save_fig(path, magnifigation=1, pixels=None, fig="gcf"):
w2if.SetMagnification(magnifigation[0])
w2if.Update()

old_path = Path.cwd()
os.chdir(str(path.parent))
if path.suffix.lower() in (".jpg", ".jpeg"):
writer = vtk.vtkJPEGWriter()
elif path.suffix.lower() == ".png":
writer = vtk.vtkPNGWriter()
else:
raise NotImplementedError(path.suffix + " is not supported")
writer.SetFileName(path.name)
writer.SetInputConnection(w2if.GetOutputPort())
writer.Write()
os.chdir(str(old_path))
from vtkplotlib.unicode_paths import PathHandler

with PathHandler(path, "w") as path_handler:

# if path.suffix.lower() in (".jpg", ".jpeg"):
# writer = vtk.vtkJPEGWriter()
# elif path.suffix.lower() == ".png":
# writer = vtk.vtkPNGWriter()
# else:
# raise NotImplementedError(path.suffix + " is not supported")
writer = vtk.vtkImageWriter()

writer.SetFileName(path_handler.access_path)
writer.SetInputConnection(w2if.GetOutputPort())
writer.Write()



Expand Down
21 changes: 14 additions & 7 deletions vtkplotlib/plots/BasePlot.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from vtkplotlib.figures import gcf
from vtkplotlib.colors import process_color
from vtkplotlib import nuts_and_bolts

from vtkplotlib.plots.polydata import PolyData



Expand All @@ -50,15 +50,15 @@ def __init__(self, fig="gcf"):
fig = gcf()
self.fig = fig
self.temp = []


def add_to_plot(self):

self.mapper = vtk.vtkPolyDataMapper()

self.actor = vtk.vtkActor()
self.actor.SetMapper(self.mapper)


def add_to_plot(self):
self.actor.SetMapper(self.mapper)

self.property = self.actor.GetProperty()
if self.fig is not None:
self.fig.add_plot(self)
Expand Down Expand Up @@ -127,11 +127,18 @@ class ConstructedPlot(BasePlot):
"""
def __init__(self, fig="gcf"):
super().__init__(fig)
self.poly_data = vtk.vtkPolyData()
self.polydata = PolyData()

def add_to_plot(self):
super().add_to_plot()
self.mapper.SetInputData(self.poly_data)
if vtk.VTK_MAJOR_VERSION <= 5:
self.mapper.SetInput(self.polydata.vtk_polydata)
else:
self.mapper.SetInputData(self.polydata.vtk_polydata)

scalars = self.polydata.point_scalars
if scalars is not None:
self.mapper.SetScalarRange(np.nanmin(scalars), np.nanmin(scalars.max()))



Expand Down
59 changes: 24 additions & 35 deletions vtkplotlib/plots/Lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@


from vtkplotlib.plots.BasePlot import ConstructedPlot, _iter_colors, _iter_points, _iter_scalar
from vtkplotlib import geometry as geom, numpy_vtk
from vtkplotlib import numpy_vtk, nuts_and_bolts
from vtkplotlib.plots.polydata import join_line_ends



Expand All @@ -49,39 +50,21 @@ class Lines(ConstructedPlot):
def __init__(self, vertices, color=None, opacity=None, line_width=1.0, join_ends=False, fig="gcf"):
super().__init__(fig)

vertices = numpy_vtk.contiguous_safe(vertices)
self.temp.append(vertices)

points = vtk.vtkPoints()
points.SetData(numpy_to_vtk(vertices))
shape = vertices.shape[:-1]
points = numpy_vtk.contiguous_safe(nuts_and_bolts.flatten_all_but_last(vertices))
self.temp.append(points)

# vtkCellArray is a supporting object that explicitly represents cell connectivity.
# The cell array structure is a raw integer list of the form:
# (n,id1,id2,...,idn, n,id1,id2,...,idn, ...) where n is the number of points in
# the cell, and id is a zero-offset index into an associated point list.
args = nuts_and_bolts.flatten_all_but_last(np.arange(np.prod(shape)).reshape(shape))

point_args = np.empty(1 + len(vertices) + join_ends, np.int64)
point_args[0] = len(vertices) + join_ends
point_args[1: 1+len(vertices)] = np.arange(len(vertices))
self.polydata.points = points
if join_ends:
point_args[-1] = 0
lines = vtk.vtkCellArray()
lines.SetCells(len(point_args), numpy_to_vtkIdTypeArray(point_args.ravel()))
self.polydata.lines = join_line_ends(args)
else:
self.polydata.lines = args

# assert np.array_equal(points[args], vertices)

# vtkPolyData is a data object that is a concrete implementation of vtkDataSet.
# vtkPolyData represents a geometric structure consisting of vertices, lines,
# polygons, and/or triangle strips
polygon = self.poly_data
polygon.SetPoints(points)
polygon.SetLines(lines)


# Create an actor to represent the polygon. The actor orchestrates rendering of
# the mapper's graphics primitives. An actor also refers to properties via a
# vtkProperty instance, and includes an internal transformation matrix. We
# set this actor's mapper to be polygonMapper which we created above.
self.actor = vtk.vtkActor()

self.add_to_plot()

Expand All @@ -92,17 +75,23 @@ def __init__(self, vertices, color=None, opacity=None, line_width=1.0, join_ends





if __name__ == "__main__":
import vtkplotlib as vpl

t = np.arange(0, 1, .001) * 2 * np.pi
points = np.array([np.cos(2 * t),
np.sin(3 * t),
np.cos(5 * t) * np.sin(7 *t)]).T
vertices = np.array([np.cos(2 * t),
np.sin(3 * t),
np.cos(5 * t) * np.sin(7 *t)]).T
vertices = np.array([vertices, vertices + 2])

# vertices = np.random.uniform(-30, 30, (3, 3))
self = vpl.plot(points, color="green", line_width=3, join_ends=True)
t = np.arange(0, 1, .125) * 2 * np.pi
vertices = np.array([np.cos(t), np.sin(t), np.zeros_like(t)]).T

# vertices = np.random.uniform(-30, 30, (3, 3))
self = vpl.plot(vertices, color="green", line_width=6, join_ends=True)
# self.polydata.point_scalars = vpl.geometry.distance(vertices)
self.polydata.point_scalars = t
fig = vpl.gcf()
fig.background_color = "grey"
self.add_to_plot()
vpl.show()
Loading

0 comments on commit 3cc8017

Please sign in to comment.