virtual protected void ComputeSubMeshes() { Submeshes = new List <DSubmesh3>(); KeyToMesh = new Dictionary <object, DSubmesh3>(); SpinLock data_lock = new SpinLock(); gParallel.ForEach(TriangleSetKeys, (obj) => { DSubmesh3 submesh = new DSubmesh3(Mesh, TriangleSetF(obj), 0); bool taken = false; data_lock.Enter(ref taken); Submeshes.Add(submesh); KeyToMesh[obj] = submesh; data_lock.Exit(); }); }
// TODO: parallel version, cache tri normals void Compute_FaceAvg_AreaWeighted() { int NV = Mesh.MaxVertexID; if (NV != Normals.size) { Normals.resize(NV); } for (int i = 0; i < NV; ++i) { Normals[i] = Vector3d.Zero; } var Normals_lock = new SpinLock(); gParallel.ForEach(Mesh.TriangleIndices(), (ti) => { Index3i tri = Mesh.GetTriangle(ti); Vector3d va = Mesh.GetVertex(tri.a); Vector3d vb = Mesh.GetVertex(tri.b); Vector3d vc = Mesh.GetVertex(tri.c); Vector3d N = MathUtil.Normal(ref va, ref vb, ref vc); double a = MathUtil.Area(ref va, ref vb, ref vc); bool taken = false; Normals_lock.Enter(ref taken); Normals[tri.a] += a * N; Normals[tri.b] += a * N; Normals[tri.c] += a * N; Normals_lock.Exit(); }); gParallel.BlockStartEnd(0, NV - 1, (vi_start, vi_end) => { for (int vi = vi_start; vi <= vi_end; vi++) { if (Normals[vi].LengthSquared > MathUtil.ZeroTolerancef) { Normals[vi] = Normals[vi].Normalized; } } }); }
} // end make_level_set_3 void make_level_set3_parallel(Vector3f origin, float dx, int ni, int nj, int nk, DenseGrid3f distances, int exact_band) { distances.resize(ni, nj, nk); distances.assign((float)((ni + nj + nk) * dx)); // upper bound on distance // closest triangle id for each grid cell DenseGrid3i closest_tri = new DenseGrid3i(ni, nj, nk, -1); // intersection_count(i,j,k) is # of tri intersections in (i-1,i]x{j}x{k} DenseGrid3i intersection_count = new DenseGrid3i(ni, nj, nk, 0); if (DebugPrint) { System.Console.WriteLine("start"); } double ox = (double)origin[0], oy = (double)origin[1], oz = (double)origin[2]; double invdx = 1.0 / dx; // Compute narrow-band distances. For each triangle, we find its grid-coord-bbox, // and compute exact distances within that box. // To compute in parallel, we need to safely update grid cells. Current strategy is // to use a spinlock to control access to grid. Partitioning the grid into a few regions, // each w/ a separate spinlock, improves performance somewhat. Have also tried having a // separate spinlock per-row, this resulted in a few-percent performance improvement. // Also tried pre-sorting triangles into disjoint regions, this did not help much except // on "perfect" cases like a sphere. int wi = ni / 2, wj = nj / 2, wk = nk / 2; SpinLock[] grid_locks = new SpinLock[8]; bool abort = false; gParallel.ForEach(Mesh.TriangleIndices(), (tid) => { if (tid % 100 == 0) { abort = CancelF(); } if (abort) { return; } Vector3d xp = Vector3d.Zero, xq = Vector3d.Zero, xr = Vector3d.Zero; Mesh.GetTriVertices(tid, ref xp, ref xq, ref xr); // real ijk coordinates of xp/xq/xr double fip = (xp[0] - ox) * invdx, fjp = (xp[1] - oy) * invdx, fkp = (xp[2] - oz) * invdx; double fiq = (xq[0] - ox) * invdx, fjq = (xq[1] - oy) * invdx, fkq = (xq[2] - oz) * invdx; double fir = (xr[0] - ox) * invdx, fjr = (xr[1] - oy) * invdx, fkr = (xr[2] - oz) * invdx; // clamped integer bounding box of triangle plus exact-band int i0 = MathUtil.Clamp(((int)MathUtil.Min(fip, fiq, fir)) - exact_band, 0, ni - 1); int i1 = MathUtil.Clamp(((int)MathUtil.Max(fip, fiq, fir)) + exact_band + 1, 0, ni - 1); int j0 = MathUtil.Clamp(((int)MathUtil.Min(fjp, fjq, fjr)) - exact_band, 0, nj - 1); int j1 = MathUtil.Clamp(((int)MathUtil.Max(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1); int k0 = MathUtil.Clamp(((int)MathUtil.Min(fkp, fkq, fkr)) - exact_band, 0, nk - 1); int k1 = MathUtil.Clamp(((int)MathUtil.Max(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1); // compute distance for each tri inside this bounding box // note: this can be very conservative if the triangle is large and on diagonal to grid axes for (int k = k0; k <= k1; ++k) { for (int j = j0; j <= j1; ++j) { int base_idx = ((j < wj) ? 0 : 1) | ((k < wk) ? 0 : 2); // construct index into spinlocks array for (int i = i0; i <= i1; ++i) { Vector3d gx = new Vector3d((float)i * dx + origin[0], (float)j * dx + origin[1], (float)k * dx + origin[2]); float d = (float)point_triangle_distance(ref gx, ref xp, ref xq, ref xr); if (d < distances[i, j, k]) { int lock_idx = base_idx | ((i < wi) ? 0 : 4); bool taken = false; grid_locks[lock_idx].Enter(ref taken); if (d < distances[i, j, k]) // have to check again in case grid changed in another thread... { distances[i, j, k] = d; closest_tri[i, j, k] = tid; } grid_locks[lock_idx].Exit(); } } } } }); if (CancelF()) { return; } if (ComputeSigns == true) { if (DebugPrint) { System.Console.WriteLine("done narrow-band"); } compute_intersections(origin, dx, ni, nj, nk, intersection_count); if (CancelF()) { return; } if (DebugPrint) { System.Console.WriteLine("done intersections"); } if (ComputeMode == ComputeModes.FullGrid) { // and now we fill in the rest of the distances with fast sweeping for (int pass = 0; pass < 2; ++pass) { sweep_pass(origin, dx, distances, closest_tri); if (CancelF()) { return; } } if (DebugPrint) { System.Console.WriteLine("done sweeping"); } } else { // nothing! if (DebugPrint) { System.Console.WriteLine("skipped sweeping"); } } if (DebugPrint) { System.Console.WriteLine("done sweeping"); } // then figure out signs (inside/outside) from intersection counts compute_signs(ni, nj, nk, distances, intersection_count); if (CancelF()) { return; } if (WantIntersectionsGrid) { intersections_grid = intersection_count; } if (DebugPrint) { System.Console.WriteLine("done signs"); } } if (WantClosestTriGrid) { closest_tri_grid = closest_tri; } } // end make_level_set_3
public SafeListBuilder() { List = new List <T>(); spinlock = new SpinLock(); }