Last active
September 26, 2017 20:50
-
-
Save davepkennedy/3cbd098530fcab67017464587b7a4bf4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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