internal void ComputeForces() { foreach (var u in particles[0]) { foreach (var v in particles[0]) { if (u != v) { u.force += MultipoleCoefficients.Force(u.point, v.point); } } } }
/// <summary> /// Compute forces between particles using multipole approximations. /// </summary> /// <param name="precision"></param> public void ComputeForces(int precision) { root.computeMultipoleCoefficients(precision); foreach (var l in leaves) { l.ComputeForces(); List <KdNode> stack = new List <KdNode>(); stack.Add(root); while (stack.Count > 0) { KdNode v = stack.Last(); stack.RemoveAt(stack.Count - 1); if (!l.intersects(v)) { foreach (var p in l.particles[0]) { p.force -= v.multipoleCoefficients.ApproximateForce(p.point); } } else { var leaf = v as LeafKdNode; if (leaf != null) { foreach (var p in l.particles[0]) { foreach (var q in leaf.particles[0]) { if (p != q) { p.force += MultipoleCoefficients.Force(p.point, q.point); } } } } else { var n = v as InternalKdNode; stack.Add(n.leftChild); stack.Add(n.rightChild); } } } } }
void ComputeRepulsiveForces(FiNode[] vs) { int n = vs.Length; if (n > 16 && settings.ApproximateRepulsion) { var ps = new KDTree.Particle[vs.Length]; // before calculating forces we perturb each center by a small vector in a unique // but deterministic direction (by walking around a circle in n steps) - this allows // the KD-tree to decompose even when some nodes are at exactly the same position double angle = 0, angleDelta = 2.0 * Math.PI / n; for (int i = 0; i < n; ++i) { ps[i] = new KDTree.Particle(vs[i].Center + 1e-5 * new Point(Math.Cos(angle), Math.Sin(angle))); angle += angleDelta; } var kdTree = new KDTree(ps, 8); kdTree.ComputeForces(5); for (int i = 0; i < vs.Length; ++i) { AddRepulsiveForce(vs[i], ps[i].force); } } else { foreach (FiNode u in vs) { var fu = new Point(); foreach (FiNode v in vs) { if (u != v) { fu += MultipoleCoefficients.Force(u.Center, v.Center); } } AddRepulsiveForce(u, fu); } } }