9
Output coordinates of the vertices of a cube. Then, output a list of twelve triangles that will cover the cube, each triangle being a list of three vertex-indexes, consistently oriented. Output must be an ASCII string of distinct decimal numbers. This golf has no input. Winner is the fewest characters, where the character set is Unicode.
For an example, consider a 1x1x1 cube cornered at 0,0,0. The eight vertices of the cube can be described by the following xyz coordinates on a 3d Cartesian grid:
x y z = (0,0,1) (1,0,1) (1,1,1) (0,1,1) (0,0,0) (1,0,0) (1,1,0) (0,1,0)
Each vertex can be given an index: x y z->index: 0 0 1->0, 1 0 1->1, 1 1 1->2, 0 1 1->3, 0 0 0->4, 1 0 0->5, 1 1 0->6, 0 1 0->7
Now consider the top face, vertexes indexed zero to three. The two covering triangles can be described by three indices each:
[0,1,2] [2,3,0]
Here is a picture of this top face, viewed from above the cube:
3_____2
| /|
| / |
| / |
| / |
0_____1
And here is a view from an angle.
3____2
/ __-/|
0/_`__1 |
| | /6
|____|/
4 5
Note the orientation, or 'winding', of both of these triangles is 'counterclockwise' when viewed from 'outside' the cube directly looking at the face in question (imagine visiting each vertex as listed, it goes counterclockwise). Now imagine this done for all six sides of the cube.
vertices: (0,0,1) (1,0,1) (1,1,1) (0,1,1) (0,0,0) (1,0,0) (1,1,0) (0,1,0)
triangles as indices: [0,1,2], [2,3,0], [6,5,4], [4,7,6],
[5,2,1], [2,5,6], [0,3,4], [4,3,7], [2,6,3], [3,6,7], [0,4,1], [1,4,5]
You can output any size of cube located at any coordinates. You can number and order the vertex coordinates however you wish. Indices can be 0 based or 1 based. The triangle's orientation can be either clockwise or counterclockwise when viewed from outside the cube as long as it is consistent for all triangles.
The output can be formatted however you wish, as long as each ASCII decimal number is separated by at least one non-numeric ASCII character. For instance the above example could also be output as follows:
0 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0
0 1 2 2 3 0 6 5 4 4 7 6 5 2 1 2 5 6 0 3 4 4 3 7 2 6 3 3 6 7 0 4 1 1 4 5
This golf is inspired by various 3d graphics systems and formats, including OpenGL, OBJ, OFF, AMF, CGAL, etc. This golf is similar to the golf by Calvin's Hobbies named Output a Face on a Numbered Cube , the big difference being you need to output the x y z coordinates of the vertices yourself and output triangle indices. Thanks for reading.
Per user inspiration here is a "helper" validation program in python2 (non-golfy) that will print 'ok' or 'not ok' for test output data in variables vertstr and idxstr. It doesn't work perfectly... but it can catch some errors.
Edit: fixed typo in example and bugs in validation code.
#vertstr = '0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1' #idxstr = '1 2 0 2 1 3 7 5 6 4 6 5 2 4 0 4 2 6 7 3 5 1 5 3 4 1 0 1 4 5 7 6 3 2 3 6' vertstr = '0 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0' idxstr = '0 1 2 2 3 0 6 5 4 4 7 6 5 2 1 2 5 6 0 3 4 4 3 7 2 6 3 3 6 7 0 4 1 1 4 5' class Vector: def __init__(self,v): self.x,self.y,self.z=v[0],v[1],v[2] def __add__(self,v): return Vector([self.x+v.x,self.y+v.y,self.z+v.z]) def __sub__(self,v): return Vector([self.x-v.x,self.y-v.y,self.z-v.z]) def __str__(self): return str(self.x)+','+str(self.y)+','+str(self.z) def cross(v1,v2): x = v1.y*v2.z-v2.y*v1.z z = v1.x*v2.y-v2.x*v1.y y = v1.z*v2.x-v2.z*v1.x return Vector([x,y,z]) # http://mathforum.org/library/drmath/view/55343.html & http://sympy.org def winding(v1,v2,v3,obs): x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4=v1.x,v1.y,v1.z,v2.x,v2.y,v2.z,v3.x,v3.y,v3.z,obs.x,obs.y,obs.z d = x1*(y2*z3 - y2*z4 - y3*z2 + y3*z4 + y4*z2 - y4*z3) d = d + y1*(-x2*z3 + x2*z4 + x3*z2 - x3*z4 - x4*z2 + x4*z3) d = d + z1*(x2*y3 - x2*y4 - x3*y2 + x3*y4 + x4*y2 - x4*y3) d = d - x2*y3*z4 + x2*y4*z3 + x3*y2*z4 - x3*y4*z2 - x4*y2*z3 + x4*y3*z2 return d def normals(v1,v2,v3): va = v2-v1 vb = v3-v2 vc = v1-v3 n1 = cross(va,vb) n2 = cross(vb,vc) n3 = cross(vc,va) return [n1,n2,n3] def triplify(str): nums,triples=[],[] for num in str.split(' '): nums+=[int(num)] for i in range(0,len(nums),3): triples += [[nums[i],nums[i+1],nums[i+2]]] return triples verts = triplify(vertstr) indices = triplify(idxstr) nsum = Vector([0,0,0]) windsum = 0 xs,ys,zs=[],[],[] for v in verts: xs+=[v[0]] ys+=[v[1]] zs+=[v[2]] #print xs,ys,zs,len(xs) center=Vector([float(sum(xs))/len(xs),float(sum(ys))/len(ys),float(sum(zs))/len(zs)]) for triangle in indices: v1 = Vector(verts[triangle[0]]) v2 = Vector(verts[triangle[1]]) v3 = Vector(verts[triangle[2]]) norms = normals(v1,v2,v3) print v1,v2,v3,norms[0],norms[1],norms[2] for n in norms: nsum += n w = winding(v1,v2,v3,center) print 'winding',w if w<0: windsum-=1 elif w>0: windsum+=1 if abs(windsum)==12: print 'winding ok' else: print 'winding not ok' if (nsum.x==0 and nsum.y==0 and nsum.z==0): print 'normal sum ok' else: print 'normal sum not ok'
1It's clear from the example, but just to make it perfectly unambiguous, you may want to mention that the indices are 0-based. This is not a given, since at least one of the formats you list as example (OBJ) uses 1-based indices. – Reto Koradi – 2015-10-19T16:37:33.030
That will work as well. I think one difficulty with this challenge is that it's moderately painful to verify the correctness of the output. You pretty much have to sketch a cube with the chose vertex ordering on a piece of paper, and manually validate all 12 triangles. Well, you could write a validation program. That might actually be another challenge idea... more difficult than this one, I think. – Reto Koradi – 2015-10-19T16:54:23.140
i really like that idea of another golf for a validator. i updated the example to give a full dataset. thanks again. – don bright – 2015-10-19T17:22:37.310
ok I added a very quick and dirty validation program that takes cross products of each pair of vectors in each triangle, adds them all, and if 0 says 'ok'. – don bright – 2015-10-20T00:20:00.173