Hi,
This is a fair amount of code to look at, and more than what is reasonable to ask anyone to look at. I’m hoping that the issue is a fairly common one and will just jump out at someone who knows what they’re looking for. I’m a super amateur coder, so I also appreciate this is all probably a horrible mess. Thanks to anyone who has time to help.
Issues
-
I’m building a custom slicer component in c#. First compute works as expected. If I recompute the component seems to take twice as long and uses up more memory. Outputs the same number of results.
-
I’m trying for the first time to use Parallel processes, however my CPU never goes above the none-threaded version despite the process being fairly heavy, so I’m wondering if I’ve coded it correctly. The two issues might be linked.
Logic
The pseudo logic is pretty simple, a list of topologically identical Surfaces are the cutting planes, and a subd is the geo input. Surfaces are ordered based on height location, then tweened to the desired layer height. The resulting list finds intersection with the SubD input (cast to Brep). This process is Paralleled. Results are closed if they slice open. I have 2 custom classes, a Path Class and a Cutplanes Class.
Main Code
protected override void SolveInstance(IGH_DataAccess DA)
{
SubD Geometry = new SubD();
List<Surface> Cutplanes = new List<Surface>();
List<Curve> Seams = new List<Curve>();
double LayerHeight = 0;
Interval PrintDomain = new Interval();
double PathLengthCull = 0;
double DeviationTolerance = 0.1;
double MaximumNodeSpacing = 100;
if (!DA.GetData(0, ref Geometry)) return;
DA.GetDataList(1, Cutplanes);
DA.GetDataList(2, Seams);
if (!DA.GetData(3, ref LayerHeight)) return;
if (!DA.GetData(4, ref PrintDomain)) return;
if (!DA.GetData(5, ref PathLengthCull)) return;
if (!DA.GetData(6, ref DeviationTolerance)) return;
if (!DA.GetData(7, ref MaximumNodeSpacing)) return;
var PrintPaths = new DataTree<Curve>();
var IgnoredPaths = new DataTree<Curve>();
var DiscardedPaths = new DataTree<Curve>();
var pathCurve = new DataTree<Curve>();
var startLayer = (int)PrintDomain.T0;
var endLayer = (int)PrintDomain.T1;
var cutPlanes = new CutPlanes(Cutplanes, LayerHeight);
var Paths = GetPaths(Geometry, cutPlanes.SurfaceCutplanes, Seams, DeviationTolerance, MaximumNodeSpacing);
Out(Paths, PathLengthCull, startLayer, endLayer, out PrintPaths, out DiscardedPaths, out IgnoredPaths);
DA.SetDataTree(0, PrintPaths);
DA.SetDataTree(1, IgnoredPaths);
DA.SetDataTree(2, DiscardedPaths);
DA.SetDataList(3, cutPlanes.SurfaceCutplanes);
}
CutPlanes Class
class CutPlanes
{
public List SurfaceCutplanes = new List();
public CutPlanes()
{
}
public CutPlanes(List<Surface> SurfaceInputs, double LayerHeight)
{
if (SurfaceCutplanes.Count != 0) { SurfaceCutplanes.Clear(); }
if (SortSurfaceCutPlanes(SurfaceInputs, out List<Surface> SortedSurfaceInputs))
{
for (int i = 0; i < SortedSurfaceInputs.Count - 1; i++)
{
NurbsSurface surfaceA = SortedSurfaceInputs[i].ToNurbsSurface();
NurbsSurface surfaceB = SortedSurfaceInputs[i + 1].ToNurbsSurface();
List<ControlPoint> pointsA = surfaceA.Points.ToList();
List<ControlPoint> pointsB = surfaceB.Points.ToList();
Point3d avg1 = new Point3d(pointsA.Average(p => p.X), pointsA.Average(p => p.Y), pointsA.Average(p => p.Z));
Point3d avg2 = new Point3d(pointsB.Average(t => t.X), pointsB.Average(t => t.Y), pointsB.Average(t => t.Z));
double AveragedDistance = avg1.DistanceTo(avg2);
int DivisionAmount = (int)Math.Round(AveragedDistance / LayerHeight);
for (int j = 0; j < DivisionAmount; j++)
{
NurbsSurface surfaceC = (NurbsSurface)surfaceA.Duplicate();
for (int u = 0; u < surfaceA.Points.CountU; u++)
{
for (int v = 0; v < surfaceA.Points.CountV; v++)
{
Point3d uvPointA;
Point3d uvPointB;
surfaceA.Points.GetPoint(u, v, out uvPointA);
surfaceB.Points.GetPoint(u, v, out uvPointB);
double DistanceAB = uvPointA.DistanceTo(uvPointB);
double TweenDistance = (DistanceAB / DivisionAmount) * j;
double TweenFactor = TweenDistance / DistanceAB;
Point3d uvPointC = uvPointA + ((uvPointB - uvPointA) * TweenFactor);
surfaceC.Points.SetPoint(u, v, uvPointC.X, uvPointC.Y, uvPointC.Z);
}
}
SurfaceCutplanes.Add(surfaceC);
}
if (i == SortedSurfaceInputs.Count - 2)
SurfaceCutplanes.Add(surfaceB);
}
}
}
bool SortSurfaceCutPlanes(List<Surface> SurfaceInputs, out List<Surface> SurfaceOutputs)
{
var SortedSurfaceOutputs = new SortedList();
foreach (Surface s in SurfaceInputs)
{
NurbsSurface ns = s.ToNurbsSurface();
if (ns.ToNurbsSurface() == null) { SurfaceOutputs = null; return false; }
double highestz = double.MinValue;
foreach (ControlPoint cp in ns.Points.ToList())
{
if (cp.Z > highestz)
{
highestz = cp.Z;
}
}
SortedSurfaceOutputs.Add(highestz, ns);
}
SurfaceOutputs = new List<Surface>();
if(SortedSurfaceOutputs.Count == 0) { SurfaceOutputs = null; return false; }
for (int i = 0; i < SortedSurfaceOutputs.Count; i++)
{
SurfaceOutputs.Add((Surface)SortedSurfaceOutputs.GetValueList()[i]);
}
return true;
}
}
GetPaths() Method with Parallel Processing
DataTree<Path> GetPaths(SubD Geometry, List<NurbsSurface> CutplaneInput, List<Curve> Seams, double DeviationTolerance, double MaximumNodeSpacing)
{
List<Curve[]> Intersections = new List<Curve[]>();
foreach (NurbsSurface cp in CutplaneInput) { Intersections.Add(null); }
DataTree<Path> PathsOutput = new DataTree<Path>();
Parallel.For(0, CutplaneInput.Count, (Index) =>
{
if (!Rhino.Geometry.Intersect.Intersection.BrepSurface(Geometry.ToBrep(), CutplaneInput[Index], 0.001, out Curve[] Ints, out _))
{ WriteErrors("CP001", Index); return; }
Intersections[Index] = Ints;
});
for (int i = 0; i < Intersections.Count; i++)
{
GH_Path treePath = new GH_Path(i);
if (Intersections[i].Length > 1) { Intersections[i] = Curve.JoinCurves(Intersections[i], 1); }
foreach (Curve crv in Intersections[i])
{
Path path = new Path(crv);
if (!path.PathCurve.IsClosed) { if (!path.TryClose()) { WriteErrors("PP002", i); } }
if(!path.AdjustSeams(Seams)) { WriteErrors("PP005", i); }
PathsOutput.Add(path, treePath);
}
}
return PathsOutput;
}