// Build the tree. Policy only matters for bottom-up strategies public void Build(BuildStrategy eStrategy = BuildStrategy.TopDownMidpoint, ClusterPolicy ePolicy = ClusterPolicy.Default) { if (eStrategy == BuildStrategy.BottomUpFromOneRings) { build_by_one_rings(ePolicy); } else if (eStrategy == BuildStrategy.TopDownMedian) { build_top_down(true); } else if (eStrategy == BuildStrategy.TopDownMidpoint) { build_top_down(false); } else if (eStrategy == BuildStrategy.Default) { build_top_down(false); } mesh_timestamp = mesh.Timestamp; }
// strategy here is: // 1) partition triangles by vertex one-rings into leaf boxes // 1a) first pass where we skip one-rings that have < 3 free tris // 1b) second pass where we handle any missed tris // 2) sequentially combine N leaf boxes into (N/2 + N%2) layer 2 boxes // 3) repeat until layer K has only 1 box, which is root of tree void build_by_one_rings(ClusterPolicy ePolicy) { box_to_index = new DVector <int>(); box_centers = new DVector <Vector3f>(); box_extents = new DVector <Vector3f>(); int iBoxCur = 0; index_list = new DVector <int>(); int iIndicesCur = 0; // replace w/ BitArray ? byte[] used_triangles = new byte[mesh.MaxTriangleID]; Array.Clear(used_triangles, 0, used_triangles.Length); // temporary buffer int nMaxEdgeCount = mesh.GetMaxVtxEdgeCount(); int[] temp_tris = new int[2 * nMaxEdgeCount]; // first pass: cluster by one-ring, but if # of free tris // in a ring is small (< 3), push onto spill list to try again, // because those tris might be picked up by a bigger cluster DVector <int> spill = new DVector <int>(); foreach (int vid in mesh.VertexIndices()) { int tCount = add_one_ring_box(vid, used_triangles, temp_tris, ref iBoxCur, ref iIndicesCur, spill, 3); if (tCount < 3) { spill.Add(vid); } } // second pass: check any spill vertices. Most are probably gone // now, but a few stray triangles might still exist int N = spill.Length; for (int si = 0; si < N; ++si) { int vid = spill[si]; add_one_ring_box(vid, used_triangles, temp_tris, ref iBoxCur, ref iIndicesCur, null, 0); } // [RMS] test code to make sure each triangle is in exactly one list //foreach ( int tid in mesh.TriangleIndices() ) { // int n = used_triangles[tid]; // if (n != 1) // Util.gBreakToDebugger(); //} // keep track of where triangle lists end triangles_end = iIndicesCur; // this defines ClusterPolicy.Default //ClusterFunctionType clusterF = cluster_boxes; //ClusterFunctionType clusterF = cluster_boxes_matrix; ClusterFunctionType clusterF = cluster_boxes_nearsearch; if (ePolicy == ClusterPolicy.Fastest) { clusterF = cluster_boxes; } else if (ePolicy == ClusterPolicy.MinimalVolume) { clusterF = cluster_boxes_matrix; } else if (ePolicy == ClusterPolicy.FastVolumeMetric) { clusterF = cluster_boxes_nearsearch; } // ok, now repeatedly cluster current layer of N boxes into N/2 + N%2 boxes, // until we hit a 1-box layer, which is root of the tree int nPrevEnd = iBoxCur; int nLayerSize = clusterF(0, iBoxCur, ref iBoxCur, ref iIndicesCur); int iStart = nPrevEnd; int iCount = iBoxCur - nPrevEnd; while (nLayerSize > 1) { nPrevEnd = iBoxCur; nLayerSize = clusterF(iStart, iCount, ref iBoxCur, ref iIndicesCur); iStart = nPrevEnd; iCount = iBoxCur - nPrevEnd; } root_index = iBoxCur - 1; }