03 · Live animation (NFP)
Run the NFP engine on a background thread and poll the evolving best layout (progress, fitness, live poses).
Project: Download 03_live.zip — Windows run.bat, macOS/Linux ./run.command.
// 03 live — run the NFP engine on a background thread, poll the evolving best layout.
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
[StructLayout(LayoutKind.Sequential)]
struct NfpParams {
public int placementType, rotations, mutationRate, populationSize, seed;
public double curveTolerance, clipperScale, spacing, sheetSpacing, rotationLimit;
public int useHoles, exploreConcave, clipByHull, clipByRects, simplify, mode, generations, numSeeds, useParallel;
public double timeBudgetSecs;
public int maxSheets, edgeSamples, compactionPasses, tryAllRotations, exactNfp;
}
static class Program {
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)]
static extern int nfp_nest(int part_count, int[] pvc, double[] pxy, int[] pqty, int[] prot,
int[] phc, int[] phvc, double[] phxy, int sheet_count, int[] svc, double[] sxy,
int[] shc, int[] shvc, double[] shxy, ref NfpParams p,
double[] tx, double[] ty, double[] ang, int[] sid, int[] pidx, out int nSheets, out double fitness);
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)] static extern long nfp_progress();
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)] static extern double nfp_fitness();
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)] static extern void nfp_cancel();
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)] static extern void nfp_cancel_reset();
[DllImport("nfp_nest", CallingConvention = CallingConvention.Cdecl)]
static extern int nfp_poll_layout(int n, double[] tx, double[] ty, double[] ang, int[] sid, int[] pidx, out int nSheets);
static void Main() {
var pvc = new int[12]; var pxy = new double[12 * 8];
for (int i = 0; i < 12; i++) {
double w = 20 + (i % 4) * 6, h = 14;
pvc[i] = 4;
double[] r = { 0,0, w,0, w,h, 0,h };
Array.Copy(r, 0, pxy, i * 8, 8);
}
var pqty = new int[12]; for (int i = 0; i < 12; i++) pqty[i] = 1;
int[] svc = { 4 }; double[] sxy = { 0,0, 200,0, 200,200, 0,200 };
var p = new NfpParams { placementType = 1, rotations = 8, populationSize = 10, mutationRate = 10,
seed = 7, clipperScale = 1e7, curveTolerance = 0.3, mode = 1,
generations = 200, useParallel = 1, numSeeds = 4 };
var tx = new double[12]; var ty = new double[12]; var ang = new double[12];
var sid = new int[12]; var pidx = new int[12];
nfp_cancel_reset();
var task = Task.Run(() => nfp_nest(12, pvc, pxy, pqty, null, new int[12], null, null,
1, svc, sxy, new int[1], null, null, ref p, tx, ty, ang, sid, pidx, out _, out _));
for (int frame = 0; frame < 5; frame++) {
Thread.Sleep(100);
var ptx = new double[12]; var pty = new double[12]; var pang = new double[12];
var psid = new int[12]; var ppidx = new int[12];
int placed = nfp_poll_layout(12, ptx, pty, pang, psid, ppidx, out _);
Console.WriteLine($"gen {nfp_progress()}, fitness {nfp_fitness():F3}, placed {placed} so far");
}
nfp_cancel(); // ask the solve to stop early
task.Wait();
Console.WriteLine("done.");
}
}