Re: covering a sphere with patches
Kadir Haldenbilen <khaldenbilen-/[email protected]> Wed, 18 Apr 2012 02:37:48 -0700 (PDT)
| Newsgroups | gmane.comp.python.visualpython.user |
|---|---|
| Message-ID | <[email protected]> |
Here is a sample code to create a Geodesic Dome, together with some "platonic solids", just in case. I imported this script from Blender and adapted it to VPython as is. So, do not ask about math/geom. Kadir ________________________________ ------------------------------------------------------------------------------ Better than sec? Nothing is better than sec when it comes to monitoring Big Data applications. Try Boundary one-second resolution app monitoring today. Free. http://p.sf.net/sfu/Boundary-dev2dev _______________________________________________ Visualpython-users mailing list Visualpython-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/visualpython-users
Vdome.py
(application/octet-stream, 10.4 KB)
from visual import *
import math
from math import *
#
# general vector and quaternion functions
#
def add(v0, v1):
return [ v1[0] + v0[0], v1[1] + v0[1], v1[2] + v0[2] ]
def sub(v0, v1):
return [ v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2] ]
def mag(v):
return math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] )
def mul(scalar, v):
return [ scalar * v[0], scalar * v[1], scalar * v[2] ]
def normalize(v):
return mul(1/mag(v), v)
def cross(v0, v1):
return [ v0[1]*v1[2] - v0[2]*v1[1], v0[2]*v1[0] - v0[0]*v1[2], v0[0]*v1[1] - v0[1]*v1[0] ]
def dot(v0, v1):
return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]
def createQuaternionFromAngleAndAxis(angle, axis):
angle = angle / 2
axis = mul(math.sin(angle), normalize(axis))
return axis + [ math.cos(angle) ]
# return a quarternion, which represents the rotation which is needed
# to get the target vector, if the source vector is rotated
def angleBetween(source, target):
# the following code is based on an article by Stan Melax in Game Programming Gems,
# see this book: http://books.google.de/books?id=hiBFUv_FT0wC&pg=PA214
# first calculate a quarternion, which represents the rotation between v0 and v1
v0 = normalize(source)
v1 = normalize(target)
d = dot(v0, v1)
# special case: if the dot product is near -1, v0 and v1 are pointing
# in opposite directions and we can use any perpendicular axis and 180 degree
if d < 1e-5 - 1:
axis = cross([0, 1, 0], v0)
if mag(axis) < 1e-5:
axis = cross([0, 0, 1], v0)
return createQuaternionFromAngleAndAxis(pi, axis)
else:
# normal case
s = sqrt((1+d) * 2)
c = cross(v0, v1)
qx = c[0] / s
qy = c[1] / s
qz = c[2] / s
qw = s / 2
return [ qx, qy, qz, qw ]
# return a new vector, which is the vector v rotated by the quaternion q
def rotate(q, v):
rw = -q[0]*v[0]-q[1]*v[1]-q[2]*v[2]
rx = q[3]*v[0]+q[1]*v[2]-q[2]*v[1]
ry = q[3]*v[1]+q[2]*v[0]-q[0]*v[2]
rz = q[3]*v[2]+q[0]*v[1]-q[1]*v[0]
return [
-rw*q[0]+rx*q[3]-ry*q[2]+rz*q[1],
-rw*q[1]+ry*q[3]-rz*q[0]+rx*q[2],
-rw*q[2]+rz*q[3]-rx*q[1]+ry*q[0] ]
# scale a vector
# v: vector
# length: destination length
def scaleToLength(v, length):
return mul(length / mag(v), v)
#
# general mesh functions
#
# translate all points of the specified array
def translateArray(coords, v):
coords2 = []
for i in range(len(coords)):
coords2 = coords2 + [ add(v, coords[i]) ]
return coords2
# scale all points of the specified array to the specified length
def scaleArrayToLength(coords, length):
coords2 = []
for i in range(len(coords)):
coords2 = coords2 + [ scaleToLength(coords[i], length) ]
return coords2
# triangulate a mesh, if a polygon has more than 4 vertices (convex polygons, only)
def triangulate(coords, faces):
faces2 = []
for i in range(len(faces)):
face = faces[i]
if len(face) > 4:
center = [0, 0, 0]
for j in range(len(face)):
coord = coords[face[j]]
center[0] = center[0] + coord[0]
center[1] = center[1] + coord[1]
center[2] = center[2] + coord[2]
center[0] = center[0] / len(face)
center[1] = center[1] / len(face)
center[2] = center[2] / len(face)
centerIndex = len(coords)
coords = coords + [center]
for j in range(len(face)):
oldIndex1 = face[j]
if j == len(face) - 1:
oldIndex2 = face[0]
else:
oldIndex2 = face[j + 1]
faces2 = faces2 + [[oldIndex1, oldIndex2, centerIndex]]
else:
faces2 = faces2 + [face]
return coords, faces2
# rotate all points of the specified array
def rotateArray(coords, q):
coords2 = []
for i in range(len(coords)):
coords2 = coords2 + [ rotate(q, coords[i]) ]
return coords2
# subdivide a polyhedron
# coords: coordinates
# faces: faces of the polyhedron (must be triangles)
# radius: radius of the sphere in which the polyhedron is inscribed
def subdivide(coords, faces, radius):
lineHash = {}
coords2 = coords
faces2 = []
for i in range(len(faces)):
# get face coordinate indices
face = faces[i]
iv0 = face[0]
iv1 = face[1]
iv2 = face[2]
# get face coordinates
v0 = coords[iv0]
v1 = coords[iv1]
v2 = coords[iv2]
# build line keys
if iv0 < iv1:
l1 = iv0 * len(coords) + iv1
else:
l1 = iv1 * len(coords) + iv0
if iv1 < iv2:
l2 = iv1 * len(coords) + iv2
else:
l2 = iv2 * len(coords) + iv1
if iv0 < iv2:
l3 = iv0 * len(coords) + iv2
else:
l3 = iv2 * len(coords) + iv0
# try to find mid point index of a line in line hashtable
if l1 in lineHash:
iv0v1 = lineHash[l1]
else:
v0v1 = scaleToLength(mul(0.5, add(v0, v1)), radius)
iv0v1 = len(coords2)
lineHash[l1] = iv0v1
coords2 = coords2 + [ v0v1 ]
if l2 in lineHash:
iv1v2 = lineHash[l2]
else:
v1v2 = scaleToLength(mul(0.5, add(v1, v2)), radius)
iv1v2 = len(coords2)
lineHash[l2] = iv1v2
coords2 = coords2 + [ v1v2 ]
if l3 in lineHash:
iv2v0 = lineHash[l3]
else:
v2v0 = scaleToLength(mul(0.5, add(v2, v0)), radius)
iv2v0 = len(coords2)
lineHash[l3] = iv2v0
coords2 = coords2 + [ v2v0 ]
# create new faces
faces2 = faces2 + [ [ iv0, iv0v1, iv2v0 ] ]
faces2 = faces2 + [ [ iv1, iv1v2, iv0v1 ] ]
faces2 = faces2 + [ [ iv2, iv2v0, iv1v2] ]
faces2 = faces2 + [ [ iv0v1, iv1v2, iv2v0] ]
return coords2, faces2
# keep all polygons with z coordinate less than the limit parameter
def half(coords, faces, limit):
coords2 = []
faces2 = []
coordsHash = {}
for i in range(len(faces)):
face = faces[i]
iv0 = face[0]
iv1 = face[1]
iv2 = face[2]
v0 = coords[iv0]
v1 = coords[iv1]
v2 = coords[iv2]
if v0[2] < limit or v1[2] < limit or v2[2] < limit:
# map old coordinates to new coordinates to avoid duplicates
if iv0 in coordsHash:
iv0 = coordsHash[iv0]
else:
coordsHash[iv0] = len(coords2)
iv0 = len(coords2)
coords2 = coords2 + [ v0 ]
if iv1 in coordsHash:
iv1 = coordsHash[iv1]
else:
coordsHash[iv1] = len(coords2)
iv1 = len(coords2)
coords2 = coords2 + [ v1 ]
if iv2 in coordsHash:
iv2 = coordsHash[iv2]
else:
coordsHash[iv2] = len(coords2)
iv2 = len(coords2)
coords2 = coords2 + [ v2 ]
faces2 = faces2 + [ [ iv0, iv1, iv2 ] ]
return coords2, faces2
#
# platonic solids
# coordinates and faces from http://people.sc.fsu.edu/~burkardt/c_src/plato_ply/plato_ply.c
#
def tetrahedronData():
coords = [ [-1, -1, -1], [1, 1, -1], [1, -1, 1], [-1, 1, 1] ]
faces = [ [3, 2, 1], [2, 0, 1], [0, 2, 3], [3, 1, 0] ]
return coords, faces
def octahedronData():
coords = [ [1, 0, 0], [0, -1, 0], [-1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, -1] ]
faces = [ [1, 0, 4], [2, 1, 4], [3, 2, 4], [0, 3, 4], [0, 1, 5], [1, 2, 5], [2, 3, 5], [3, 0, 5] ]
return coords, faces
def cubeData():
coords = [ [-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1], [-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1] ]
faces = [ [3, 2, 1, 0], [6, 7, 4, 5], [5, 1, 2, 6], [0, 4, 7, 3], [6, 2, 3, 7], [4, 0, 1, 5] ]
return coords, faces
def icosahedronData():
a = (sqrt(5) + 1) / 2
b = 1
len = sqrt(a*a + b*b)
a = a / len
b = b / len
coords = [ [0, -b, a], [a, 0, b], [a, 0, -b], [-a, 0, -b], [-a, 0, b], [-b, a, 0], [b, a, 0], [b, -a, 0], [-b, -a, 0], [0, -b, -a], [0, b, -a], [0, b, a] ]
faces = [ [1, 2, 6], [1, 7, 2], [3, 4, 5], [4, 3, 8], [6, 5, 11], [5, 6, 10], [9, 10, 2], [10, 9, 3], [7, 8, 9], [8, 7, 0], [11, 0, 1], [0, 11, 4], [6, 2, 10], [1, 6, 11], [3, 5, 10], [5, 4, 11], [2, 7, 9], [7, 1, 0], [3, 9, 8], [4, 8, 0] ]
return coords, faces
def dodecahedronData():
a = 1 + (1 + sqrt(5)) / 2
b = 1
c = (1 + sqrt(5)) / 2
len = sqrt(a*a + b*b)
a = a / len
b = b / len
c = c / len
coords = [ [-c, -c, c], [a, b, 0], [a, -b, 0], [-a, b, 0], [-a, -b, 0], [0, a, b], [0, a, -b], [b, 0, -a], [-b, 0, -a], [0, -a, -b], [0, -a, b], [b, 0, a], [-b, 0, a], [c, c, -c], [c, c, c], [-c, c, -c], [-c, c, c], [c, -c, -c], [c, -c, c], [-c, -c, -c] ]
faces = [ [14, 11, 18, 2, 1], [2, 17, 7, 13, 1], [15, 8, 19, 4, 3], [4, 0, 12, 16, 3], [16, 5, 6, 15, 3], [13, 6, 5, 14, 1], [18, 10, 9, 17, 2], [19, 9, 10, 0, 4], [17, 9, 19, 8, 7], [13, 7, 8, 15, 6], [16, 12, 11, 14, 5], [18, 11, 12, 0, 10] ]
return coords, faces
# create a icosphere
# radius: radius of the sphere
# subdivisions: number of triangle subdivisions
def createIcosphere(radius, subdivisions):
coords, faces = icosahedronData()
q = angleBetween(coords[0], [0, 0, 1])
coords = rotateArray(coords, q)
coords = scaleArrayToLength(coords, radius)
for i in range(subdivisions):
coords, faces = subdivide(coords, faces, radius)
return coords, faces
def VDrawMesh(coords, faces, color):
lc = len(coords)
carray = array(lc*[lc*[0]])
#print carray
for coord in coords:
sphere(pos=coord, radius=0.1,color=(1,0,0))
for face in faces:
lp = len(face)
for i in range(-1,lp):
p1 = face[i]
j = i+1
if j == lp: j = -1
p2 = face[j]
if carray[p1][p2] == 1 or carray[p2][p1] == 1: continue
wire = cylinder(pos=coords[p1], axis=vector(coords[p2])-vector(coords[p1]),
radius=0.05, color=color)
carray[p1][p2] = 1
carray[p2][p1] = 1
# create platonic solids
solidRadius = 2
coords, faces = cubeData()
coords = scaleArrayToLength(coords, solidRadius)
coords = translateArray(coords, [ -5, 0, 0 ])
vcube = VDrawMesh(coords, faces, (0,0,1))
coords, faces = octahedronData()
coords = scaleArrayToLength(coords, solidRadius)
coords = translateArray(coords, [ 0, 0, 0 ])
voctahedron = VDrawMesh(coords, faces, (0,1,0))
coords, faces = dodecahedronData()
coords = scaleArrayToLength(coords, solidRadius)
coords = translateArray(coords, [ 5, 0, 0 ])
vdodecahedron = VDrawMesh(coords, faces, (1,1,1))
coords, faces = icosahedronData()
coords = scaleArrayToLength(coords, solidRadius)
coords = translateArray(coords, [ 0, 5, 0 ])
vicosahedron = VDrawMesh(coords, faces, (0,1,1))
coords, faces = tetrahedronData()
coords = scaleArrayToLength(coords, solidRadius)
coords = translateArray(coords, [ 5, 5, 0 ])
vtetrahedron = VDrawMesh(coords, faces, (1,0,1))
# create geodesic dome
domeRadius = 7
domeSubdivisions = 3
coords, faces = createIcosphere(domeRadius, domeSubdivisions)
vfull = VDrawMesh(coords, faces, (1,1,0))