Skip to content

Instantly share code, notes, and snippets.

@davepkennedy
Last active September 26, 2017 20:50
Show Gist options
  • Save davepkennedy/3cbd098530fcab67017464587b7a4bf4 to your computer and use it in GitHub Desktop.
Save davepkennedy/3cbd098530fcab67017464587b7a4bf4 to your computer and use it in GitHub Desktop.
public class IcosahedronBuilder extends PolygonBuilder {
@Override
protected void buildVertices() {
// create 12 vertices of a icosahedron
float t = (float)((1.0 + Math.sqrt(5.0)) / 2.0);
addVertex(new Vec3d(-1, t, 0));
addVertex(new Vec3d( 1, t, 0));
addVertex(new Vec3d(-1, -t, 0));
addVertex(new Vec3d( 1, -t, 0));
addVertex(new Vec3d( 0, -1, t));
addVertex(new Vec3d( 0, 1, t));
addVertex(new Vec3d( 0, -1, -t));
addVertex(new Vec3d( 0, 1, -t));
addVertex(new Vec3d( t, 0, -1));
addVertex(new Vec3d( t, 0, 1));
addVertex(new Vec3d(-t, 0, -1));
addVertex(new Vec3d(-t, 0, 1));
}
@Override
protected void buildIndices() {
// create 20 triangles of the icosahedron
// 5 faces around point 0
addFace(new TriangleIndices(0, 11, 5));
addFace(new TriangleIndices(0, 5, 1));
addFace(new TriangleIndices(0, 1, 7));
addFace(new TriangleIndices(0, 7, 10));
addFace(new TriangleIndices(0, 10, 11));
// 5 adjacent faces
addFace(new TriangleIndices(1, 5, 9));
addFace(new TriangleIndices(5, 11, 4));
addFace(new TriangleIndices(11, 10, 2));
addFace(new TriangleIndices(10, 7, 6));
addFace(new TriangleIndices(7, 1, 8));
// 5 faces around point 3
addFace(new TriangleIndices(3, 9, 4));
addFace(new TriangleIndices(3, 4, 2));
addFace(new TriangleIndices(3, 2, 6));
addFace(new TriangleIndices(3, 6, 8));
addFace(new TriangleIndices(3, 8, 9));
// 5 adjacent faces
addFace(new TriangleIndices(4, 9, 5));
addFace(new TriangleIndices(2, 4, 11));
addFace(new TriangleIndices(6, 2, 10));
addFace(new TriangleIndices(8, 6, 7));
addFace(new TriangleIndices(9, 8, 1));
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class PolygonBuilder {
int index;
private List<Vec3d> positions = new ArrayList<>();
private List<TriangleIndices> faces = new ArrayList<>();
private Map<Long,Integer> middlePointIndexCache = new HashMap<>();
int addVertex(Vec3d p) {
positions.add(p.normalize());
return index++;
}
void addFace (TriangleIndices indices) {
faces.add(indices);
}
protected int getPointBetween(int p1, int p2) {
// first check if we have it already
boolean firstIsSmaller = p1 < p2;
long smallerIndex = firstIsSmaller ? p1 : p2;
long greaterIndex = firstIsSmaller ? p2 : p1;
long key = (smallerIndex << 32) + greaterIndex;
if (middlePointIndexCache.containsKey(key)) {
return middlePointIndexCache.get(key);
}
// not in cache, calculate it
Vec3d point1 = positions.get(p1);
Vec3d point2 = positions.get(p2);
Vec3d middle = new Vec3d ((point1.getX() + point2.getX()) / 2.0f,
(point1.getY() + point2.getY()) / 2.0f,
(point1.getZ() + point2.getZ()) / 2.0f);
// add vertex makes sure point is on unit sphere
int i = addVertex(middle);
// store it, return index
middlePointIndexCache.put(key, i);
return i;
}
public void build(int recursion) {
buildVertices();
buildIndices();
refine(recursion);
}
protected abstract void buildVertices();
protected abstract void buildIndices();
void refine(int recursionLevel) {
for (int i = 0; i < recursionLevel; i++) {
List<TriangleIndices> faces2 = new ArrayList<>();
for (TriangleIndices tri : faces) {
// replace triangle by 4 triangles
int a = getPointBetween(tri.getA(), tri.getB());
int b = getPointBetween(tri.getB(), tri.getC());
int c = getPointBetween(tri.getC(), tri.getA());
faces2.add(new TriangleIndices(tri.getA(), a, c));
faces2.add(new TriangleIndices(tri.getB(), b, a));
faces2.add(new TriangleIndices(tri.getC(), c, b));
faces2.add(new TriangleIndices(a, b, c));
}
faces = faces2;
}
}
public List<Vec3d> getVertices() {
return positions;
}
public List<TriangleIndices> getFaces() {
return faces;
}
}
public class Vec3d {
private final float x;
private final float y;
private final float z;
public Vec3d(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
Vec3d normalize() {
return scale(invLen());
}
float dot(Vec3d a) {
return (x * a.x) + (y * a.y) + (z * a.z);
}
Vec3d scale(float s) {
return new Vec3d(
x * s,
y * s,
z * s);
}
float sqLen() {
return dot(this);
}
float len() {
return (float) Math.sqrt(sqLen());
}
float invLen() {
return (1.f / len());
}
public Position toPosition(float R) {
return new Position(
(float) Math.toDegrees(Math.asin(z / R)),
(float) Math.toDegrees(Math.atan2(y, x)));
}
public Vec3d subtract(Vec3d other) {
return new Vec3d(
x - other.x,
y - other.y,
z - other.z);
}
public static Vec3d crossVector(Vec3d a, Vec3d b) {
return new Vec3d(
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x);
}
private static boolean sameSide(Vec3d p1, Vec3d p2, Vec3d a, Vec3d b) {
Vec3d cp1 = crossVector(b.subtract(a), p1.subtract(a));
Vec3d cp2 = crossVector(b.subtract(a), p2.subtract(a));
return (cp1.dot(cp2) >= 0);
}
public static boolean pointInTriangle(Vec3d p, Vec3d a, Vec3d b, Vec3d c) {
return sameSide(p, a, b, c) && sameSide(p,b,a,c) && sameSide(p, c, a, b);
}
@Override
public String toString() {
return "Vec3d{" +
"x=" + x +
", y=" + y +
", z=" + z +
'}';
}
public double distance (Vec3d a, Vec3d b) {
float dx = a.x - b.x;
float dy = a.y - b.y;
float dz = a.z - b.z;
return Math.sqrt ((dx*dx)+(dy*dy)+(dz*dz));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment