📄 subdivisionbutterfly.java
字号:
Vector vert = new Vector(bufferElementSize);
vert.populateFromBuffer(vb, vertexIndex);
//c = 1 - (1/((double)k-1))*Math.sin(theta)*Math.sin((double)i*theta) / (1d-Math.cos(theta));
c = 1d - (Math.sin(theta)*Math.sin((double)i*theta))/((double)k*(1d-Math.cos(theta)));
vert.multLocal((float)c);
result.addLocal(vert);
for (j=0; j < valence; j++) {
vert.populateFromBuffer(vb, v[j]);
if (j == 0 || j == (valence-1)) {
//c = 1d/4d * Math.cos((double)i*theta) - (1d/4d*(double)(k-1))*Math.sin(2d*theta)*Math.sin(2d*(double)i*theta) / (Math.cos(theta)-Math.cos(2d*theta));
c = 1d/4d * Math.cos((double)i*theta) - ( Math.sin(2d*theta)*Math.sin(2d*(double)i*theta) )/(4d*(double)k*(Math.cos(theta) - Math.cos(2d*theta)));
if (j == (valence-1)) c = -c;
} else {
//c = (1d/(double)k)*(Math.sin((double)i*theta)*Math.sin((double)j*theta) + (1d/2d) * Math.sin(2d*(double)i*theta)*Math.sin(2d*(double)j*theta));
c = 1d/(double)k * (Math.sin((double)i*theta)*Math.sin((double)j*theta) + (1d/2d)*Math.sin(2d*(double)i*theta)*Math.sin(2d*(double)j*theta));
}
vert.multLocal((float)c);
result.addLocal(vert);
}
return result;
}
private static Vector regularCreaseCrease(Edge edge, FloatBuffer vb, int bufferElementSize, ArrayList<Edge>[] vertexEdgeMap) {
Vector result = new Vector(bufferElementSize);
Vector vert;
boolean rule1 = false;
ArrayList<Edge> edges0, edges1, tempEdges;
edges0 = vertexEdgeMap[edge.vertexIndex[0]];
edges1 = vertexEdgeMap[edge.vertexIndex[1]];
// If we are the base of a triangle in a corner
// (i.e. if the two vertices are joined by a third crease vertex)
// We do crease-crease rule 1, else we do 4-point crease rule (which also approximates crease-crease rule 2, for now)
int vertex0 = -1, vertex1 = -1;
if (edges0.get(0).otherVertex(edge.vertexIndex[0]) == edges1.get(3).otherVertex(edge.vertexIndex[1])) {
// Rule 1
rule1 = true;
vertex0 = edge.vertexIndex[0]; // corner vertex is the most clockwise edge
vertex1 = edge.vertexIndex[1]; // corner vertex is the most counter-clockwise edge
} else if (edges0.get(3).otherVertex(edge.vertexIndex[0]) == edges1.get(0).otherVertex(edge.vertexIndex[1])) {
// Rule 2
rule1 = true;
vertex0 = edge.vertexIndex[1]; // corner vertex is the most clockwise edge
vertex1 = edge.vertexIndex[0]; // corner vertex is the most counter-clockwise edge
// Flip also the edgelists
tempEdges = edges1; edges1 = edges0; edges0 = tempEdges; tempEdges = null;
} else {
// 4-point regular butterfly rule
rule1 = false;
}
if (rule1) {
// edges0.get(0) is the corner vertex, also the most clockwise edge
// edges1.get(3) is the corner vertex, also the most counter-clockwise edge
// Do the first vertex of the splitting edge
vert = new Vector(bufferElementSize);
vert.populateFromBuffer(vb, vertex0);
vert.multLocal(1f/2f);
result.addLocal(vert);
vert.populateFromBuffer(vb, edges0.get(2).otherVertex(vertex0));
vert.multLocal(1f/4f);
result.addLocal(vert);
vert.populateFromBuffer(vb, edges0.get(3).otherVertex(vertex0));
vert.multLocal(-1f/8f);
result.addLocal(vert);
// Do the second vertex of the splitting edge
vert.populateFromBuffer(vb, vertex1);
vert.multLocal(1f/2f);
result.addLocal(vert);
vert.populateFromBuffer(vb, edges1.get(0).otherVertex(vertex1));
vert.multLocal(-1f/8f);
result.addLocal(vert);
// finished Crease-Crease Rule 1
} else {
// 4-point regular butterfly rule ( +---+-*-+---+ )
if (edges0.get(0).equals(edge)) {
vertex0 = edge.vertexIndex[1];
vertex1 = edge.vertexIndex[0];
// Flip also the edgelists
tempEdges = edges1; edges1 = edges0; edges0 = tempEdges; tempEdges = null;
} else {
vertex0 = edge.vertexIndex[0];
vertex1 = edge.vertexIndex[1];
}
vert = new Vector(bufferElementSize);
// Do the first vertex of the splitting edge
vert.populateFromBuffer(vb, vertex0);
vert.multLocal(9f/16f);
result.addLocal(vert);
vert.populateFromBuffer(vb, edges0.get(0).otherVertex(vertex0));
vert.multLocal(-1f/16f);
result.addLocal(vert);
// Do the second vertex of the splitting edge
vert.populateFromBuffer(vb, vertex1);
vert.multLocal(9f/16f);
result.addLocal(vert);
vert.populateFromBuffer(vb, edges1.get(3).otherVertex(vertex1));
vert.multLocal(-1f/16f);
result.addLocal(vert);
// finished 4-point regular butterfly rule
}
return result;
}
private static Vector regularInteriorCrease(Edge edge, int vertexIndex, FloatBuffer vb, int bufferElementSize, ArrayList<Edge> interiorEdges, ArrayList<Edge> creaseEdges) {
Vector result = new Vector(bufferElementSize);
Vector vert;
int v[] = new int[6];
// First take care of the interior vertex
// Fast forward the edgeMap to the edge we're starting at
Iterator<Edge> it = interiorEdges.iterator();
while (it.hasNext() && (!edge.equals(it.next())));
// circle around the interior vertex counter clock wise and find all vertices
for (int i=0 ; i<6 ; i++) {
if (!it.hasNext())
it = interiorEdges.iterator();
v[i] = it.next().otherVertex(vertexIndex);
}
// v[0] is the first vertex counted CCW from the edge to split
vert = new Vector(bufferElementSize);
vert.populateFromBuffer(vb, vertexIndex);
vert.multLocal(5f/8f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[0]);
vert.multLocal(3f/16f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[1]);
vert.multLocal(-1f/8f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[3]);
vert.multLocal(-1f/16f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[4]);
vert.multLocal(1f/16f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[5]);
vert.multLocal(3f/8f);
result.addLocal(vert);
// now the crease/boundary vertex
// Since it's a crease-edge we know that the first index in the map is the edge
// that is the most clock-wise
vert.populateFromBuffer(vb, creaseEdges.get(0).otherVertex(edge.otherVertex(vertexIndex)));
vert.multLocal(-1f/16f);
result.addLocal(vert);
return result;
}
private static Vector extraordinaryInterior(Edge edge, int vertexIndex, FloatBuffer vb, int bufferElementSize, ArrayList<Edge> edges, ArrayList<Triangle> triangles) {
Vector result = new Vector(bufferElementSize);
int valence = edges.size();
int v[] = new int[valence];
Edge tempEdge = null;
// spola fram i edgeMappen till edgen a1-a2
Iterator<Edge> it = edges.iterator();
while (it.hasNext() && (!edge.equals(tempEdge = it.next())));
// circle around the vertex counter clock-wise and find all vertices
for (int i=0 ; i<valence ; i++) {
v[i] = tempEdge.otherVertex(vertexIndex);
if (!it.hasNext())
it = edges.iterator();
tempEdge = it.next();
}
Vector vert = new Vector(bufferElementSize);
if (valence == 3) {
vert.populateFromBuffer(vb, vertexIndex);
vert.multLocal(3f/4f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[0]);
vert.multLocal(5f/12f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[1]);
vert.multLocal(-(1f/12f));
result.addLocal(vert);
vert.populateFromBuffer(vb, v[2]);
vert.multLocal(-(1f/12f));
result.addLocal(vert);
} else if (valence == 4) {
vert.populateFromBuffer(vb, vertexIndex);
vert.multLocal(3f/4f);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[0]);
vert.multLocal(3f/8f);
result.addLocal(vert);
//vert.populateFromBuffer(vb, v[1]);
//vert.multLocal(0f);
//result.addLocal(vert);
vert.populateFromBuffer(vb, v[2]);
vert.multLocal(-1f/8f);
result.addLocal(vert);
//vert.populateFromBuffer(vb, v[3]);
//vert.multLocal(0f);
//result.addLocal(vert);
} else {
vert.populateFromBuffer(vb, vertexIndex);
vert.multLocal(3f/4f);
result.addLocal(vert);
int n;
n = valence;
for (int j=0; j<n; j++) {
vert.populateFromBuffer(vb, v[j]);
vert.multLocal((float)( 1f/4f +
Math.cos(2f*Math.PI*(float)j/(float)n) +
1f/2f * Math.cos(4f*Math.PI*(float)j/(float)n)));
vert.multLocal( 1f/(float)n );
result.addLocal(vert);
}
}
return result;
}
private static Vector regularButterfly(Edge edge, int vertexIndex, FloatBuffer vb, int bufferElementSize, ArrayList<Edge> edges) {
Vector result = new Vector(bufferElementSize);
int v[] = new int[6]; // v[0] = b1, 1=c1, 2=d, 3=c2, 4=b2, 5=other_a
// spola fram i edgeMappen till edgen a1-a2
Iterator<Edge> it = edges.iterator();
while (it.hasNext() && (!edge.equals(it.next())));
// circle around the vertex counter clock wise and find all vertices
for (int i=0 ; i<6 ; i++) {
if (!it.hasNext())
it = edges.iterator();
v[i] = it.next().otherVertex(vertexIndex);
}
Vector vert = new Vector(bufferElementSize);
vert.populateFromBuffer(vb, vertexIndex);
vert.multLocal(1f/2f - WEIGHT);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[0]);
vert.multLocal((1f/8f + 2*WEIGHT) / 2); // divided by 2 because it will be visited again
result.addLocal(vert);
vert.populateFromBuffer(vb, v[1]);
vert.multLocal((-1f/16f) - WEIGHT);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[2]);
vert.multLocal(WEIGHT);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[3]);
vert.multLocal((-1f/16f) - WEIGHT);
result.addLocal(vert);
vert.populateFromBuffer(vb, v[4]);
vert.multLocal((1f/8f + 2*WEIGHT) / 2); // divided by 2 because it will be visited again
result.addLocal(vert);
return result;
}
static int standard = 0;
static int regularCreaseCrease = 0;
static int regularInteriorCrease = 0;
static int extraordinaryAverage = 0;
static int extraordinaryInterior = 0;
static int extraordinaryCrease = 0;
/**
* @return A String showing some statistics on the number of types of vertices of the subdivision
*/
public static String stats() {
return "standard = " + standard + ", regularCreaseCrease = " + regularCreaseCrease + ", regularInteriorCrease = " + regularInteriorCrease + ", extraordinaryAverage = " + extraordinaryAverage + ", extraordinaryInterior = " + extraordinaryInterior + ", extraordinaryCrease = " + extraordinaryCrease;
}
}
/**
* Whether the vertex is interior or lies on a boundary
*
* @author Tobias
*/
public enum Location {
INTERIOR,
CREASE
}
/**
* Regular: Valence==6 for interior vertices, Valence==4 for boundary/crease vertices
* Extraordinary: Everything else
*
* @author Tobias
*/
public enum Valence {
REGULAR,
EXTRAORDINARY;
/**
* Calculates whether a vertex is REGULAR or EXTRAORDINARY, given the Location and valence(degree) of the vertex
* @param location
* @param valence
* @return <code>Valence.REGULAR</code> or <code>Valence.EXTRAORDINARY</code>
*/
public static Valence getValence(Location location, int valence) {
if (location == Location.INTERIOR) {
if (valence == 6) return Valence.REGULAR;
} else {
if (valence == 4) return Valence.REGULAR;
}
return Valence.EXTRAORDINARY;
}
}
/**
* Helper class to calculate which <code>Rule</code> to use
* when splitting an <code>Edge</code> whose vertices have
* <code>Location</code> and <code>Valence</code>
*
* Call: <code>VertexType.getRule(valence1, location1, valence2, location2);</code>
*
* @author Tobias
*/
public enum VertexType {
REGULAR_INTERIOR,
REGULAR_CREASE,
EXTRAORDINARY_INTERIOR,
EXTRAORDINARY_CREASE;
private static VertexType getVertexType(Valence valence, Location location) {
if (location == Location.INTERIOR)
if (valence == Valence.REGULAR) return REGULAR_INTERIOR; else return EXTRAORDINARY_INTERIOR;
else if (valence == Valence.REGULAR) return REGULAR_CREASE; else return EXTRAORDINARY_CREASE;
}
/**
* Calculates which subdivision Rule to use on an edge whose vertices have the provided Locations and
* Valances
*
* @param valence1
* @param location1
* @param valence2
* @param location2
* @return The Rule to use on an edge with the provided Locations and Valances
*/
public static Rule getRule(Valence valence1, Location location1, Valence valence2, Location location2) {
return getRule(getVertexType(valence1, location1), getVertexType(valence2, location2));
}
private static Rule getRule(VertexType type1, VertexType type2) {
if (isSame(type1,type2,REGULAR_INTERIOR,REGULAR_INTERIOR))
return Rule.STANDARD;
if (isSame(type1,type2,REGULAR_INTERIOR,REGULAR_CREASE))
return Rule.REGULAR_INTERIOR_CREASE;
if (isSame(type1,type2,REGULAR_CREASE,REGULAR_CREASE))
return Rule.REGULAR_CREASE_CREASE;
if (isSame(type1,type2,EXTRAORDINARY_INTERIOR,EXTRAORDINARY_INTERIOR))
return Rule.EXTRAORDINARY_AVERAGE;
if (isSame(type1,type2,EXTRAORDINARY_INTERIOR,EXTRAORDINARY_CREASE))
return Rule.EXTRAORDINARY_AVERAGE;
if (isSame(type1,type2,EXTRAORDINARY_CREASE,EXTRAORDINARY_CREASE))
return Rule.EXTRAORDINARY_AVERAGE;
if (isSame(type1,type2,REGULAR_INTERIOR,EXTRAORDINARY_INTERIOR))
return Rule.EXTRAORDINARY_INTERIOR;
if (isSame(type1,type2,REGULAR_INTERIOR,EXTRAORDINARY_CREASE))
return Rule.EXTRAORDINARY_CREASE;
if (isSame(type1,type2,EXTRAORDINARY_INTERIOR,REGULAR_CREASE))
return Rule.EXTRAORDINARY_INTERIOR;
if (isSame(type1,type2,REGULAR_CREASE,EXTRAORDINARY_CREASE))
return Rule.EXTRAORDINARY_CREASE;
logger.info("Warning: unknown rule for " + type1 + " and " + type2);
return Rule.EXTRAORDINARY_AVERAGE;
}
/**
* Compares the permutations of the types
*
* @param type1
* @param type2
* @param comp1
* @param comp2
* @return <code>true</code> if they are equivalent
*/
public static boolean isSame(VertexType type1, VertexType type2, VertexType comp1, VertexType comp2) {
return (((type1 == comp1) && (type2 == comp2)) || ((type1 == comp2) && (type2 == comp1)));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -