summaryrefslogtreecommitdiff
path: root/geometry.py
diff options
context:
space:
mode:
Diffstat (limited to 'geometry.py')
-rw-r--r--geometry.py158
1 files changed, 141 insertions, 17 deletions
diff --git a/geometry.py b/geometry.py
index 5cd1bf2..be31e4b 100644
--- a/geometry.py
+++ b/geometry.py
@@ -1,9 +1,117 @@
import numpy as np
-import numpy.ma as ma
import pycuda.driver as cuda
from pycuda import gpuarray
-from mesh import Mesh
-from materials import standard_wavelengths
+
+# all material/surface properties are interpolated at these
+# wavelengths when they are sent to the gpu
+standard_wavelengths = np.arange(200, 810, 20).astype(np.float32)
+
+class Mesh(object):
+ def __init__(self, vertices, triangles):
+ vertices = np.asarray(vertices, dtype=np.float32)
+ triangles = np.asarray(triangles, dtype=np.int32)
+
+ if len(vertices.shape) != 2 or vertices.shape[1] != 3:
+ raise ValueError('shape mismatch')
+
+ if len(triangles.shape) != 2 or triangles.shape[1] != 3:
+ raise ValueError('shape mismatch')
+
+ if (triangles < 0).any():
+ raise ValueError('indices in `triangles` must be positive.')
+
+ if (triangles >= len(vertices)).any():
+ raise ValueError('indices in `triangles` must be less than the '
+ 'length of the vertex array.')
+
+ self.vertices = vertices
+ self.triangles = triangles
+
+ def build(self):
+ return self.vertices[self.triangles]
+
+ def __getitem__(self, key):
+ return self.vertices[self.triangles[key]]
+
+ def __len__(self):
+ return len(self.triangles)
+
+ def __add__(self, other):
+ return Mesh(np.concatenate((self.vertices, other.vertices)), np.concatenate((self.triangles, other.triangles + len(self.vertices))))
+
+class Solid(object):
+ def __init__(self, mesh, material1=None, material2=None, surface=None, color=0xffffffff):
+ self.mesh = mesh
+
+ if np.iterable(material1):
+ if len(material1) != len(mesh):
+ raise ValueError('shape mismatch')
+ self.material1 = np.array(material1, dtype=np.object)
+ else:
+ self.material1 = np.tile(material1, len(self.mesh))
+
+ if np.iterable(material2):
+ if len(material2) != len(mesh):
+ raise ValueError('shape mismatch')
+ self.material2 = np.array(material2, dtype=np.object)
+ else:
+ self.material2 = np.tile(material2, len(self.mesh))
+
+ if np.iterable(surface):
+ if len(surface) != len(mesh):
+ raise ValueError('shape mismatch')
+ self.surface = np.array(surface, dtype=np.object)
+ else:
+ self.surface = np.tile(surface, len(self.mesh))
+
+ if np.iterable(color):
+ if len(color) != len(mesh):
+ raise ValueError('shape mismatch')
+ self.color = np.array(color, dtype=np.uint32)
+ else:
+ self.color = np.tile(color, len(self.mesh)).astype(np.uint32)
+
+ def __len__(self):
+ return len(self.mesh)
+
+ def __add__(self, other):
+ return Solid(self.mesh + other.mesh, np.concatenate((self.material1, other.material1)), np.concatenate((self.material2, other.material2)), np.concatenate((self.surface, other.surface)), np.concatenate((self.color, other.color)))
+
+class Material(object):
+ """Material optical properties."""
+ def __init__(self, name='none'):
+ self.name = name
+
+ self.refractive_index = None
+ self.absorption_length = None
+ self.scattering_length = None
+
+ def set(self, name, value, wavelengths=standard_wavelengths):
+ if np.iterable(value):
+ if len(value) != len(wavelengths):
+ raise ValueError('shape mismatch')
+ else:
+ value = np.tile(value, len(wavelengths))
+
+ self.__dict__[name] = np.array(zip(wavelengths, value), dtype=np.float32)
+
+class Surface(object):
+ """Surface optical properties."""
+ def __init__(self, name='none'):
+ self.name = name
+
+ self.absorption = None
+ self.reflection_diffuse = None
+ self.reflection_specular = None
+
+ def set(self, name, value, wavelengths=standard_wavelengths):
+ if np.iterable(value):
+ if len(value) != len(wavelengths):
+ raise ValueError('shape mismatch')
+ else:
+ value = np.tile(value, len(wavelengths))
+
+ self.__dict__[name] = np.array(zip(wavelengths, value), dtype=np.float32)
def interleave(arr, bits):
"""
@@ -51,15 +159,30 @@ def morton_order(mesh, bits):
return interleave(mean_positions, bits)
class Geometry(object):
- def __init__(self, solids=None):
- if solids is not None:
- self.solids = list(solids)
- else:
- self.solids = []
+ def __init__(self):
+ self.solids = []
+ self.solid_rotations = []
+ self.solid_displacements = []
+
+ def add_solid(self, solid, rotation=np.identity(3), displacement=(0,0,0)):
+ rotation = np.asarray(rotation, dtype=np.float32)
+
+ if rotation.shape != (3,3):
+ raise ValueError('shape mismatch')
+
+ self.solid_rotations.append(rotation.astype(np.float32))
+
+ displacement = np.asarray(displacement, dtype=np.float32)
+
+ if displacement.shape != (3,):
+ raise ValueError('shape mismatch')
+
+ self.solid_displacements.append(displacement)
- def add_solid(self, solid):
self.solids.append(solid)
+ return len(self.solids)-1
+
def build(self, bits=8):
offsets = [ (0,0) ]
for solid in self.solids:
@@ -69,15 +192,14 @@ class Geometry(object):
vertices = np.zeros(shape=(offsets[-1][0], 3), dtype=np.float32)
triangles = np.zeros(shape=(offsets[-1][1],3), dtype=np.int32)
- for solid, (vertex_offset, triangle_offset) in zip(self.solids, offsets[:-1]):
+ for i, (solid, (vertex_offset, triangle_offset)) in \
+ enumerate(zip(self.solids, offsets[:-1])):
triangles[triangle_offset:triangle_offset+len(solid.mesh.triangles),:] = \
solid.mesh.triangles + vertex_offset
- vertices[vertex_offset:vertex_offset + len(solid.mesh.vertices),:] = \
- np.inner(solid.mesh.vertices, solid.rotation) + solid.displacement
+ vertices[vertex_offset:vertex_offset+len(solid.mesh.vertices),:] = \
+ np.inner(solid.mesh.vertices, self.solid_rotations[i]) + self.solid_displacements[i]
self.mesh = Mesh(vertices, triangles)
- #del vertices
- #del triangles
zvalues_mesh = morton_order(self.mesh[:], bits)
reorder = np.argsort(zvalues_mesh)
@@ -121,10 +243,12 @@ class Geometry(object):
else:
self.surface_index[i] = -1
- self.colors = np.concatenate([solid.color for solid in self.solids])[reorder]
+ self.colors = \
+ np.concatenate([solid.color for solid in self.solids])[reorder]
- self.solid_id = np.concatenate([np.tile(solid.id, len(solid.mesh)) \
- for solid in self.solids])[reorder]
+ self.solid_id = \
+ np.concatenate([np.tile(i, len(solid.mesh)) for i, solid in \
+ enumerate(self.solids)])[reorder]
unique_zvalues = np.unique(zvalues_mesh)
zvalues = np.empty(unique_zvalues.size, dtype=np.uint64)