Slightly faster. still much room for improvement. Curve operations are definitely bottlenecks.
protected override void SolveInstance(IGH_DataAccess DA)
{
unchecked
{
Curve crv = null;
var N = 0;
var iteration = 20;
DA.GetData(0, ref crv);
DA.GetData(1, ref N);
DA.GetData(2, ref iteration);
var sw = new Stopwatch();
sw.Start();
var srf = Brep.CreatePlanarBreps(crv, 0.0001)[0];
var rnd = new System.Random();
var face = srf.Faces[0];
var domU = face.Domain(0);
int ss = 100;
var AM = AreaMassProperties.Compute(srf);
var area = AM.Area;
double dd = Math.Sqrt(area / (N * ss));
ee = Math.Sqrt(area / ((double)N) * 4d / Math.Sqrt(3d)) * 1.1d;
int NN = (int)(Math.Sqrt(N * ss));
var pts = new List<Point3d>();
_crv = crv;
for (var i = 0; i < NN; i++)
{
double t = ((double)i) / ((double)NN);
double u = domU[0] + (domU[1] - domU[0]) * t;
var cc = face.TrimAwareIsoCurve(1, u);
for (var j = 0; j < cc.Length; j++)
{
var ccc = cc[j];
double L = ccc.GetLength();
int NNN = (int)(L / dd);
if (NNN > 0)
{
pts.AddRange(ccc.DivideByCount(NNN, false).Select(ccc.PointAt));
}
}
}
ppp = pts.OrderBy(x => rnd.NextDouble()).Take(N).ToArray();
dict1 = new Dictionary<(int, int), List<Point3d>>();
dict2 = new (int, int)[N];
for (var i = 0; i < N; i++)
{
var p = ppp[i];
int xx = (int)Math.Floor(p.X / ee);
int yy = (int)Math.Floor(p.Y / ee);
var key = (xx, yy);
if (dict1.TryGetValue(key, out var list))
{
list.Add(p);
}
else
{
dict1[key] = new List<Point3d>() { p };
}
dict2[i] = key;
}
var boundary = new Dictionary<(int, int), bool>();
foreach (var key in dict1.Keys)
{
boundary[key] = test(key.Item1, key.Item2);
}
for (var t = 0; t < iteration; t++)
{
var dict3 = ParallelEnumerable.Range(0, N).AsOrdered().Select(F1).ToArray();
for (var i = 0; i < N; i++)
{
var V = dict3[i];
var p = ppp[i];
var key = dict2[i];
dict1[key].Remove(p);
Point3d newp = p + V * 0.7;
if (boundary[key])
{
var PC = _crv.Contains(newp, Plane.WorldXY, 0.0001);
if (PC == PointContainment.Inside)
{
ppp[i] = newp;
}
else
{
double tt;
_crv.ClosestPoint(p, out tt, 1000);
var T = _crv.TangentAt(tt);
T = new Vector3d(T.Y, -T.X, 0);
T.Unitize();
V -= (T * V) * T;
newp = p + V * 0.7;
ppp[i] = newp;
}
}
else
{
ppp[i] = newp;
}
int xx = (int)Math.Floor(newp.X / ee);
int yy = (int)Math.Floor(newp.Y / ee);
key = (xx, yy);
if (dict1.TryGetValue(key, out var list))
{
list.Add(newp);
}
else
{
dict1[key] = new List<Point3d>() { newp };
}
dict2[i] = key;
}
foreach (var _key in dict1.Keys)
{
if (!boundary.ContainsKey(_key))
{
boundary[_key] = test(_key.Item1, _key.Item2);
}
}
}
sw.Stop();
DA.SetDataList(0, ppp);
DA.SetData(1, sw.ElapsedMilliseconds);
}
}
Point3d[] ppp;
Curve _crv;
Dictionary<(int, int), List<Point3d>> dict1;
(int, int)[] dict2;
double ee;
static readonly int[] jjj = new[] { 0, -1, 1 };
private bool test(int xx, int yy)
{
unchecked
{
double minx = (double)(xx) * (ee);
double maxx = (double)(xx + 1) * (ee);
double miny = (double)(yy) * (ee);
double maxy = (double)(yy + 1) * (ee);
var P = new Point3d(minx, miny, 0);
var Q = new Point3d(maxx, miny, 0);
var R = new Point3d(maxx, maxy, 0);
var W = new Point3d(minx, maxy, 0);
return _crv.Contains(P, Plane.WorldXY) != PointContainment.Inside
|| _crv.Contains(Q, Plane.WorldXY) != PointContainment.Inside
|| _crv.Contains(R, Plane.WorldXY) != PointContainment.Inside
|| _crv.Contains(W, Plane.WorldXY) != PointContainment.Inside;
}
}
Vector3d F1(int i)
{
unchecked
{
var p = ppp[i];
var key = dict2[i];
var xx = key.Item1;
var yy = key.Item2;
var V = Vector3d.Zero;
for (var iu = 0; iu < 3; iu++)
{
for (var iv = 0; iv < 3; iv++)
{
var u = jjj[iu];
var v = jjj[iv];
key = (xx + u, yy + v);
if (dict1.TryGetValue(key, out var cell))
{
for (var ii = 0; ii < cell.Count; ii++)
{
var q = cell[ii];
var dist = (p.DistanceTo(q));
if (dist <= ee)
{
var L = 1 - dist / ee;
V += (p - q) * (L * L);
}
}
}
}
}
return V;
}
}