public void ClusterCell(float error)
{
if (type != NodeType.Internal)
return;
/*
* First cluster all the children nodes
*/
int[] signs = { -1, -1, -1, -1, -1, -1, -1, -1 };
int mid_sign = -1;
bool is_collapsible = true;
for (int i = 0; i < 8; i++)
{
if (children[i] == null)
continue;
children[i].ClusterCell(error);
if (children[i].type == NodeType.Internal) //Can't cluster if the child has children
is_collapsible = false;
else
{
mid_sign = (children[i].corners >> (7 - i)) & 1;
signs[i] = (children[i].corners >> i) & 1;
}
}
corners = 0;
for (int i = 0; i < 8; i++)
{
if (signs[i] == -1)
corners |= (byte)(mid_sign << i);
else
corners |= (byte)(signs[i] << i);
}
//if (!is_collapsible)
// return;
int surface_index = 0;
List<Vertex> collected_vertices = new List<Vertex>();
List<Vertex> new_vertices = new List<Vertex>();
if (index == 31681)
{
}
if (index == 61440)
{
}
if (index == 7715)
{
}
if ((int)position.X == 12 && (int)position.Y == 18 && (int)position.Z == 26)
{
}
/*
* Find all the surfaces inside the children that cross the 6 Euclidean edges and the vertices that connect to them
*/
for (int i = 0; i < 12; i++)
{
OctreeNode[] face_nodes = new OctreeNode[2];
int c1 = Utilities.TEdgePairs[i, 0];
int c2 = Utilities.TEdgePairs[i, 1];
face_nodes[0] = children[c1];
face_nodes[1] = children[c2];
ClusterFace(face_nodes, Utilities.TEdgePairs[i, 2], ref surface_index, collected_vertices);
}
for (int i = 0; i < 6; i++)
{
OctreeNode[] edge_nodes =
{
children[Utilities.TCellProcEdgeMask[i, 0]],
children[Utilities.TCellProcEdgeMask[i, 1]],
children[Utilities.TCellProcEdgeMask[i, 2]],
children[Utilities.TCellProcEdgeMask[i, 3]]
};
if (size == 4 && i == 1)
{
}
ClusterEdge(edge_nodes, Utilities.TCellProcEdgeMask[i, 4], ref surface_index, collected_vertices);
}
if (size == 16 && position.X == 0 && position.Y == 16 && position.Z == 16)
{
}
if (index == 61440)
{
}
int highest_index = surface_index;
if (highest_index == -1)
highest_index = 0;
/*
* Gather the stray vertices
*/
foreach (OctreeNode n in children)
{
if (n == null)
continue;
foreach (Vertex v in n.vertices)
{
if (v == null)
continue;
if (v.surface_index == -1)
{
v.surface_index = highest_index++;
collected_vertices.Add(v);
}
}
}
//GatherVertices(this, collected_vertices, ref highest_index);
//if (surface_index == 0 && highest_index > 1)
// return;
if (highest_index == 7)
{
}
int clustered_count = 0;
if (collected_vertices.Count > 0)
{
for (int i = 0; i <= highest_index; i++)
{
QEFProper.QEFSolver qef = new QEFProper.QEFSolver();
Vector3 normal = Vector3.Zero;
int count = 0;
int[] edges = new int[12];
int euler = 0;
int e = 0;
foreach (Vertex v in collected_vertices)
{
if (v.surface_index == i)
{
/*if (!v.qef.hasSolution)
v.qef.Solve(1e-6f, 4, 1e-6f);
if (v.qef.GetError() > error)
{
count = 0;
break;
}*/
/* Calculate ei(Sv) */
for (int k = 0; k < 3; k++)
{
int edge = Utilities.TExternalEdges[v.in_cell, k];
edges[edge] += v.eis[edge];
}
/* Calculate e(Svk) */
for (int k = 0; k < 9; k++)
{
int edge = Utilities.TInternalEdges[v.in_cell, k];
e += v.eis[edge];
}
euler += v.euler;
qef.Add(ref v.qef.data);
normal += v.normal;
count++;
}
}
/*
* One vertex might have an error greater than the threshold, preventing simplification.
* When it's just one, we can ignore the error and proceed.
*/
if (count == 0)
{
continue;
}
bool face_prop2 = true;
for (int f = 0; f < 6 && face_prop2; f++)
{
int intersections = 0;
for (int ei = 0; ei < 4; ei++)
{
intersections += edges[Utilities.TFaces[f, ei]];
}
if (!(intersections == 0 || intersections == 2))
face_prop2 = false;
}
Vertex new_vertex = new Vertex();
normal /= (float)count;
normal.Normalize();
new_vertex.normal = normal;
new_vertex.qef = qef;
new_vertex.eis = edges;
new_vertex.euler = euler - e / 4;
if (new_vertex.euler != 1)
{
}
new_vertex.in_cell = this.child_index;
new_vertex.face_prop2 = face_prop2;
if (face_prop2)
{
}
if (new_vertex.euler != 1)
{
}
new_vertices.Add(new_vertex);
//new_vertex.index = rnd.Next();
qef.Solve(1e-6f, 4, 1e-6f);
float err = qef.GetError();
new_vertex.collapsible = err <= error/* && new_vertex.euler == 1 && face_prop2*/;
new_vertex.error = err;
clustered_count++;
if (count > 4)
{
}
foreach (Vertex v in collected_vertices)
{
if (v.surface_index == i)
{
Vertex p = v;
//p.surface_index = -1;
/*while (p.parent != null)
{
p = p.parent;
//p.surface_index = -1;
if (p == p.parent)
{
p.parent = null;
break;
}
}*/
if (p != new_vertex)
p.parent = new_vertex;
else
p.parent = null;
}
}
}
}
else
{
return;
}
if (new_vertices.Count >= collected_vertices.Count)
{
}
//if (clustered_count <= 0)
{
foreach (Vertex v2 in collected_vertices)
{
v2.surface_index = -1;
}
}
//this.type = NodeType.Collapsed;
//for (int i = 0; i < 8; i++)
// children[i] = null;
this.vertices = new_vertices.ToArray();
if (this.vertices.Length > 4)
{
}
}