/*
         * /// <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();
        }
        /// <inheritdoc />
        protected override void Calculate(ReadOnlyArrayView <Body> bodies, ReadOnlyArrayView <int> indices, ArrayView <Vector3d> deltas)
        {
            if (_grid == null)
            {
                _grid = new HashGrid3d <Vector3d>(indices.Count);
            }

            // update grid
            _grid.Scale = Radius * _radiusToGridScale;

            // insert body positions
            for (int i = 0; i < indices.Count; i++)
            {
                var p = bodies[indices[i]].Position.Current;
                _grid.Insert(p, p);
            }

            // search from each body position
            if (_parallel)
            {
                ForEach(Partitioner.Create(0, indices.Count), range =>
                {
                    var i = range.Item1;
                    var n = range.Item2 - i;
                    CalculateImpl(bodies, indices.Subview(i, n), deltas.Subview(i, n));
                });
            }
            else
            {
                CalculateImpl(bodies, indices, deltas);
            }

            _grid.Clear();
        }
        /// <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;
                }
            });
        }
Exemple #5
0
            /*
             * /// <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();
            }
Exemple #6
0
        /// <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;
                }
            });
        }