style: apply CSharpier formatting to all C# sources
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests pass after reformat, full solution builds 0 errors. Added .csharpierignore so csproj/config XML keeps its existing layout (CSharpier's XML wrapping churns attributes with zero benefit). Formatting is now enforceable: dotnet csharpier check . passes.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace OpenNest.Gpu
|
||||
{
|
||||
@@ -18,7 +18,8 @@ namespace OpenNest.Gpu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_probed) Probe();
|
||||
if (!_probed)
|
||||
Probe();
|
||||
return _gpuAvailable;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +28,8 @@ namespace OpenNest.Gpu
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_probed) Probe();
|
||||
if (!_probed)
|
||||
Probe();
|
||||
return _deviceName ?? "None";
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,9 @@ namespace OpenNest.Gpu
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[GpuEvaluatorFactory] GPU slide computer failed: {ex.Message}");
|
||||
Debug.WriteLine(
|
||||
$"[GpuEvaluatorFactory] GPU slide computer failed: {ex.Message}"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -80,12 +84,16 @@ namespace OpenNest.Gpu
|
||||
using var context = Context.CreateDefault();
|
||||
foreach (var device in context.Devices)
|
||||
{
|
||||
if (device.AcceleratorType == AcceleratorType.Cuda ||
|
||||
device.AcceleratorType == AcceleratorType.OpenCL)
|
||||
if (
|
||||
device.AcceleratorType == AcceleratorType.Cuda
|
||||
|| device.AcceleratorType == AcceleratorType.OpenCL
|
||||
)
|
||||
{
|
||||
_gpuAvailable = true;
|
||||
_deviceName = device.Name;
|
||||
Debug.WriteLine($"[GpuEvaluatorFactory] GPU found: {device.Name} ({device.AcceleratorType})");
|
||||
Debug.WriteLine(
|
||||
$"[GpuEvaluatorFactory] GPU found: {device.Name} ({device.AcceleratorType})"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ILGPU;
|
||||
using ILGPU.Runtime;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenNest.Gpu
|
||||
{
|
||||
@@ -18,13 +18,18 @@ namespace OpenNest.Gpu
|
||||
private readonly double _spacing;
|
||||
private readonly double _cellSize;
|
||||
|
||||
public GpuPairEvaluator(Drawing drawing, double spacing, double cellSize = PartBitmap.DefaultCellSize)
|
||||
public GpuPairEvaluator(
|
||||
Drawing drawing,
|
||||
double spacing,
|
||||
double cellSize = PartBitmap.DefaultCellSize
|
||||
)
|
||||
{
|
||||
_drawing = drawing;
|
||||
_spacing = spacing;
|
||||
_cellSize = cellSize;
|
||||
_context = Context.CreateDefault();
|
||||
_accelerator = _context.GetPreferredDevice(preferCPU: false)
|
||||
_accelerator = _context
|
||||
.GetPreferredDevice(preferCPU: false)
|
||||
.CreateAccelerator(_context);
|
||||
}
|
||||
|
||||
@@ -91,8 +96,10 @@ namespace OpenNest.Gpu
|
||||
var c = groupItems[i].Candidate;
|
||||
var shiftX = c.Part2Offset.X - locationB.X;
|
||||
var shiftY = c.Part2Offset.Y - locationB.Y;
|
||||
offsets[i * 2 + 0] = (int)System.Math.Round((shiftX + bitmapB.OriginX - bitmapA.OriginX) / _cellSize);
|
||||
offsets[i * 2 + 1] = (int)System.Math.Round((shiftY + bitmapB.OriginY - bitmapA.OriginY) / _cellSize);
|
||||
offsets[i * 2 + 0] = (int)
|
||||
System.Math.Round((shiftX + bitmapB.OriginX - bitmapA.OriginX) / _cellSize);
|
||||
offsets[i * 2 + 1] = (int)
|
||||
System.Math.Round((shiftY + bitmapB.OriginY - bitmapA.OriginY) / _cellSize);
|
||||
}
|
||||
|
||||
var resultScores = new int[candidateCount];
|
||||
@@ -108,10 +115,19 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<int, Stride1D.Dense>,
|
||||
ArrayView1D<int, Stride1D.Dense>,
|
||||
ArrayView1D<int, Stride1D.Dense>,
|
||||
int, int>(OverlapKernel);
|
||||
int,
|
||||
int
|
||||
>(OverlapKernel);
|
||||
|
||||
kernel(candidateCount, gpuPaddedA.View, gpuPaddedB.View,
|
||||
gpuOffsets.View, gpuResults.View, gridWidth, gridHeight);
|
||||
kernel(
|
||||
candidateCount,
|
||||
gpuPaddedA.View,
|
||||
gpuPaddedB.View,
|
||||
gpuOffsets.View,
|
||||
gpuResults.View,
|
||||
gridWidth,
|
||||
gridHeight
|
||||
);
|
||||
|
||||
_accelerator.Synchronize();
|
||||
gpuResults.CopyToCPU(resultScores);
|
||||
@@ -119,31 +135,40 @@ namespace OpenNest.Gpu
|
||||
// Process results in parallel — pre-computed vertices avoid
|
||||
// per-candidate Part creation, and Parallel.For matches the
|
||||
// CPU evaluator's Parallel.ForEach concurrency.
|
||||
Parallel.For(0, candidateCount, i =>
|
||||
{
|
||||
var item = groupItems[i];
|
||||
var hasOverlap = resultScores[i] > 0;
|
||||
Parallel.For(
|
||||
0,
|
||||
candidateCount,
|
||||
i =>
|
||||
{
|
||||
var item = groupItems[i];
|
||||
var hasOverlap = resultScores[i] > 0;
|
||||
|
||||
if (hasOverlap)
|
||||
{
|
||||
allResults[item.OriginalIndex] = new BestFitResult
|
||||
if (hasOverlap)
|
||||
{
|
||||
Candidate = item.Candidate,
|
||||
RotatedArea = 0,
|
||||
BoundingWidth = 0,
|
||||
BoundingHeight = 0,
|
||||
OptimalRotation = 0,
|
||||
TrueArea = trueArea,
|
||||
Keep = false,
|
||||
Reason = "Overlap detected"
|
||||
};
|
||||
allResults[item.OriginalIndex] = new BestFitResult
|
||||
{
|
||||
Candidate = item.Candidate,
|
||||
RotatedArea = 0,
|
||||
BoundingWidth = 0,
|
||||
BoundingHeight = 0,
|
||||
OptimalRotation = 0,
|
||||
TrueArea = trueArea,
|
||||
Keep = false,
|
||||
Reason = "Overlap detected",
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
allResults[item.OriginalIndex] = ComputeBoundingResult(
|
||||
item.Candidate,
|
||||
trueArea,
|
||||
verticesA,
|
||||
verticesB,
|
||||
locationB
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allResults[item.OriginalIndex] = ComputeBoundingResult(
|
||||
item.Candidate, trueArea, verticesA, verticesB, locationB);
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
return allResults.ToList();
|
||||
@@ -161,7 +186,8 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<int, Stride1D.Dense> candidateOffsets,
|
||||
ArrayView1D<int, Stride1D.Dense> results,
|
||||
int gridWidth,
|
||||
int gridHeight)
|
||||
int gridHeight
|
||||
)
|
||||
{
|
||||
var offsetX = candidateOffsets[index * 2];
|
||||
var offsetY = candidateOffsets[index * 2 + 1];
|
||||
@@ -173,7 +199,8 @@ namespace OpenNest.Gpu
|
||||
for (var x = 0; x < gridWidth; x++)
|
||||
{
|
||||
var cellA = partBitmapA[y * gridWidth + x];
|
||||
if (cellA != 1) continue;
|
||||
if (cellA != 1)
|
||||
continue;
|
||||
|
||||
var bx = x - offsetX;
|
||||
var by = y - offsetY;
|
||||
@@ -210,8 +237,12 @@ namespace OpenNest.Gpu
|
||||
private const double ChordTolerance = 0.01;
|
||||
|
||||
private static BestFitResult ComputeBoundingResult(
|
||||
PairCandidate candidate, double trueArea,
|
||||
List<Vector> verticesA, List<Vector> verticesB, Vector locationB)
|
||||
PairCandidate candidate,
|
||||
double trueArea,
|
||||
List<Vector> verticesA,
|
||||
List<Vector> verticesB,
|
||||
Vector locationB
|
||||
)
|
||||
{
|
||||
var shift = candidate.Part2Offset - locationB;
|
||||
|
||||
@@ -221,7 +252,10 @@ namespace OpenNest.Gpu
|
||||
foreach (var v in verticesB)
|
||||
allPoints.Add(v + shift);
|
||||
|
||||
double bestArea, bestWidth, bestHeight, bestRotation;
|
||||
double bestArea,
|
||||
bestWidth,
|
||||
bestHeight,
|
||||
bestRotation;
|
||||
|
||||
if (allPoints.Count >= 3)
|
||||
{
|
||||
@@ -249,13 +283,14 @@ namespace OpenNest.Gpu
|
||||
OptimalRotation = bestRotation,
|
||||
TrueArea = trueArea,
|
||||
Keep = true,
|
||||
Reason = "Valid"
|
||||
Reason = "Valid",
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Vector> GetPartVertices(Part part)
|
||||
{
|
||||
var entities = ConvertProgram.ToGeometry(part.Program)
|
||||
var entities = ConvertProgram
|
||||
.ToGeometry(part.Program)
|
||||
.Where(e => e.Layer != SpecialLayers.Rapid);
|
||||
var shapes = ShapeBuilder.GetShapes(entities);
|
||||
var points = new List<Vector>();
|
||||
@@ -283,7 +318,7 @@ namespace OpenNest.Gpu
|
||||
OptimalRotation = 0,
|
||||
TrueArea = 0,
|
||||
Keep = false,
|
||||
Reason = "No geometry"
|
||||
Reason = "No geometry",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using ILGPU;
|
||||
using ILGPU.Algorithms;
|
||||
using ILGPU.Runtime;
|
||||
using OpenNest.Engine.BestFit;
|
||||
using System;
|
||||
|
||||
namespace OpenNest.Gpu
|
||||
{
|
||||
@@ -14,25 +14,34 @@ namespace OpenNest.Gpu
|
||||
|
||||
// ── Kernels ──────────────────────────────────────────────────
|
||||
|
||||
private readonly Action<Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // stationaryPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // movingPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // offsets
|
||||
ArrayView1D<double, Stride1D.Dense>, // results
|
||||
int, int, int> _kernel;
|
||||
private readonly Action<
|
||||
Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // stationaryPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // movingPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // offsets
|
||||
ArrayView1D<double, Stride1D.Dense>, // results
|
||||
int,
|
||||
int,
|
||||
int
|
||||
> _kernel;
|
||||
|
||||
private readonly Action<Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // stationaryPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // movingPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // offsets
|
||||
ArrayView1D<double, Stride1D.Dense>, // results
|
||||
ArrayView1D<int, Stride1D.Dense>, // directions
|
||||
int, int> _kernelMultiDir;
|
||||
private readonly Action<
|
||||
Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // stationaryPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // movingPrep
|
||||
ArrayView1D<double, Stride1D.Dense>, // offsets
|
||||
ArrayView1D<double, Stride1D.Dense>, // results
|
||||
ArrayView1D<int, Stride1D.Dense>, // directions
|
||||
int,
|
||||
int
|
||||
> _kernelMultiDir;
|
||||
|
||||
private readonly Action<Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // raw
|
||||
ArrayView1D<double, Stride1D.Dense>, // prepared
|
||||
int> _prepareKernel;
|
||||
private readonly Action<
|
||||
Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>, // raw
|
||||
ArrayView1D<double, Stride1D.Dense>, // prepared
|
||||
int
|
||||
> _prepareKernel;
|
||||
|
||||
// ── Buffers ──────────────────────────────────────────────────
|
||||
|
||||
@@ -52,7 +61,8 @@ namespace OpenNest.Gpu
|
||||
public GpuSlideComputer()
|
||||
{
|
||||
_context = Context.CreateDefault();
|
||||
_accelerator = _context.GetPreferredDevice(preferCPU: false)
|
||||
_accelerator = _context
|
||||
.GetPreferredDevice(preferCPU: false)
|
||||
.CreateAccelerator(_context);
|
||||
|
||||
_kernel = _accelerator.LoadAutoGroupedStreamKernel<
|
||||
@@ -61,7 +71,10 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
int, int, int>(SlideKernel);
|
||||
int,
|
||||
int,
|
||||
int
|
||||
>(SlideKernel);
|
||||
|
||||
_kernelMultiDir = _accelerator.LoadAutoGroupedStreamKernel<
|
||||
Index1D,
|
||||
@@ -70,20 +83,27 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
ArrayView1D<int, Stride1D.Dense>,
|
||||
int, int>(SlideKernelMultiDir);
|
||||
int,
|
||||
int
|
||||
>(SlideKernelMultiDir);
|
||||
|
||||
_prepareKernel = _accelerator.LoadAutoGroupedStreamKernel<
|
||||
Index1D,
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
ArrayView1D<double, Stride1D.Dense>,
|
||||
int>(PrepareKernel);
|
||||
int
|
||||
>(PrepareKernel);
|
||||
}
|
||||
|
||||
public double[] ComputeBatch(
|
||||
double[] stationarySegments, int stationaryCount,
|
||||
double[] movingTemplateSegments, int movingCount,
|
||||
double[] offsets, int offsetCount,
|
||||
PushDirection direction)
|
||||
double[] stationarySegments,
|
||||
int stationaryCount,
|
||||
double[] movingTemplateSegments,
|
||||
int movingCount,
|
||||
double[] offsets,
|
||||
int offsetCount,
|
||||
PushDirection direction
|
||||
)
|
||||
{
|
||||
var results = new double[offsetCount];
|
||||
if (offsetCount == 0 || stationaryCount == 0 || movingCount == 0)
|
||||
@@ -100,10 +120,16 @@ namespace OpenNest.Gpu
|
||||
|
||||
_gpuOffsets!.View.SubView(0, offsetCount * 2).CopyFromCPU(offsets);
|
||||
|
||||
_kernel(offsetCount,
|
||||
_gpuStationaryPrep!.View, _gpuMovingPrep!.View,
|
||||
_gpuOffsets.View, _gpuResults!.View,
|
||||
stationaryCount, movingCount, (int)direction);
|
||||
_kernel(
|
||||
offsetCount,
|
||||
_gpuStationaryPrep!.View,
|
||||
_gpuMovingPrep!.View,
|
||||
_gpuOffsets.View,
|
||||
_gpuResults!.View,
|
||||
stationaryCount,
|
||||
movingCount,
|
||||
(int)direction
|
||||
);
|
||||
|
||||
_accelerator.Synchronize();
|
||||
_gpuResults.View.SubView(0, offsetCount).CopyToCPU(results);
|
||||
@@ -113,10 +139,14 @@ namespace OpenNest.Gpu
|
||||
}
|
||||
|
||||
public double[] ComputeBatchMultiDir(
|
||||
double[] stationarySegments, int stationaryCount,
|
||||
double[] movingTemplateSegments, int movingCount,
|
||||
double[] offsets, int offsetCount,
|
||||
int[] directions)
|
||||
double[] stationarySegments,
|
||||
int stationaryCount,
|
||||
double[] movingTemplateSegments,
|
||||
int movingCount,
|
||||
double[] offsets,
|
||||
int offsetCount,
|
||||
int[] directions
|
||||
)
|
||||
{
|
||||
var results = new double[offsetCount];
|
||||
if (offsetCount == 0 || stationaryCount == 0 || movingCount == 0)
|
||||
@@ -134,10 +164,16 @@ namespace OpenNest.Gpu
|
||||
_gpuOffsets!.View.SubView(0, offsetCount * 2).CopyFromCPU(offsets);
|
||||
_gpuDirs!.View.SubView(0, offsetCount).CopyFromCPU(directions);
|
||||
|
||||
_kernelMultiDir(offsetCount,
|
||||
_gpuStationaryPrep!.View, _gpuMovingPrep!.View,
|
||||
_gpuOffsets.View, _gpuResults!.View, _gpuDirs.View,
|
||||
stationaryCount, movingCount);
|
||||
_kernelMultiDir(
|
||||
offsetCount,
|
||||
_gpuStationaryPrep!.View,
|
||||
_gpuMovingPrep!.View,
|
||||
_gpuOffsets.View,
|
||||
_gpuResults!.View,
|
||||
_gpuDirs.View,
|
||||
stationaryCount,
|
||||
movingCount
|
||||
);
|
||||
|
||||
_accelerator.Synchronize();
|
||||
_gpuResults.View.SubView(0, offsetCount).CopyToCPU(results);
|
||||
@@ -147,18 +183,25 @@ namespace OpenNest.Gpu
|
||||
}
|
||||
|
||||
public void InvalidateStationary() => _lastStationaryData = null;
|
||||
|
||||
public void InvalidateMoving() => _lastMovingData = null;
|
||||
|
||||
private void EnsureStationary(double[] data, int count)
|
||||
{
|
||||
// Fast check: if same object or content is identical, skip upload
|
||||
if (_gpuStationaryPrep != null &&
|
||||
_lastStationaryData != null &&
|
||||
_lastStationaryData.Length == data.Length)
|
||||
if (
|
||||
_gpuStationaryPrep != null
|
||||
&& _lastStationaryData != null
|
||||
&& _lastStationaryData.Length == data.Length
|
||||
)
|
||||
{
|
||||
// Reference equality or content equality
|
||||
if (_lastStationaryData == data ||
|
||||
new ReadOnlySpan<double>(_lastStationaryData).SequenceEqual(new ReadOnlySpan<double>(data)))
|
||||
if (
|
||||
_lastStationaryData == data
|
||||
|| new ReadOnlySpan<double>(_lastStationaryData).SequenceEqual(
|
||||
new ReadOnlySpan<double>(data)
|
||||
)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -178,12 +221,18 @@ namespace OpenNest.Gpu
|
||||
|
||||
private void EnsureMoving(double[] data, int count)
|
||||
{
|
||||
if (_gpuMovingPrep != null &&
|
||||
_lastMovingData != null &&
|
||||
_lastMovingData.Length == data.Length)
|
||||
if (
|
||||
_gpuMovingPrep != null
|
||||
&& _lastMovingData != null
|
||||
&& _lastMovingData.Length == data.Length
|
||||
)
|
||||
{
|
||||
if (_lastMovingData == data ||
|
||||
new ReadOnlySpan<double>(_lastMovingData).SequenceEqual(new ReadOnlySpan<double>(data)))
|
||||
if (
|
||||
_lastMovingData == data
|
||||
|| new ReadOnlySpan<double>(_lastMovingData).SequenceEqual(
|
||||
new ReadOnlySpan<double>(data)
|
||||
)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -225,9 +274,11 @@ namespace OpenNest.Gpu
|
||||
Index1D index,
|
||||
ArrayView1D<double, Stride1D.Dense> raw,
|
||||
ArrayView1D<double, Stride1D.Dense> prepared,
|
||||
int count)
|
||||
int count
|
||||
)
|
||||
{
|
||||
if (index >= count) return;
|
||||
if (index >= count)
|
||||
return;
|
||||
var x1 = raw[index * 4 + 0];
|
||||
var y1 = raw[index * 4 + 1];
|
||||
var x2 = raw[index * 4 + 2];
|
||||
@@ -259,15 +310,26 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<double, Stride1D.Dense> movingPrep,
|
||||
ArrayView1D<double, Stride1D.Dense> offsets,
|
||||
ArrayView1D<double, Stride1D.Dense> results,
|
||||
int sCount, int mCount, int direction)
|
||||
int sCount,
|
||||
int mCount,
|
||||
int direction
|
||||
)
|
||||
{
|
||||
if (index >= results.Length) return;
|
||||
if (index >= results.Length)
|
||||
return;
|
||||
|
||||
var dx = offsets[index * 2];
|
||||
var dy = offsets[index * 2 + 1];
|
||||
|
||||
results[index] = ComputeSlideLean(
|
||||
stationaryPrep, movingPrep, dx, dy, sCount, mCount, direction);
|
||||
stationaryPrep,
|
||||
movingPrep,
|
||||
dx,
|
||||
dy,
|
||||
sCount,
|
||||
mCount,
|
||||
direction
|
||||
);
|
||||
}
|
||||
|
||||
private static void SlideKernelMultiDir(
|
||||
@@ -277,22 +339,37 @@ namespace OpenNest.Gpu
|
||||
ArrayView1D<double, Stride1D.Dense> offsets,
|
||||
ArrayView1D<double, Stride1D.Dense> results,
|
||||
ArrayView1D<int, Stride1D.Dense> directions,
|
||||
int sCount, int mCount)
|
||||
int sCount,
|
||||
int mCount
|
||||
)
|
||||
{
|
||||
if (index >= results.Length) return;
|
||||
if (index >= results.Length)
|
||||
return;
|
||||
|
||||
var dx = offsets[index * 2];
|
||||
var dy = offsets[index * 2 + 1];
|
||||
var dir = directions[index];
|
||||
|
||||
results[index] = ComputeSlideLean(
|
||||
stationaryPrep, movingPrep, dx, dy, sCount, mCount, dir);
|
||||
stationaryPrep,
|
||||
movingPrep,
|
||||
dx,
|
||||
dy,
|
||||
sCount,
|
||||
mCount,
|
||||
dir
|
||||
);
|
||||
}
|
||||
|
||||
private static double ComputeSlideLean(
|
||||
ArrayView1D<double, Stride1D.Dense> sPrep,
|
||||
ArrayView1D<double, Stride1D.Dense> mPrep,
|
||||
double dx, double dy, int sCount, int mCount, int direction)
|
||||
double dx,
|
||||
double dy,
|
||||
int sCount,
|
||||
int mCount,
|
||||
int direction
|
||||
)
|
||||
{
|
||||
const double eps = 0.00001;
|
||||
var minDist = double.MaxValue;
|
||||
@@ -317,7 +394,8 @@ namespace OpenNest.Gpu
|
||||
if (mv1 >= sMin - eps && mv1 <= sMax + eps)
|
||||
{
|
||||
var d = RayEdgeLean(m1x, m1y, sPrep, j, direction, eps);
|
||||
if (d < minDist) minDist = d;
|
||||
if (d < minDist)
|
||||
minDist = d;
|
||||
}
|
||||
|
||||
// Test moving vertex 2 against stationary edge j
|
||||
@@ -325,7 +403,8 @@ namespace OpenNest.Gpu
|
||||
if (mv2 >= sMin - eps && mv2 <= sMax + eps)
|
||||
{
|
||||
var d = RayEdgeLean(m2x, m2y, sPrep, j, direction, eps);
|
||||
if (d < minDist) minDist = d;
|
||||
if (d < minDist)
|
||||
minDist = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,7 +427,8 @@ namespace OpenNest.Gpu
|
||||
if (sv1 >= mMin - eps && sv1 <= mMax + eps)
|
||||
{
|
||||
var d = RayEdgeLeanMoving(s1x, s1y, mPrep, j, dx, dy, oppDir, eps);
|
||||
if (d < minDist) minDist = d;
|
||||
if (d < minDist)
|
||||
minDist = d;
|
||||
}
|
||||
|
||||
// Test stationary vertex 2 against moving edge j
|
||||
@@ -356,7 +436,8 @@ namespace OpenNest.Gpu
|
||||
if (sv2 >= mMin - eps && sv2 <= mMax + eps)
|
||||
{
|
||||
var d = RayEdgeLeanMoving(s2x, s2y, mPrep, j, dx, dy, oppDir, eps);
|
||||
if (d < minDist) minDist = d;
|
||||
if (d < minDist)
|
||||
minDist = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,9 +446,13 @@ namespace OpenNest.Gpu
|
||||
}
|
||||
|
||||
private static double RayEdgeLean(
|
||||
double vx, double vy,
|
||||
ArrayView1D<double, Stride1D.Dense> sPrep, int j,
|
||||
int direction, double eps)
|
||||
double vx,
|
||||
double vy,
|
||||
ArrayView1D<double, Stride1D.Dense> sPrep,
|
||||
int j,
|
||||
int direction,
|
||||
double eps
|
||||
)
|
||||
{
|
||||
var p1x = sPrep[j * 10 + 0];
|
||||
var p1y = sPrep[j * 10 + 1];
|
||||
@@ -377,37 +462,49 @@ namespace OpenNest.Gpu
|
||||
if (direction >= 2) // Horizontal (Left=2, Right=3)
|
||||
{
|
||||
var invDy = sPrep[j * 10 + 5];
|
||||
if (invDy == 0) return double.MaxValue;
|
||||
if (invDy == 0)
|
||||
return double.MaxValue;
|
||||
|
||||
var t = (vy - p1y) * invDy;
|
||||
if (t < -eps || t > 1.0 + eps) return double.MaxValue;
|
||||
if (t < -eps || t > 1.0 + eps)
|
||||
return double.MaxValue;
|
||||
|
||||
var ix = p1x + t * (p2x - p1x);
|
||||
var dist = (direction == 2) ? (vx - ix) : (ix - vx);
|
||||
|
||||
if (dist > eps) return dist;
|
||||
if (dist > eps)
|
||||
return dist;
|
||||
return (dist >= -eps) ? 0.0 : double.MaxValue;
|
||||
}
|
||||
else // Vertical (Up=0, Down=1)
|
||||
{
|
||||
var invDx = sPrep[j * 10 + 4];
|
||||
if (invDx == 0) return double.MaxValue;
|
||||
if (invDx == 0)
|
||||
return double.MaxValue;
|
||||
|
||||
var t = (vx - p1x) * invDx;
|
||||
if (t < -eps || t > 1.0 + eps) return double.MaxValue;
|
||||
if (t < -eps || t > 1.0 + eps)
|
||||
return double.MaxValue;
|
||||
|
||||
var iy = p1y + t * (p2y - p1y);
|
||||
var dist = (direction == 1) ? (vy - iy) : (iy - vy);
|
||||
|
||||
if (dist > eps) return dist;
|
||||
if (dist > eps)
|
||||
return dist;
|
||||
return (dist >= -eps) ? 0.0 : double.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static double RayEdgeLeanMoving(
|
||||
double vx, double vy,
|
||||
ArrayView1D<double, Stride1D.Dense> mPrep, int j,
|
||||
double dx, double dy, int direction, double eps)
|
||||
double vx,
|
||||
double vy,
|
||||
ArrayView1D<double, Stride1D.Dense> mPrep,
|
||||
int j,
|
||||
double dx,
|
||||
double dy,
|
||||
int direction,
|
||||
double eps
|
||||
)
|
||||
{
|
||||
var p1x = mPrep[j * 10 + 0] + dx;
|
||||
var p1y = mPrep[j * 10 + 1] + dy;
|
||||
@@ -417,29 +514,35 @@ namespace OpenNest.Gpu
|
||||
if (direction >= 2) // Horizontal
|
||||
{
|
||||
var invDy = mPrep[j * 10 + 5];
|
||||
if (invDy == 0) return double.MaxValue;
|
||||
if (invDy == 0)
|
||||
return double.MaxValue;
|
||||
|
||||
var t = (vy - p1y) * invDy;
|
||||
if (t < -eps || t > 1.0 + eps) return double.MaxValue;
|
||||
if (t < -eps || t > 1.0 + eps)
|
||||
return double.MaxValue;
|
||||
|
||||
var ix = p1x + t * (p2x - p1x);
|
||||
var dist = (direction == 2) ? (vx - ix) : (ix - vx);
|
||||
|
||||
if (dist > eps) return dist;
|
||||
if (dist > eps)
|
||||
return dist;
|
||||
return (dist >= -eps) ? 0.0 : double.MaxValue;
|
||||
}
|
||||
else // Vertical
|
||||
{
|
||||
var invDx = mPrep[j * 10 + 4];
|
||||
if (invDx == 0) return double.MaxValue;
|
||||
if (invDx == 0)
|
||||
return double.MaxValue;
|
||||
|
||||
var t = (vx - p1x) * invDx;
|
||||
if (t < -eps || t > 1.0 + eps) return double.MaxValue;
|
||||
if (t < -eps || t > 1.0 + eps)
|
||||
return double.MaxValue;
|
||||
|
||||
var iy = p1y + t * (p2y - p1y);
|
||||
var dist = (direction == 1) ? (vy - iy) : (iy - vy);
|
||||
|
||||
if (dist > eps) return dist;
|
||||
if (dist > eps)
|
||||
return dist;
|
||||
return (dist >= -eps) ? 0.0 : double.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
+55
-18
@@ -1,9 +1,9 @@
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
|
||||
namespace OpenNest.Gpu
|
||||
{
|
||||
@@ -18,13 +18,22 @@ namespace OpenNest.Gpu
|
||||
|
||||
public const double DefaultCellSize = 0.05;
|
||||
|
||||
public static PartBitmap FromDrawing(Drawing drawing, double cellSize = DefaultCellSize, double spacingDilation = 0)
|
||||
public static PartBitmap FromDrawing(
|
||||
Drawing drawing,
|
||||
double cellSize = DefaultCellSize,
|
||||
double spacingDilation = 0
|
||||
)
|
||||
{
|
||||
var polygons = GetClosedPolygons(drawing);
|
||||
return Rasterize(polygons, cellSize, spacingDilation);
|
||||
}
|
||||
|
||||
public static PartBitmap FromDrawingRotated(Drawing drawing, double rotation, double cellSize = DefaultCellSize, double spacingDilation = 0)
|
||||
public static PartBitmap FromDrawingRotated(
|
||||
Drawing drawing,
|
||||
double rotation,
|
||||
double cellSize = DefaultCellSize,
|
||||
double spacingDilation = 0
|
||||
)
|
||||
{
|
||||
var polygons = GetClosedPolygons(drawing);
|
||||
|
||||
@@ -45,7 +54,8 @@ namespace OpenNest.Gpu
|
||||
/// </summary>
|
||||
public static PartBitmap FromPart(Part part, double cellSize = DefaultCellSize)
|
||||
{
|
||||
var entities = ConvertProgram.ToGeometry(part.Program)
|
||||
var entities = ConvertProgram
|
||||
.ToGeometry(part.Program)
|
||||
.Where(e => e.Layer != SpecialLayers.Rapid);
|
||||
var shapes = ShapeBuilder.GetShapes(entities);
|
||||
|
||||
@@ -65,10 +75,20 @@ namespace OpenNest.Gpu
|
||||
return Rasterize(polygons, cellSize, 0);
|
||||
}
|
||||
|
||||
private static PartBitmap Rasterize(List<Polygon> polygons, double cellSize, double spacingDilation)
|
||||
private static PartBitmap Rasterize(
|
||||
List<Polygon> polygons,
|
||||
double cellSize,
|
||||
double spacingDilation
|
||||
)
|
||||
{
|
||||
if (polygons.Count == 0)
|
||||
return new PartBitmap { Cells = Array.Empty<int>(), Width = 0, Height = 0, CellSize = cellSize };
|
||||
return new PartBitmap
|
||||
{
|
||||
Cells = Array.Empty<int>(),
|
||||
Width = 0,
|
||||
Height = 0,
|
||||
CellSize = cellSize,
|
||||
};
|
||||
|
||||
var minX = double.MaxValue;
|
||||
var minY = double.MaxValue;
|
||||
@@ -79,10 +99,14 @@ namespace OpenNest.Gpu
|
||||
{
|
||||
poly.UpdateBounds();
|
||||
var bb = poly.BoundingBox;
|
||||
if (bb.Left < minX) minX = bb.Left;
|
||||
if (bb.Bottom < minY) minY = bb.Bottom;
|
||||
if (bb.Right > maxX) maxX = bb.Right;
|
||||
if (bb.Top > maxY) maxY = bb.Top;
|
||||
if (bb.Left < minX)
|
||||
minX = bb.Left;
|
||||
if (bb.Bottom < minY)
|
||||
minY = bb.Bottom;
|
||||
if (bb.Right > maxX)
|
||||
maxX = bb.Right;
|
||||
if (bb.Top > maxY)
|
||||
maxY = bb.Top;
|
||||
}
|
||||
|
||||
minX -= spacingDilation;
|
||||
@@ -94,7 +118,13 @@ namespace OpenNest.Gpu
|
||||
var height = (int)System.Math.Ceiling((maxY - minY) / cellSize);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return new PartBitmap { Cells = Array.Empty<int>(), Width = 0, Height = 0, CellSize = cellSize };
|
||||
return new PartBitmap
|
||||
{
|
||||
Cells = Array.Empty<int>(),
|
||||
Width = 0,
|
||||
Height = 0,
|
||||
CellSize = cellSize,
|
||||
};
|
||||
|
||||
var cells = new int[width * height];
|
||||
|
||||
@@ -129,13 +159,14 @@ namespace OpenNest.Gpu
|
||||
Height = height,
|
||||
CellSize = cellSize,
|
||||
OriginX = minX,
|
||||
OriginY = minY
|
||||
OriginY = minY,
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Polygon> GetClosedPolygons(Drawing drawing)
|
||||
{
|
||||
var entities = ConvertProgram.ToGeometry(drawing.Program)
|
||||
var entities = ConvertProgram
|
||||
.ToGeometry(drawing.Program)
|
||||
.Where(e => e.Layer != SpecialLayers.Rapid);
|
||||
var shapes = ShapeBuilder.GetShapes(entities);
|
||||
|
||||
@@ -160,7 +191,11 @@ namespace OpenNest.Gpu
|
||||
/// arrays of identical dimensions with no fractional offset math.
|
||||
/// </summary>
|
||||
public static (int[] cellsA, int[] cellsB, int width, int height) BlitPair(
|
||||
PartBitmap bitmapA, PartBitmap bitmapB, double offsetX, double offsetY)
|
||||
PartBitmap bitmapA,
|
||||
PartBitmap bitmapB,
|
||||
double offsetX,
|
||||
double offsetY
|
||||
)
|
||||
{
|
||||
var cellSize = bitmapA.CellSize;
|
||||
|
||||
@@ -173,10 +208,12 @@ namespace OpenNest.Gpu
|
||||
var combinedMinY = System.Math.Min(bitmapA.OriginY, bWorldOriginY);
|
||||
var combinedMaxX = System.Math.Max(
|
||||
bitmapA.OriginX + bitmapA.Width * cellSize,
|
||||
bWorldOriginX + bitmapB.Width * cellSize);
|
||||
bWorldOriginX + bitmapB.Width * cellSize
|
||||
);
|
||||
var combinedMaxY = System.Math.Max(
|
||||
bitmapA.OriginY + bitmapA.Height * cellSize,
|
||||
bWorldOriginY + bitmapB.Height * cellSize);
|
||||
bWorldOriginY + bitmapB.Height * cellSize
|
||||
);
|
||||
|
||||
var sharedWidth = (int)System.Math.Ceiling((combinedMaxX - combinedMinX) / cellSize);
|
||||
var sharedHeight = (int)System.Math.Ceiling((combinedMaxY - combinedMinY) / cellSize);
|
||||
|
||||
Reference in New Issue
Block a user