/* Threaded is a very simple way to multithread the node generation * Be careful though, as the number of tasks generated is 8^threaded * Anything more than 1 generally is slower than 1 * To be safe, either keep it at 0 or 1 */ public bool ConstructNodes(List<VertexPositionColorNormal> vertices, int grid_size, int threaded = 0) { if (size == 1) { return ConstructLeaf(vertices, grid_size); } int child_size = size / 2; bool has_children = false; Task[] threads = new Task[8]; bool[] return_values = new bool[8]; for (int i = 0; i < 8; i++) { Vector3 offset = new Vector3(i / 4, i % 4 / 2, i % 2); OctreeNode child = new OctreeNode(); child.size = child_size; child.position = position + offset * (float)child_size; child.type = OctreeNodeType.Internal; int index = i; if (threaded > 0 && size > 2) { threads[index] = Task.Factory.StartNew( () => { return_values[index] = child.ConstructNodes(vertices, grid_size, threaded - 1); if (return_values[index]) children[index] = child; else children[index] = null; }, TaskCreationOptions.AttachedToParent); //threads[index].Start(); } else { if (child.ConstructNodes(vertices, grid_size, 0)) has_children = true; else child = null; children[i] = child; } } if (threaded > 0 && size > 2) { for (int i = 0; i < 8; i++) { threads[i].Wait(); if (return_values[i]) has_children = true; } } if (!has_children) return false; return true; }
public void ProcessCell(List<int> indexes) { if (type == OctreeNodeType.Internal) { for (int i = 0; i < 8; i++) { if (children[i] != null) children[i].ProcessCell(indexes); } for (int i = 0; i < 12; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; int c1 = cellProcFaceMask[i, 0]; int c2 = cellProcFaceMask[i, 1]; face_nodes[0] = children[c1]; face_nodes[1] = children[c2]; ProcessFace(face_nodes, cellProcFaceMask[i, 2], indexes); } for (int i = 0; i < 6; i++) { OctreeNode[] edge_nodes = { children[cellProcEdgeMask[i, 0]], children[cellProcEdgeMask[i, 1]], children[cellProcEdgeMask[i, 2]], children[cellProcEdgeMask[i, 3]] }; ProcessEdge(edge_nodes, cellProcEdgeMask[i, 4], indexes); } } }
public static void ProcessIndexes(OctreeNode[] nodes, int direction, List<int> indexes) { int min_size = 10000000; int min_index = 0; int[] indices = { -1, -1, -1, -1 }; bool flip = false; bool sign_changed = false; for (int i = 0; i < 4; i++) { int edge = processEdgeMask[direction, i]; int c1 = edgevmap[edge, 0]; int c2 = edgevmap[edge, 1]; int m1 = (nodes[i].draw_info.corners >> c1) & 1; int m2 = (nodes[i].draw_info.corners >> c2) & 1; if (nodes[i].size < min_size) { min_size = nodes[i].size; min_index = i; flip = m1 == 1; sign_changed = ((m1 == 0 && m2 != 0) || (m1 != 0 && m2 == 0)); } indices[i] = nodes[i].draw_info.index; //sign_changed = true; } if (sign_changed) { if (!flip) { if (indices[0] != indices[1] && indices[1] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[1]); indexes.Add(indices[3]); } if (indices[0] != indices[2] && indices[2] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[3]); indexes.Add(indices[2]); } } else { if (indices[0] != indices[1] && indices[1] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[3]); indexes.Add(indices[1]); } if (indices[0] != indices[2] && indices[2] != indices[3]) { indexes.Add(indices[0]); indexes.Add(indices[2]); indexes.Add(indices[3]); } } } }
public static void ProcessFace(OctreeNode[] nodes, int direction, List<int> indexes) { if (nodes[0] == null || nodes[1] == null) return; if (nodes[0].type == OctreeNodeType.Internal || nodes[1].type == OctreeNodeType.Internal) { for (int i = 0; i < 4; i++) { OctreeNode[] face_nodes = new OctreeNode[2]; for (int j = 0; j < 2; j++) { if (nodes[j].type != OctreeNodeType.Internal) face_nodes[j] = nodes[j]; else face_nodes[j] = nodes[j].children[faceProcFaceMask[direction, i, j]]; } ProcessFace(face_nodes, faceProcFaceMask[direction, i, 2], indexes); } int[,] orders = { { 0, 0, 1, 1 }, { 0, 1, 0, 1 }, }; for (int i = 0; i < 4; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[orders[faceProcEdgeMask[direction, i, 0], j]].type == OctreeNodeType.Leaf || nodes[orders[faceProcEdgeMask[direction, i, 0], j]].type == OctreeNodeType.Pseudo) edge_nodes[j] = nodes[orders[faceProcEdgeMask[direction, i, 0], j]]; else edge_nodes[j] = nodes[orders[faceProcEdgeMask[direction, i, 0], j]].children[faceProcEdgeMask[direction, i, 1 + j]]; } ProcessEdge(edge_nodes, faceProcEdgeMask[direction, i, 5], indexes); } } }
public static void ProcessEdge(OctreeNode[] nodes, int direction, List<int> indexes) { if (nodes[0] == null || nodes[1] == null || nodes[2] == null || nodes[3] == null) return; if (nodes[0].type != OctreeNodeType.Internal && nodes[1].type != OctreeNodeType.Internal && nodes[2].type != OctreeNodeType.Internal && nodes[3].type != OctreeNodeType.Internal) { ProcessIndexes(nodes, direction, indexes); } else { for (int i = 0; i < 2; i++) { OctreeNode[] edge_nodes = new OctreeNode[4]; for (int j = 0; j < 4; j++) { if (nodes[j].type == OctreeNodeType.Leaf || nodes[j].type == OctreeNodeType.Pseudo) edge_nodes[j] = nodes[j]; else edge_nodes[j] = nodes[j].children[edgeProcEdgeMask[direction, i, j]]; } ProcessEdge(edge_nodes, edgeProcEdgeMask[direction, i, 4], indexes); } } }
public void ConstructTreeGrid(OctreeNode node) { if (node == null) return; VertexPositionColor[] vs = new VertexPositionColor[24]; int x = (int)node.position.X; int y = (int)node.position.Y; int z = (int)node.position.Z; Color c = Color.LightSteelBlue; Color v = Color.Red; float size = node.size; vs[0] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[1] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[2] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[3] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[4] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[5] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[6] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[7] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[8] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[9] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[10] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[11] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); vs[12] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); vs[13] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[14] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[15] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[16] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 0 * size), c); vs[17] = new VertexPositionColor(new Vector3(x + 0 * size, y + 0 * size, z + 1 * size), c); vs[18] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 0 * size), c); vs[19] = new VertexPositionColor(new Vector3(x + 0 * size, y + 1 * size, z + 1 * size), c); vs[20] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 0 * size), c); vs[21] = new VertexPositionColor(new Vector3(x + 1 * size, y + 0 * size, z + 1 * size), c); vs[22] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 0 * size), c); vs[23] = new VertexPositionColor(new Vector3(x + 1 * size, y + 1 * size, z + 1 * size), c); OutlineBuffer.SetData<VertexPositionColor>(OutlineLocation * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 24, VertexPositionColor.VertexDeclaration.VertexStride); OutlineLocation += 24; /*if (node.type != OctreeNodeType.Leaf || node.draw_info.index == -1 || true) { OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 8, VertexPositionColor.VertexDeclaration.VertexStride); outline_location += 8; } else { x += (int)(node.draw_info.position.X * (float)this.size); y += (int)(node.draw_info.position.Y * (float)this.size); float r = 2; vs[8] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); vs[9] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); vs[10] = new VertexPositionColor(new Vector3(x + r, y - r, 0), v); vs[11] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); vs[12] = new VertexPositionColor(new Vector3(x + r, y + r, 0), v); vs[13] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); vs[14] = new VertexPositionColor(new Vector3(x - r, y + r, 0), v); vs[15] = new VertexPositionColor(new Vector3(x - r, y - r, 0), v); OutlineBuffer.SetData<VertexPositionColor>(outline_location * VertexPositionColor.VertexDeclaration.VertexStride, vs, 0, 16, VertexPositionColor.VertexDeclaration.VertexStride); outline_location += 16; }*/ if (node.type != OctreeNodeType.Leaf) { for (int i = 0; i < 8; i++) { ConstructTreeGrid(node.children[i]); } } }
public override long Contour(float threshold) { Stopwatch watch = new Stopwatch(); Vertices.Clear(); tree = new OctreeNode(); watch.Start(); tree.Build(Vector3.Zero, Resolution, threshold, Vertices, Size); tree.GenerateVertexBuffer(Vertices); if (Vertices.Count > 0) VertexBuffer.SetData<VertexPositionColorNormal>(Vertices.ToArray()); VertexCount = Vertices.Count; //ConstructTreeGrid(tree); CalculateIndexes(); watch.Stop(); return watch.ElapsedMilliseconds; }