136 lines
3.9 KiB
C#
136 lines
3.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace FurnitureExporter;
|
|
|
|
/// <summary>
|
|
/// 从板件包围盒推导辅助装配吸附面。
|
|
/// </summary>
|
|
public static class SnapSurfaceBuilder
|
|
{
|
|
private static readonly FaceDefinition[] Faces =
|
|
{
|
|
new("left", 0, false, new[] { -1.0, 0.0, 0.0 }),
|
|
new("right", 0, true, new[] { 1.0, 0.0, 0.0 }),
|
|
new("front", 1, false, new[] { 0.0, -1.0, 0.0 }),
|
|
new("back", 1, true, new[] { 0.0, 1.0, 0.0 }),
|
|
new("bottom", 2, false, new[] { 0.0, 0.0, -1.0 }),
|
|
new("top", 2, true, new[] { 0.0, 0.0, 1.0 }),
|
|
};
|
|
|
|
public static List<SnapSurfaceInfo> BuildSnapSurfaces(IReadOnlyList<PanelInfo> panels)
|
|
{
|
|
var allSurfaces = new List<SnapSurfaceInfo>();
|
|
|
|
foreach (var panel in panels)
|
|
{
|
|
var panelSurfaces = BuildPanelSurfaces(panel);
|
|
panel.SnapSurfaces = panelSurfaces;
|
|
allSurfaces.AddRange(panelSurfaces);
|
|
}
|
|
|
|
return allSurfaces;
|
|
}
|
|
|
|
private static List<SnapSurfaceInfo> BuildPanelSurfaces(PanelInfo panel)
|
|
{
|
|
var (min, max, confidence) = ResolveBounds(panel);
|
|
var surfaces = new List<SnapSurfaceInfo>(Faces.Length);
|
|
|
|
foreach (var face in Faces)
|
|
{
|
|
var center = new[]
|
|
{
|
|
Round((min[0] + max[0]) / 2.0),
|
|
Round((min[1] + max[1]) / 2.0),
|
|
Round((min[2] + max[2]) / 2.0),
|
|
};
|
|
|
|
var boundsMin = new[] { min[0], min[1], min[2] };
|
|
var boundsMax = new[] { max[0], max[1], max[2] };
|
|
var planeValue = face.UseMax ? max[face.Axis] : min[face.Axis];
|
|
center[face.Axis] = planeValue;
|
|
boundsMin[face.Axis] = planeValue;
|
|
boundsMax[face.Axis] = planeValue;
|
|
|
|
surfaces.Add(new SnapSurfaceInfo
|
|
{
|
|
Id = $"{panel.Id}_snap_{face.Name}",
|
|
Face = face.Name,
|
|
PanelId = panel.Id,
|
|
Normal = face.Normal,
|
|
Center = center,
|
|
Bounds = new BoundingBox3D
|
|
{
|
|
Min = RoundAll(boundsMin),
|
|
Max = RoundAll(boundsMax),
|
|
},
|
|
Confidence = confidence,
|
|
});
|
|
}
|
|
|
|
return surfaces;
|
|
}
|
|
|
|
private static (double[] Min, double[] Max, double Confidence) ResolveBounds(PanelInfo panel)
|
|
{
|
|
if (panel.BoundingBox?.Min?.Length == 3 && panel.BoundingBox.Max?.Length == 3)
|
|
{
|
|
return (RoundAll(panel.BoundingBox.Min), RoundAll(panel.BoundingBox.Max), 1.0);
|
|
}
|
|
|
|
var center = panel.Position?.Length == 3
|
|
? panel.Position
|
|
: new[] { 0.0, 0.0, 0.0 };
|
|
var size = panel.Size?.Length == 3
|
|
? panel.Size
|
|
: new[] { 0.0, 0.0, 0.0 };
|
|
|
|
var min = new[]
|
|
{
|
|
center[0] - Math.Abs(size[0]) / 2.0,
|
|
center[1] - Math.Abs(size[1]) / 2.0,
|
|
center[2] - Math.Abs(size[2]) / 2.0,
|
|
};
|
|
var max = new[]
|
|
{
|
|
center[0] + Math.Abs(size[0]) / 2.0,
|
|
center[1] + Math.Abs(size[1]) / 2.0,
|
|
center[2] + Math.Abs(size[2]) / 2.0,
|
|
};
|
|
|
|
return (RoundAll(min), RoundAll(max), 0.6);
|
|
}
|
|
|
|
private static double[] RoundAll(IReadOnlyList<double> values)
|
|
{
|
|
return new[]
|
|
{
|
|
Round(values[0]),
|
|
Round(values[1]),
|
|
Round(values[2]),
|
|
};
|
|
}
|
|
|
|
private static double Round(double value)
|
|
{
|
|
return Math.Round(value, 2);
|
|
}
|
|
|
|
private sealed class FaceDefinition
|
|
{
|
|
public FaceDefinition(string name, int axis, bool useMax, double[] normal)
|
|
{
|
|
Name = name;
|
|
Axis = axis;
|
|
UseMax = useMax;
|
|
Normal = normal;
|
|
}
|
|
|
|
public string Name { get; }
|
|
public int Axis { get; }
|
|
public bool UseMax { get; }
|
|
public double[] Normal { get; }
|
|
}
|
|
}
|