Skip to content

Commit

Permalink
face orientation
Browse files Browse the repository at this point in the history
  • Loading branch information
brsr committed Mar 17, 2017
1 parent 4c52ad7 commit 0a16001
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 17 deletions.
50 changes: 42 additions & 8 deletions antitile/tiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
Generic polyhedron and tiling methods
"""
import numpy as np
from scipy.linalg import circulant

class Tiling:
"""Generic class for tilings and polyhedrons"""
def __init__(self, vertices, faces):
self.vertices = vertices
self.faces = faces
Expand All @@ -13,29 +15,61 @@ def __init__(self, vertices, faces):
def edges(self):
"""Returns a list of edges in the tiling"""
return edges_from_facelist(self.faces)


@property
def face_size(self):
return np.array([len(x) for x in self.faces])

@property
def face_orientation(self):
"""Returns the orientation of each face in the tiling with
respect to (0,0,0)."""
#only really need this for triangles and squares
return NotImplemented
"""Returns the orientation of the points in each face in the
tiling with respect to (0,0,0). 1 is counterclockwise, -1 is
clockwise, 0 means it's mixed (probably some sort of weird
self-intersecting thing) or lies on a plane through the origin."""
lens = self.face_size
min_len = lens.min()
max_len = lens.max()
orientation = np.zeros(lens.shape, dtype=np.int8)
for i in range(min_len, max_len+1):
index = lens == i
i_faces = np.array([self.faces[i] for i in np.nonzero(index)[0]])
i_pts = self.vertices[i_faces]
if i == 3:
dets = np.linalg.det(i_pts)
cclock = dets > 0
clock = dets < 0
else:
det_index = circulant(np.arange(4))[:, :3]
dets_ind = np.linalg.det(i_pts[..., det_index, :])
cclock = np.all(dets_ind > 0, axis=-1)
clock = np.all(dets_ind < 0, axis=-1)
ix = np.nonzero(index)[0]
orientation[ix[cclock]] = 1
orientation[ix[clock]] = -1
return orientation

def orient_faces(self):
"""Orient faces of tiling in counterclockwise order with
respect (0,0,0)"""
for face, o in zip(self.faces, self.face_orientation):
if o == -1:
face.reverse()

@property
def vertex_adjacency(self):
return NotImplemented

@property
def face_adjacency(self):
return NotImplemented

@property
def vertex_face_incidence(self):
return NotImplemented

def faces_by_edge(self, edges):
return NotImplemented

def edges_from_facelist(faces):
"""Given a list of faces, returns a list of edges."""
edges = set()
Expand Down
18 changes: 18 additions & 0 deletions bin/face_orient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Orient faces of a tiling in counterclockwise order
"""
import argparse
from antitile import tiling, off

if __name__ == "__main__":
parser = argparse.ArgumentParser(description=
"Subdivide a tiling or polyhedron")
parser.add_argument("filename", help="Input file")
args = parser.parse_args()
filename = args.filename
vertices, faces, fc, e, ec, v, vc = off.load_off(filename)
base = tiling.Tiling(vertices, faces)
base.orient_faces()
print(off.write_off(base.vertices, base.faces))
16 changes: 8 additions & 8 deletions bin/subtile.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@
from antitile import off, tiling, breakdown, projection

def subdiv(base, freq={'t': (2,0), 'q': (2,0)}, proj='flat'):
bkdns = {shape: breakdown.Breakdown(*freq, shape)
bkdns = {shape: breakdown.Breakdown(*freq, shape)
for (shape, freq) in freq.items()}
newverts = []
base.orient_faces()
for face in base.faces:
face_n = len(face)
face_pts = base.vertices[face]
if face_n > 4:
raise ValueError("Tiling contains at least one face with more than"
" 4 sides. Try triangulating that face first.")
" 4 sides. Try triangulating those faces first.")
elif face_n < 2:
#just ignore any edges or vertices that show up in the face list
continue
elif face_n == 3:
proj = projection.tri_bary
bkdn = bkdns['t']
newvert = projection.tri_bary(bkdn.coord, face_pts)
elif face_n == 4:
proj = projection.square_to_quad
bkdn = bkdns['q']
face_pts = base.vertices[face]
newvert = proj(bkdn.coord, face_pts)
bkdn = bkdns['q']
newvert = projection.square_to_quad(bkdn.coord[:, np.newaxis], face_pts)
newverts.append(newvert)
return np.concatenate(newverts, axis=0)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description=
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
'Topic :: Multimedia :: Graphics :: 3D Modeling',
'Topic :: Scientific/Engineering :: Mathematics'
],
scripts = ['bin/view_off.py', 'bin/balloon.py', 'bin/subtile.py'],
scripts = ['bin/view_off.py', 'bin/balloon.py', 'bin/subtile.py',
'bin/face_orient.py'],
include_package_data=True,
zip_safe=True,
test_suite='tests')

0 comments on commit 0a16001

Please sign in to comment.