"""Reader for NIST SAVG files.
This reader reads in a .savg file and produces a vtkPartionedDatasSetCollection
with one vtkPartitionedDataSet for each type of primitive: points, lines,
and polygons.
"""
from paraview.util.vtkAlgorithm import VTKPythonAlgorithmBase
from .. import print_error
[docs]def get_coords_from_line(line):
""" Given a line, split it, and parse out the coordinates.
Return:
A tuple containing coords (position, color, normal)
"""
values = line.split()
pt = None
pt_n = None
pt_col = None
# The first three are always the point coords
if len(values) >= 3:
pt = [float(values[0]), float(values[1]), float(values[2])]
# Then if there are only 6 total, the next three are normal coords
if len(values) == 6:
pt_n = [float(values[3]), float(values[4]), float(values[5])]
else:
if len(values) >= 7: # Otherwise the next 4 are colors
pt_col = [float(values[3]), float(values[4]), float(values[5]), float(values[6])]
if len(values) >= 10: # And if there are more, those are the normals
pt_n = [float(values[7]), float(values[8]), float(values[9])]
return pt, pt_col, pt_n
[docs]def not_supported(line):
return (
line.startswith('tri') or
line.startswith('pixel') or
line.startswith('text') or
line.startswith('program') or
line.startswith('attribute') or
line.startswith('nooptimizations')
)
[docs]class SAVGReader(VTKPythonAlgorithmBase):
def __init__(self):
VTKPythonAlgorithmBase.__init__(self, nInputPorts=0, nOutputPorts=1,
outputType="vtkPartitionedDataSetCollection")
self._filename = None
self._ndata = None
self._timesteps = None
[docs] def SetFileName(self, name):
"""Specify filename for the file to read."""
if name.lower().endswith("savg"):
if self._filename != name:
self._filename = name
self.Modified()
[docs] def RequestData(self, request, inInfoVec, outInfoVec):
from vtkmodules.vtkCommonCore import vtkFloatArray, vtkPoints
from vtkmodules.vtkCommonDataModel import (
vtkCellArray,
vtkCompositeDataSet,
vtkPartitionedDataSet,
vtkPartitionedDataSetCollection,
vtkPolyData
)
output = vtkPartitionedDataSetCollection.GetData(outInfoVec);
partitioned_datasets = []
partitioned_dataset_names = []
# Parse line file
if not self._filename:
print_error("SAVGReader requires a FileName")
return 0
# Stores lines of text from the file associated with each group of
# geometries encountered.
geometries = {
"lines": [],
"points": [],
"poly": []
}
# Read the file and build up data structure to hold the primitives
with open(self._filename, "r") as file:
current = None
for line in file:
parts = line.split("#")
line = parts[0].strip().lower()
if len(line) < 1:
continue
if not_supported(line):
continue
if line.startswith("lin"):
geometries["lines"].append({
"rgba": None,
"values": []
})
current = geometries["lines"][-1]
line_parts = line.split(" ")
if len(line_parts) == 5:
current["rgba"] = [float(n) for n in line_parts[1:]]
elif line.startswith("point"):
geometries["points"].append({
"rgba": None,
"values": [],
})
current = geometries["points"][-1]
line_parts = line.split(" ")
if len(line_parts) == 5:
current["rgba"] = [float(n) for n in line_parts[1:]]
elif line.startswith("poly"):
geometries["poly"].append({
"rgba": None,
"npts": None,
"values": [],
})
current = geometries["poly"][-1]
line_parts = line.split(" ")
if len(line_parts) == 2:
current["npts"] = int(line_parts[1])
elif len(line_parts) == 6:
current["rgba"] = [float(n) for n in line_parts[1:5]]
current["npts"] = int(line_parts[5])
elif line.startswith("end"):
current = None
else:
if current is not None:
if "npts" in current and current["npts"] is not None:
# polygon, known num pts per poly
if len(current["values"]) == current["npts"]:
# Reached the number of points for the current one,
# start a new one.
geometries["poly"].append({
"npts": current["npts"],
"rgba": current["rgba"],
"values": []
})
current = geometries["poly"][-1]
pt, pt_col, pt_n = get_coords_from_line(line)
if pt:
current["values"].append({
"pos": pt,
})
color = pt_col or current["rgba"]
if color:
current["values"][-1]["col"] = color
if pt_n:
current["values"][-1]["norm"] = pt_n
# Build lines polydata if there were any lines
if geometries["lines"]:
line_points = vtkPoints()
line_cells = vtkCellArray()
line_point_colors = vtkFloatArray()
line_point_colors.SetNumberOfComponents(4)
line_point_colors.SetName("rgba_colors")
line_point_normals = vtkFloatArray()
line_point_normals.SetNumberOfComponents(3)
line_point_normals.SetName("vertex_normals")
pt_count = 0
for batch in geometries["lines"]:
num_in_batch = len(batch["values"])
first_in_batch = True
for coord in batch["values"]:
if "pos" in coord:
line_points.InsertNextPoint(coord["pos"])
if "norm" in coord:
line_point_normals.InsertNextTuple(coord["norm"])
if "col" in coord:
line_point_colors.InsertNextTuple(coord["col"])
if first_in_batch:
line_cells.InsertNextCell(num_in_batch)
first_in_batch = False
line_cells.InsertCellPoint(pt_count)
pt_count += 1
output_lines = vtkPolyData()
output_lines.SetPoints(line_points)
output_lines.SetLines(line_cells)
if line_point_colors.GetNumberOfTuples() > 0:
output_lines.GetPointData().AddArray(line_point_colors)
if line_point_normals.GetNumberOfTuples() > 0:
output_lines.GetPointData().AddArray(line_point_normals)
ds = vtkPartitionedDataSet()
ds.SetNumberOfPartitions(1)
ds.SetPartition(0, output_lines)
partitioned_datasets.append(ds)
partitioned_dataset_names.append("Lines")
# Build the points polydata if we found points
if geometries["points"]:
p_points = vtkPoints()
p_cells = vtkCellArray()
p_point_colors = vtkFloatArray()
p_point_colors.SetNumberOfComponents(4)
p_point_colors.SetName("rgba_colors")
p_point_normals = vtkFloatArray()
p_point_normals.SetNumberOfComponents(3)
p_point_normals.SetName("vertex_normals")
p_count = 0
for batch in geometries["points"]:
num_in_batch = len(batch["values"])
first_in_batch = True
for coord in batch["values"]:
if "pos" in coord:
p_points.InsertNextPoint(coord["pos"])
if "norm" in coord:
p_point_normals.InsertNextTuple(coord["norm"])
if "col" in coord:
p_point_colors.InsertNextTuple(coord["col"])
if first_in_batch:
p_cells.InsertNextCell(num_in_batch)
first_in_batch = False
p_cells.InsertCellPoint(p_count)
p_count += 1
output_points = vtkPolyData()
output_points.SetPoints(p_points)
output_points.SetVerts(p_cells)
if p_point_colors.GetNumberOfTuples() > 0:
output_points.GetPointData().AddArray(p_point_colors)
if p_point_normals.GetNumberOfTuples() > 0:
output_points.GetPointData().AddArray(p_point_normals)
ds = vtkPartitionedDataSet()
ds.SetNumberOfPartitions(1)
ds.SetPartition(0, output_points)
partitioned_datasets.append(ds)
partitioned_dataset_names.append("Points")
# Build the polygons if there were any
if geometries["poly"]:
poly_points = vtkPoints()
poly_cells = vtkCellArray()
poly_point_colors = vtkFloatArray()
poly_point_colors.SetNumberOfComponents(4)
poly_point_colors.SetName("rgba_colors")
poly_point_normals = vtkFloatArray()
poly_point_normals.SetNumberOfComponents(3)
poly_point_normals.SetName("vertex_normals")
pt_count = 0
for batch in geometries["poly"]:
num_in_batch = len(batch["values"])
if num_in_batch < 1:
continue
first_in_batch = True
for coord in batch["values"]:
if "pos" in coord:
poly_points.InsertNextPoint(coord["pos"])
if "norm" in coord:
poly_point_normals.InsertNextTuple(coord["norm"])
if "col" in coord:
poly_point_colors.InsertNextTuple(coord["col"])
if first_in_batch:
np_in_cell = num_in_batch
poly_cells.InsertNextCell(np_in_cell)
first_in_batch = False
poly_cells.InsertCellPoint(pt_count)
pt_count += 1
output_polys = vtkPolyData()
output_polys.SetPoints(poly_points)
output_polys.SetPolys(poly_cells)
if poly_point_colors.GetNumberOfTuples() > 0:
output_polys.GetPointData().AddArray(poly_point_colors)
if poly_point_normals.GetNumberOfTuples() > 0:
output_polys.GetPointData().AddArray(poly_point_normals)
ds = vtkPartitionedDataSet()
ds.SetNumberOfPartitions(1)
ds.SetPartition(0, output_polys)
partitioned_datasets.append(ds)
partitioned_dataset_names.append("Polygons")
# Add any partioned datasets we created
output.SetNumberOfPartitionedDataSets(len(partitioned_datasets))
for idx, pds in enumerate(partitioned_datasets):
output.SetPartitionedDataSet(idx, pds)
output.GetMetaData(idx).Set(vtkCompositeDataSet.NAME(), partitioned_dataset_names[idx])
return 1