Skip to content
Snippets Groups Projects
Commit 4d6d5433 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Initial, very rough, 3D model implementation

parent 0105d74b
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python
#
# model.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import numpy as np
def loadVTKPolydataFile(infile):
lines = None
with open(infile, 'rt') as f:
lines = f.readlines()
lines = [l.strip() for l in lines]
if lines[3] != 'DATASET POLYDATA':
raise ValueError('')
nVertices = int(lines[4].split()[1])
nPolygons = int(lines[5 + nVertices].split()[1])
nIndices = int(lines[5 + nVertices].split()[2]) - nPolygons
vertices = np.zeros((nVertices, 3), dtype=np.float32)
polygonLengths = np.zeros( nPolygons, dtype=np.uint32)
indices = np.zeros( nIndices, dtype=np.uint32)
for i in range(nVertices):
vertLine = lines[i + 5]
vertices[i, :] = map(float, vertLine.split())
indexOffset = 0
for i in range(nPolygons):
polyLine = lines[6 + nVertices + i].split()
polygonLengths[i] = int(polyLine[0])
start = indexOffset
end = indexOffset + polygonLengths[i]
indices[start:end] = map(int, polyLine[1:])
indexOffset += polygonLengths[i]
return vertices, polygonLengths, indices
class PolygonModel(object):
def __init__(self, data, indices=None):
"""
"""
if isinstance(data, str):
infile = data
data, lengths, indices = loadVTKPolydataFile(infile)
if np.any(lengths != 3):
raise RuntimeError('All polygons in VTK file must be '
'triangles ({})'.format(infile))
if indices is None:
indices = np.arange(data.shape[0], dtype=np.uint32)
self.vertices = np.array(data, dtype=np.float32)
self.indices = indices
def getBounds(self):
return (self.vertices.min(axis=0),
self.vertices.max(axis=0))
#!/usr/bin/env python
#
# modelopts.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import numpy as np
import props
import display as fsldisplay
class ModelOpts(fsldisplay.DisplayOpts):
colour = props.Colour()
outline = props.Boolean(default=True)
def __init__(self, *args, **kwargs):
fsldisplay.DisplayOpts.__init__(self, *args, **kwargs)
colour = np.random.random(4)
colour[3] = 1.0
self.colour = colour
#!/usr/bin/env python
#
# glvtkobject.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import numpy as np
import OpenGL.GL as gl
import globject
import fsl.fslview.gl.routines as glroutines
class GLModel(globject.GLObject):
def __init__(self, overlay, display):
globject.GLObject.__init__(self)
self.overlay = overlay
self.display = display
self.opts = display.getDisplayOpts()
def destroy(self):
pass
def getDisplayBounds(self):
return self.overlay.getBounds()
def setAxes(self, xax, yax):
self.xax = xax
self.yax = yax
self.zax = 3 - xax - yax
self._prepareOutlineVertices()
def _prepareOutlineVertices(self):
verts = self.overlay.vertices
mean = verts.mean(axis=0)
verts = verts - mean
verts[:, self.xax] *= 0.9
verts[:, self.yax] *= 0.9
verts += mean
self.outlineVertices = verts
def preDraw(self):
pass
def draw(self, zpos, xform=None):
if self.opts.outline: self.drawOutline(zpos, xform)
else: self.drawFilled( zpos, xform)
def drawFilled(self, zpos, xform):
xax = self.xax
yax = self.yax
zax = self.zax
lo, hi = self.getDisplayBounds()
xmin = lo[xax]
ymin = lo[yax]
xmax = hi[xax]
ymax = hi[yax]
clipPlaneVerts = np.zeros((4, 3), dtype=np.float32)
clipPlaneVerts[0, [xax, yax]] = [xmin, ymin]
clipPlaneVerts[1, [xax, yax]] = [xmin, ymax]
clipPlaneVerts[2, [xax, yax]] = [xmax, ymax]
clipPlaneVerts[3, [xax, yax]] = [xmax, ymin]
clipPlaneVerts[:, zax] = zpos
planeEq = glroutines.planeEquation(clipPlaneVerts[0, :],
clipPlaneVerts[1, :],
clipPlaneVerts[2, :])
vertices = self.overlay.vertices
indices = self.overlay.indices
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glEnable(gl.GL_CLIP_PLANE0)
gl.glEnable(gl.GL_CULL_FACE)
gl.glEnable(gl.GL_STENCIL_TEST)
gl.glClipPlane(gl.GL_CLIP_PLANE0, planeEq)
gl.glClear(gl.GL_STENCIL_BUFFER_BIT)
gl.glColorMask(gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE)
# first pass - render front faces
gl.glStencilFunc(gl.GL_ALWAYS, 0, 0)
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR)
gl.glCullFace(gl.GL_BACK)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
# Second pass - render back faces
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_DECR)
gl.glCullFace(gl.GL_FRONT)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
# third pass - render the intersection
# of the front and back faces from the
# stencil buffer
gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
gl.glDisable(gl.GL_CLIP_PLANE0)
gl.glDisable(gl.GL_CULL_FACE)
gl.glStencilFunc(gl.GL_NOTEQUAL, 0, 255)
colour = self.opts.colour
colour[3] = self.display.alpha
gl.glColor(*colour)
gl.glBegin(gl.GL_QUADS)
gl.glVertex3f(*clipPlaneVerts[0, :])
gl.glVertex3f(*clipPlaneVerts[1, :])
gl.glVertex3f(*clipPlaneVerts[2, :])
gl.glVertex3f(*clipPlaneVerts[3, :])
gl.glEnd()
gl.glDisable(gl.GL_STENCIL_TEST)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
def drawOutline(self, zpos, xform):
xax = self.xax
yax = self.yax
zax = self.zax
lo, hi = self.getDisplayBounds()
xmin = lo[xax]
ymin = lo[yax]
xmax = hi[xax]
ymax = hi[yax]
clipPlaneVerts = np.zeros((4, 3), dtype=np.float32)
clipPlaneVerts[0, [xax, yax]] = [xmin, ymin]
clipPlaneVerts[1, [xax, yax]] = [xmin, ymax]
clipPlaneVerts[2, [xax, yax]] = [xmax, ymax]
clipPlaneVerts[3, [xax, yax]] = [xmax, ymin]
clipPlaneVerts[:, zax] = zpos
planeEq = glroutines.planeEquation(clipPlaneVerts[0, :],
clipPlaneVerts[1, :],
clipPlaneVerts[2, :])
vertices = self.overlay.vertices
olVertices = self.outlineVertices
indices = self.overlay.indices
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
gl.glEnable(gl.GL_CLIP_PLANE0)
gl.glEnable(gl.GL_CULL_FACE)
gl.glEnable(gl.GL_STENCIL_TEST)
gl.glClipPlane(gl.GL_CLIP_PLANE0, planeEq)
gl.glClear(gl.GL_STENCIL_BUFFER_BIT)
gl.glColorMask(gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE)
# first pass - render front faces
gl.glStencilFunc(gl.GL_ALWAYS, 0, 0)
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR)
gl.glCullFace(gl.GL_BACK)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, olVertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
# Second pass - render back faces
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR)
gl.glCullFace(gl.GL_FRONT)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, vertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
gl.glStencilOp(gl.GL_KEEP, gl.GL_KEEP, gl.GL_INCR)
gl.glVertexPointer(3, gl.GL_FLOAT, 0, olVertices)
gl.glDrawElements(gl.GL_TRIANGLES,
len(indices),
gl.GL_UNSIGNED_INT,
indices)
# third pass - render the intersection
# of the front and back faces from the
# stencil buffer
gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE)
gl.glDisable(gl.GL_CLIP_PLANE0)
gl.glDisable(gl.GL_CULL_FACE)
gl.glStencilFunc(gl.GL_EQUAL, 3, 255)
colour = self.opts.colour
colour[3] = self.display.alpha
gl.glColor(*colour)
gl.glBegin(gl.GL_QUADS)
gl.glVertex3f(*clipPlaneVerts[0, :])
gl.glVertex3f(*clipPlaneVerts[1, :])
gl.glVertex3f(*clipPlaneVerts[2, :])
gl.glVertex3f(*clipPlaneVerts[3, :])
gl.glEnd()
gl.glStencilFunc(gl.GL_EQUAL, 1, 255)
colour = self.opts.colour
colour[3] = self.display.alpha
gl.glColor(*colour)
gl.glBegin(gl.GL_QUADS)
gl.glVertex3f(*clipPlaneVerts[0, :])
gl.glVertex3f(*clipPlaneVerts[1, :])
gl.glVertex3f(*clipPlaneVerts[2, :])
gl.glVertex3f(*clipPlaneVerts[3, :])
gl.glEnd()
gl.glDisable(gl.GL_STENCIL_TEST)
gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
def postDraw(self):
pass
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment