/* * /// <summary> * /// * /// </summary> * /// <param name="weight"></param> * private void LaplacianFair(double weight) * { * for (int i = 0; i < _verts.Count; i++) * { * var v0 = _verts[i]; * if (v0.IsRemoved) continue; * * // calculate graph laplacian * var sum = new Vec3d(); * var count = 0; * * foreach (var v1 in v0.ConnectedVertices) * { * sum += v1.Position; * count++; * } * * double t = 1.0 / count; * var move = sum * t - v0.Position; * * // apply to central vertex * v0.MoveSum += move * weight; * v0.WeightSum += weight; * * // distribute negated to neighbours * move *= -t; * foreach (var v1 in v0.ConnectedVertices) * { * v1.MoveSum += move * weight; * v1.WeightSum += weight; * } * } * } */ /// <summary> /// Note this method assumes that vertex deltas and weights are clear /// </summary> /// <param name="radius"></param> /// <param name="weight"></param> private void SphereCollide(double radius, double weight) { UpdateGrid(radius); var diam = radius * 2.0; var diamSqr = diam * diam; // calculate collisions foreach (var v0 in _verts) { var p0 = v0.Position; // search from h0 foreach (var v1 in _grid.Search(new Interval3d(p0, diam))) { var d = v1.Position - p0; var m = d.SquareLength; if (m < diamSqr && m > 0.0) { d *= (1.0 - diam / Math.Sqrt(m)) * 0.5 * weight; v0.MoveSum += d; v1.MoveSum -= d; v0.WeightSum = v1.WeightSum = weight; } } // insert h0 _grid.Insert(p0, v0); } _grid.Clear(); }
/// <summary> /// /// </summary> private void CalculateImpl(ReadOnlyArrayView <Body> bodies, ReadOnlyArrayView <int> indices, ArrayView <Vector3d> deltas) { var diam = _radius * 2.0; var diamSqr = diam * diam; for (int i = 0; i < indices.Count; i++) { var p0 = bodies[indices[i]].Position.Current; var sum = Vector3d.Zero; var count = 0; foreach (var p1 in _grid.Search(new Interval3d(p0, diam))) { var d = p1 - p0; var m = d.SquareLength; if (m < diamSqr && m > 0.0) { sum += d * (1.0 - diam / Math.Sqrt(m)); count++; } } deltas[i] = count > 0 ? sum * (Strength / count) : Vector3d.Zero; // average for stability } }
/// <summary> /// /// </summary> /// <param name="particles"></param> private void CalculateImplParallel(IReadOnlyList <IBody> particles) { var diam = _radius * 2.0; var diamSqr = diam * diam; // insert particles foreach (var h in Handles) { _grid.Insert(particles[h].Position, h); } // search from particles ForEach(Partitioner.Create(0, Handles.Count), range => { for (int i = range.Item1; i < range.Item2; i++) { var h0 = Handles[i]; var p0 = particles[h0].Position; var deltaSum = new Vec3d(); int count = 0; _grid.Search(new Interval3d(p0, diam), h1 => { var d = particles[h1].Position - p0; var m = d.SquareLength; if (m < diamSqr && m > 0.0) { deltaSum += d * (1.0 - diam / Math.Sqrt(m)); count++; } return(true); }); if (count == 0) { h0.Weight = 0.0; continue; } h0.Delta = deltaSum * 0.5; h0.Weight = Weight; } }); }
/// <summary> /// /// </summary> /// <param name="particles"></param> private void CalculateImplParallel(IReadOnlyList <IBody> particles) { var diam = _radius * 2.0; var diamSqr = diam * diam; // insert all particles foreach (var h in Handles) { _grid.Insert(particles[h].Position, h); } // search for collisions from each particle ForEach(Partitioner.Create(0, Handles.Count), range => { for (int i = range.Item1; i < range.Item2; i++) { var h0 = Handles[i]; var p0 = particles[h0].Position; var deltaSum = new Vec3d(); int count = 0; foreach (var h1 in _grid.Search(new Interval3d(p0, diam))) { var d = particles[h1].Position - p0; var m = d.SquareLength; if (m < diamSqr && m > 0.0) { deltaSum += d * (1.0 - diam / Math.Sqrt(m)); count++; } } // no projections applied if (count == 0) { h0.Skip = true; continue; } h0.Delta = deltaSum * 0.5; h0.Skip = false; } }); }
/* * /// <summary> * /// * /// </summary> * /// <param name="weightInterior"></param> * /// <param name="weightBoundary"></param> * private void LaplacianFair(double weightInterior, double weightBoundary) * { * for (int i = 0; i < _verts.Count; i++) * { * var v0 = _verts[i]; * if (v0.IsUnused) continue; * * if (v0.IsBoundary) * { * var he = v0.FirstOut; * * var v1 = he.PrevInFace.Start; * var v2 = he.NextInFace.Start; * var move = (v1.Position + v2.Position) * 0.5 - v0.Position; * * // apply to central vertex * v0.MoveSum += move * weightBoundary; * v0.WeightSum += weightBoundary; * * // distribute negated to neighbours * move *= -0.5; * v1.MoveSum += move * weightBoundary; * v1.WeightSum += weightBoundary; * v2.MoveSum += move * weightBoundary; * v2.WeightSum += weightBoundary; * } * else * { * var sum = new Vec3d(); * var count = 0; * * foreach (var v1 in v0.ConnectedVertices) * { * sum += v1.Position; * count++; * } * * double t = 1.0 / count; * var move = sum * t - v0.Position; * * // apply to central vertex * v0.MoveSum += move * weightInterior; * v0.WeightSum += weightInterior; * * // distribute negated to neighbours * move *= -t; * foreach (var v1 in v0.ConnectedVertices) * { * v1.MoveSum += move * weightInterior; * v1.WeightSum += weightInterior; * } * } * } * } */ /// <summary> /// /// </summary> /// <param name="radius"></param> /// <param name="weight"></param> private void SphereCollideParallel(double radius, double weight) { UpdateGrid(radius); var rad2 = radius * 2.0; var rad2Sqr = rad2 * rad2; // insert vertices foreach (var v in _verts) { _grid.Insert(v.Position, v); } // search from each vertex and handle collisions Parallel.ForEach(Partitioner.Create(0, _verts.Count), range => { for (int i = range.Item1; i < range.Item2; i++) { var v0 = _verts[i]; var p0 = v0.Position; var moveSum = new Vec3d(); int count = 0; _grid.Search(new Interval3d(p0, rad2), v1 => { var move = v1.Position - p0; var d = move.SquareLength; if (d < rad2Sqr && d > 0.0) { moveSum += move * (1.0 - rad2 / Math.Sqrt(d)); count++; } return(true); }); if (count == 0) { continue; } v0.MoveSum += moveSum * weight * 0.5; v0.WeightSum += weight; } }); _grid.Clear(); }
/// <summary> /// /// </summary> /// <param name="bodies"></param> private void CalculateImplParallel(IReadOnlyList <IBody> bodies) { var diam = _radius * 2.0; var diamSqr = diam * diam; // insert all particles foreach (var h in Handles) { _grid.Insert(bodies[h].Position, h); } // search for collisions from each particle ForEach(Partitioner.Create(0, Handles.Count), range => { for (int i = range.Item1; i < range.Item2; i++) { var h0 = Handles[i]; var p0 = bodies[h0].Position; var deltaSum = new Vec3d(); foreach (var h1 in _grid.Search(new Interval3d(p0, diam))) { var d = bodies[h1].Position - p0; var m = d.SquareLength; if (m < diamSqr && m > 0.0) { deltaSum += d * (1.0 - diam / Math.Sqrt(m)); } } h0.Delta = deltaSum * Strength; } }); }