Add project files.
This commit is contained in:
+495
@@ -0,0 +1,495 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BoxPacker3D
|
||||
{
|
||||
public class Viewer3D
|
||||
{
|
||||
private Panel panel;
|
||||
|
||||
public Viewer3D(Panel panel)
|
||||
{
|
||||
this.panel = panel;
|
||||
panel.Paint += Panel_Paint;
|
||||
_packedItems = new List<PackedItem>();
|
||||
}
|
||||
|
||||
private List<PackedItem> _packedItems;
|
||||
private Box _box;
|
||||
private double _rotX = 30, _rotY = 30, _zoom = 1.0;
|
||||
private double _wallPad = 0, _itemPad = 0;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_packedItems = new List<PackedItem>();
|
||||
_box = null;
|
||||
panel.Invalidate();
|
||||
}
|
||||
|
||||
public void Render(List<PackedItem> packedItems, Box box,
|
||||
double rotX, double rotY, double zoom = 1.0,
|
||||
double wallPad = 0, double itemPad = 0)
|
||||
{
|
||||
_packedItems = packedItems;
|
||||
_box = box;
|
||||
_rotX = rotX; _rotY = rotY;
|
||||
_zoom = Math.Max(0.1, zoom);
|
||||
_wallPad = wallPad; _itemPad = itemPad;
|
||||
panel.Invalidate();
|
||||
}
|
||||
|
||||
private void Panel_Paint(object sender, PaintEventArgs e)
|
||||
{
|
||||
var g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.Clear(Color.FromArgb(18, 18, 28));
|
||||
if (_box == null) { DrawWelcome(g); return; }
|
||||
DrawScene(g, panel.Width, panel.Height);
|
||||
}
|
||||
|
||||
private void DrawWelcome(Graphics g)
|
||||
{
|
||||
int w = panel.Width, h = panel.Height;
|
||||
using (var brush = new SolidBrush(Color.FromArgb(40, 40, 60)))
|
||||
g.FillRectangle(brush, 0, 0, w, h);
|
||||
using (var pen = new Pen(Color.FromArgb(35, 35, 55), 1))
|
||||
{
|
||||
for (int x = 0; x < w; x += 40) g.DrawLine(pen, x, 0, x, h);
|
||||
for (int y = 0; y < h; y += 40) g.DrawLine(pen, 0, y, w, y);
|
||||
}
|
||||
using (var font = new Font("Segoe UI", 14f))
|
||||
using (var brush = new SolidBrush(Color.FromArgb(80, 100, 160)))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
|
||||
g.DrawString("Zadajte rozmery škatule a kusy,\npotom kliknite 🚀 SPUSTIŤ BALENIE",
|
||||
font, brush, new RectangleF(0, 0, w, h), sf);
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap RenderToBitmap(List<PackedItem> packedItems, Box box,
|
||||
double rotX, double rotY, double zoom, int width, int height,
|
||||
double wallPad = 0, double itemPad = 0, bool whiteBg = false)
|
||||
{
|
||||
var bmp = new Bitmap(width, height);
|
||||
using (var g = Graphics.FromImage(bmp))
|
||||
{
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.Clear(whiteBg ? Color.White : Color.FromArgb(18, 18, 28));
|
||||
DrawSceneEx(g, width, height, packedItems, box, rotX, rotY, zoom, wallPad, itemPad, null, whiteBg);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
public Bitmap RenderLayerToBitmap(List<PackedItem> packedItems, Box box,
|
||||
double rotX, double rotY, double zoom,
|
||||
double layerYMin, double layerYMax,
|
||||
int layerIndex, int totalLayers,
|
||||
int width, int height,
|
||||
double wallPad = 0, double itemPad = 0, bool whiteBg = false)
|
||||
{
|
||||
var bmp = new Bitmap(width, height);
|
||||
using (var g = Graphics.FromImage(bmp))
|
||||
{
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
g.Clear(whiteBg ? Color.White : Color.FromArgb(18, 18, 28));
|
||||
|
||||
var layerItems = packedItems
|
||||
.Where(p => p.Y < layerYMax - 0.001 && p.Y + p.RH > layerYMin + 0.001)
|
||||
.ToList();
|
||||
|
||||
DrawSceneEx(g, width, height, layerItems, box, rotX, rotY, zoom, wallPad, itemPad,
|
||||
$"Vrstva {layerIndex + 1} / {totalLayers} (Y: {layerYMin:F1} – {layerYMax:F1} mm)", whiteBg);
|
||||
|
||||
// Draw layer boundary indicators (subtle horizontal planes at YMin and YMax)
|
||||
DrawLayerBoundaries(g, width, height, box, layerYMin, layerYMax, rotX, rotY, zoom, whiteBg);
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private void DrawLayerBoundaries(Graphics g, int w, int h, Box box,
|
||||
double yMin, double yMax, double rotX, double rotY, double zoom, bool whiteBg)
|
||||
{
|
||||
double radX = rotX * Math.PI / 180.0;
|
||||
double radY = rotY * Math.PI / 180.0;
|
||||
double maxDim = Math.Max(Math.Max(box.W, box.H), box.D);
|
||||
double scale = Math.Min(w, h) * 0.38 / maxDim * zoom;
|
||||
double cx = w / 2.0, cy = h / 2.0;
|
||||
|
||||
// Draw two horizontal planes (YMin and YMax) as subtle dotted lines
|
||||
var planeColor = whiteBg ? Color.FromArgb(80, 255, 100, 100) : Color.FromArgb(60, 255, 180, 100);
|
||||
using (var pen = new Pen(planeColor, 1f) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot })
|
||||
{
|
||||
// YMin plane
|
||||
DrawHorizontalPlane(g, pen, box, yMin, scale, cx, cy, radX, radY);
|
||||
// YMax plane
|
||||
DrawHorizontalPlane(g, pen, box, yMax, scale, cx, cy, radX, radY);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHorizontalPlane(Graphics g, Pen pen, Box box, double y,
|
||||
double scale, double cx, double cy, double radX, double radY)
|
||||
{
|
||||
double yRel = y - box.H / 2; // relative to box center
|
||||
double hw = box.W / 2, hd = box.D / 2;
|
||||
|
||||
// Four corners of the plane
|
||||
var p1 = Project(-hw, yRel, -hd, scale, cx, cy, radX, radY);
|
||||
var p2 = Project( hw, yRel, -hd, scale, cx, cy, radX, radY);
|
||||
var p3 = Project( hw, yRel, hd, scale, cx, cy, radX, radY);
|
||||
var p4 = Project(-hw, yRel, hd, scale, cx, cy, radX, radY);
|
||||
|
||||
// Draw rectangle
|
||||
g.DrawLine(pen, p1, p2);
|
||||
g.DrawLine(pen, p2, p3);
|
||||
g.DrawLine(pen, p3, p4);
|
||||
g.DrawLine(pen, p4, p1);
|
||||
}
|
||||
|
||||
private void DrawScene(Graphics g, int w, int h)
|
||||
=> DrawSceneEx(g, w, h, _packedItems, _box, _rotX, _rotY, _zoom, _wallPad, _itemPad, null, false);
|
||||
|
||||
private void DrawSceneEx(Graphics g, int w, int h,
|
||||
List<PackedItem> items, Box box,
|
||||
double rotX, double rotY, double zoom,
|
||||
double wallPad, double itemPad,
|
||||
string layerLabel, bool whiteBg)
|
||||
{
|
||||
double radX = rotX * Math.PI / 180.0;
|
||||
double radY = rotY * Math.PI / 180.0;
|
||||
|
||||
double maxDim = Math.Max(Math.Max(box.W, box.H), box.D);
|
||||
double scale = Math.Min(w, h) * 0.38 / maxDim * zoom;
|
||||
double cx = w / 2.0, cy = h / 2.0;
|
||||
|
||||
var sorted = items
|
||||
.Select(pi => (pi, depth: Transform(
|
||||
pi.X + pi.RW / 2 - box.W / 2,
|
||||
pi.Y + pi.RH / 2 - box.H / 2,
|
||||
pi.Z + pi.RD / 2 - box.D / 2, radX, radY).Z))
|
||||
.OrderBy(t => t.depth)
|
||||
.ToList();
|
||||
|
||||
DrawBoxOutline(g, scale, cx, cy, box, radX, radY, alpha: whiteBg ? 100 : 40, wallPad: wallPad, whiteBg: whiteBg);
|
||||
|
||||
if (box.WallThickness > 0.001)
|
||||
DrawWallThicknessZone(g, scale, cx, cy, box, radX, radY, whiteBg);
|
||||
|
||||
if (wallPad > 0.001)
|
||||
DrawPaddingZone(g, scale, cx, cy, box, radX, radY, wallPad, whiteBg);
|
||||
|
||||
foreach (var (pi, _) in sorted)
|
||||
DrawCuboid(g, pi, scale, cx, cy, box, radX, radY);
|
||||
|
||||
DrawBoxOutline(g, scale, cx, cy, box, radX, radY, alpha: whiteBg ? 220 : 180, wallPad: wallPad, whiteBg: whiteBg);
|
||||
|
||||
DrawLegend(g, w, h, items, whiteBg);
|
||||
DrawInfo(g, w, h, box, items.Count, whiteBg);
|
||||
|
||||
if (layerLabel != null)
|
||||
{
|
||||
using (var font = new Font("Segoe UI", 11f, FontStyle.Bold))
|
||||
using (var brush = new SolidBrush(whiteBg ? Color.FromArgb(40, 80, 160) : Color.FromArgb(220, 200, 100, 30)))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center };
|
||||
g.DrawString(layerLabel, font, brush, new RectangleF(0, 8, w, 28), sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static (double X, double Y, double Z) Transform(double x, double y, double z,
|
||||
double radX, double radY)
|
||||
{
|
||||
double x1 = x * Math.Cos(radY) + z * Math.Sin(radY);
|
||||
double y1 = y;
|
||||
double z1 = -x * Math.Sin(radY) + z * Math.Cos(radY);
|
||||
double x2 = x1;
|
||||
double y2 = y1 * Math.Cos(radX) - z1 * Math.Sin(radX);
|
||||
double z2 = y1 * Math.Sin(radX) + z1 * Math.Cos(radX);
|
||||
return (x2, y2, z2);
|
||||
}
|
||||
|
||||
private PointF Project(double x, double y, double z,
|
||||
double scale, double cx, double cy, double radX, double radY)
|
||||
{
|
||||
var (tx, ty, _) = Transform(x, y, z, radX, radY);
|
||||
return new PointF((float)(cx + tx * scale), (float)(cy - ty * scale));
|
||||
}
|
||||
|
||||
private void DrawCuboid(Graphics g, PackedItem pi,
|
||||
double scale, double cx, double cy,
|
||||
Box box, double radX, double radY)
|
||||
{
|
||||
double x0 = pi.X - box.W / 2, y0 = pi.Y - box.H / 2, z0 = pi.Z - box.D / 2;
|
||||
double x1 = x0 + pi.RW, y1 = y0 + pi.RH, z1 = z0 + pi.RD;
|
||||
|
||||
var pts = Corners8(x0, y0, z0, x1, y1, z1, scale, cx, cy, radX, radY);
|
||||
var baseColor = pi.Item.Color;
|
||||
|
||||
DrawFace(g, new[] { pts[4], pts[5], pts[6], pts[7] }, Shade(baseColor, 1.00f));
|
||||
DrawFace(g, new[] { pts[5], pts[1], pts[2], pts[6] }, Shade(baseColor, 0.75f));
|
||||
DrawFace(g, new[] { pts[3], pts[2], pts[6], pts[7] }, Shade(baseColor, 0.55f));
|
||||
|
||||
using (var pen = new Pen(Color.FromArgb(200, Color.Black), 0.8f))
|
||||
{
|
||||
g.DrawPolygon(pen, new[] { pts[4], pts[5], pts[6], pts[7] });
|
||||
g.DrawPolygon(pen, new[] { pts[5], pts[1], pts[2], pts[6] });
|
||||
g.DrawPolygon(pen, new[] { pts[3], pts[2], pts[6], pts[7] });
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPaddingZone(Graphics g, double scale, double cx, double cy,
|
||||
Box box, double radX, double radY, double pad, bool whiteBg)
|
||||
{
|
||||
double edge = pad + box.WallThickness;
|
||||
double hw = box.W / 2 - edge, hh = box.H / 2 - edge, hd = box.D / 2 - edge;
|
||||
if (hw <= 0 || hh <= 0 || hd <= 0) return;
|
||||
var pts = new PointF[8];
|
||||
pts[0] = Project(-hw, -hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[1] = Project(hw, -hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[2] = Project(hw, hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[3] = Project(-hw, hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[4] = Project(-hw, -hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[5] = Project(hw, -hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[6] = Project(hw, hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[7] = Project(-hw, hh, hd, scale, cx, cy, radX, radY);
|
||||
|
||||
var col = whiteBg ? Color.FromArgb(150, 200, 150, 50) : Color.FromArgb(60, 255, 220, 80);
|
||||
using (var pen = new Pen(col, 1f))
|
||||
{
|
||||
pen.DashStyle = DashStyle.Dot;
|
||||
g.DrawPolygon(pen, new[] { pts[0], pts[1], pts[2], pts[3] });
|
||||
g.DrawPolygon(pen, new[] { pts[4], pts[5], pts[6], pts[7] });
|
||||
g.DrawLine(pen, pts[0], pts[4]); g.DrawLine(pen, pts[1], pts[5]);
|
||||
g.DrawLine(pen, pts[2], pts[6]); g.DrawLine(pen, pts[3], pts[7]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws inner wire cube + corner connectors to visualise the thickness of the box walls.
|
||||
private void DrawWallThicknessZone(Graphics g, double scale, double cx, double cy,
|
||||
Box box, double radX, double radY, bool whiteBg)
|
||||
{
|
||||
double t = box.WallThickness;
|
||||
double hwO = box.W / 2, hhO = box.H / 2, hdO = box.D / 2;
|
||||
double hwI = hwO - t, hhI = hhO - t, hdI = hdO - t;
|
||||
if (hwI <= 0 || hhI <= 0 || hdI <= 0) return;
|
||||
|
||||
// Outer 8 corners (used for connector lines)
|
||||
var outer = new PointF[8];
|
||||
outer[0] = Project(-hwO, -hhO, -hdO, scale, cx, cy, radX, radY);
|
||||
outer[1] = Project( hwO, -hhO, -hdO, scale, cx, cy, radX, radY);
|
||||
outer[2] = Project( hwO, hhO, -hdO, scale, cx, cy, radX, radY);
|
||||
outer[3] = Project(-hwO, hhO, -hdO, scale, cx, cy, radX, radY);
|
||||
outer[4] = Project(-hwO, -hhO, hdO, scale, cx, cy, radX, radY);
|
||||
outer[5] = Project( hwO, -hhO, hdO, scale, cx, cy, radX, radY);
|
||||
outer[6] = Project( hwO, hhO, hdO, scale, cx, cy, radX, radY);
|
||||
outer[7] = Project(-hwO, hhO, hdO, scale, cx, cy, radX, radY);
|
||||
|
||||
// Inner 8 corners
|
||||
var inner = new PointF[8];
|
||||
inner[0] = Project(-hwI, -hhI, -hdI, scale, cx, cy, radX, radY);
|
||||
inner[1] = Project( hwI, -hhI, -hdI, scale, cx, cy, radX, radY);
|
||||
inner[2] = Project( hwI, hhI, -hdI, scale, cx, cy, radX, radY);
|
||||
inner[3] = Project(-hwI, hhI, -hdI, scale, cx, cy, radX, radY);
|
||||
inner[4] = Project(-hwI, -hhI, hdI, scale, cx, cy, radX, radY);
|
||||
inner[5] = Project( hwI, -hhI, hdI, scale, cx, cy, radX, radY);
|
||||
inner[6] = Project( hwI, hhI, hdI, scale, cx, cy, radX, radY);
|
||||
inner[7] = Project(-hwI, hhI, hdI, scale, cx, cy, radX, radY);
|
||||
|
||||
// Cardboard-brown tones (slightly darker on white backgrounds for print visibility)
|
||||
var innerCol = whiteBg ? Color.FromArgb(220, 120, 80, 40)
|
||||
: Color.FromArgb(200, 180, 140, 90);
|
||||
var connCol = whiteBg ? Color.FromArgb(160, 140, 95, 55)
|
||||
: Color.FromArgb(140, 180, 140, 90);
|
||||
|
||||
// Inner wire cube (solid line)
|
||||
using (var pen = new Pen(innerCol, 1.3f))
|
||||
{
|
||||
g.DrawPolygon(pen, new[] { inner[0], inner[1], inner[2], inner[3] });
|
||||
g.DrawPolygon(pen, new[] { inner[4], inner[5], inner[6], inner[7] });
|
||||
g.DrawLine(pen, inner[0], inner[4]); g.DrawLine(pen, inner[1], inner[5]);
|
||||
g.DrawLine(pen, inner[2], inner[6]); g.DrawLine(pen, inner[3], inner[7]);
|
||||
}
|
||||
|
||||
// 8 corner connectors (outer corner → inner corner)
|
||||
using (var pen = new Pen(connCol, 0.9f))
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
g.DrawLine(pen, outer[i], inner[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBoxOutline(Graphics g, double scale, double cx, double cy,
|
||||
Box box, double radX, double radY, int alpha, double wallPad, bool whiteBg)
|
||||
{
|
||||
double hw = box.W / 2, hh = box.H / 2, hd = box.D / 2;
|
||||
var pts = new PointF[8];
|
||||
pts[0] = Project(-hw, -hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[1] = Project(hw, -hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[2] = Project(hw, hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[3] = Project(-hw, hh, -hd, scale, cx, cy, radX, radY);
|
||||
pts[4] = Project(-hw, -hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[5] = Project(hw, -hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[6] = Project(hw, hh, hd, scale, cx, cy, radX, radY);
|
||||
pts[7] = Project(-hw, hh, hd, scale, cx, cy, radX, radY);
|
||||
|
||||
var col = whiteBg ? Color.FromArgb(alpha, 40, 80, 180) : Color.FromArgb(alpha, 100, 200, 255);
|
||||
using (var pen = new Pen(col, 1.5f))
|
||||
{
|
||||
pen.DashStyle = DashStyle.Dash;
|
||||
g.DrawPolygon(pen, new[] { pts[0], pts[1], pts[2], pts[3] });
|
||||
g.DrawPolygon(pen, new[] { pts[4], pts[5], pts[6], pts[7] });
|
||||
g.DrawLine(pen, pts[0], pts[4]); g.DrawLine(pen, pts[1], pts[5]);
|
||||
g.DrawLine(pen, pts[2], pts[6]); g.DrawLine(pen, pts[3], pts[7]);
|
||||
}
|
||||
|
||||
if (alpha >= 100)
|
||||
{
|
||||
using var dimFont = new Font("Segoe UI", 11f, FontStyle.Bold);
|
||||
var colW = whiteBg ? Color.FromArgb(200, 190, 50, 50) : Color.FromArgb(220, 255, 110, 110);
|
||||
var colH = whiteBg ? Color.FromArgb(200, 50, 150, 50) : Color.FromArgb(220, 110, 230, 110);
|
||||
var colD = whiteBg ? Color.FromArgb(200, 50, 50, 190) : Color.FromArgb(220, 110, 130, 255);
|
||||
|
||||
// midpoint helpers
|
||||
PointF Mid(PointF a, PointF b) => new PointF((a.X + b.X) / 2, (a.Y + b.Y) / 2);
|
||||
|
||||
void DrawDimLabel(string text, PointF pos, Color dimCol)
|
||||
{
|
||||
var sz = g.MeasureString(text, dimFont);
|
||||
float tx = pos.X - sz.Width / 2;
|
||||
float ty = pos.Y - sz.Height / 2;
|
||||
// dark background rect for readability
|
||||
var bgCol = whiteBg ? Color.FromArgb(180, 255, 255, 255) : Color.FromArgb(180, 20, 20, 30);
|
||||
using var bgBr = new SolidBrush(bgCol);
|
||||
g.FillRectangle(bgBr, tx - 2, ty - 1, sz.Width + 4, sz.Height + 2);
|
||||
using var br = new SolidBrush(dimCol);
|
||||
g.DrawString(text, dimFont, br, tx, ty);
|
||||
}
|
||||
|
||||
// šírka: midpoint of bottom-front edge, offset down
|
||||
var midW = Mid(pts[0], pts[1]);
|
||||
DrawDimLabel($"šírka {box.W:F0}", new PointF(midW.X, midW.Y + 24), colW);
|
||||
|
||||
// dĺžka: midpoint of bottom-right edge, offset right+down
|
||||
var midD = Mid(pts[1], pts[5]);
|
||||
DrawDimLabel($"dĺžka {box.D:F0}", new PointF(midD.X + 24, midD.Y + 10), colD);
|
||||
|
||||
// výška: midpoint of right-front edge, offset right
|
||||
var midH = Mid(pts[1], pts[2]);
|
||||
DrawDimLabel($"výška {box.H:F0}", new PointF(midH.X + 30, midH.Y), colH);
|
||||
}
|
||||
}
|
||||
|
||||
private PointF[] Corners8(double x0, double y0, double z0,
|
||||
double x1, double y1, double z1,
|
||||
double scale, double cx, double cy, double radX, double radY)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
Project(x0, y0, z0, scale, cx, cy, radX, radY),
|
||||
Project(x1, y0, z0, scale, cx, cy, radX, radY),
|
||||
Project(x1, y1, z0, scale, cx, cy, radX, radY),
|
||||
Project(x0, y1, z0, scale, cx, cy, radX, radY),
|
||||
Project(x0, y0, z1, scale, cx, cy, radX, radY),
|
||||
Project(x1, y0, z1, scale, cx, cy, radX, radY),
|
||||
Project(x1, y1, z1, scale, cx, cy, radX, radY),
|
||||
Project(x0, y1, z1, scale, cx, cy, radX, radY),
|
||||
};
|
||||
}
|
||||
|
||||
private static void DrawFace(Graphics g, PointF[] corners, Color color)
|
||||
{
|
||||
using (var brush = new SolidBrush(Color.FromArgb(210, color)))
|
||||
g.FillPolygon(brush, corners);
|
||||
}
|
||||
|
||||
private static Color Shade(Color c, float f) => Color.FromArgb(
|
||||
Math.Min(255, (int)(c.R * f)),
|
||||
Math.Min(255, (int)(c.G * f)),
|
||||
Math.Min(255, (int)(c.B * f)));
|
||||
|
||||
private void DrawLegend(Graphics g, int w, int h, List<PackedItem> items, bool whiteBg)
|
||||
{
|
||||
if (items == null || items.Count == 0) return;
|
||||
var unique = items
|
||||
.GroupBy(p => p.Item.Name)
|
||||
.Select(grp => (grp.Key, grp.First().Item.Color, grp.Count()))
|
||||
.ToList();
|
||||
|
||||
int lx = 10, ly = 10;
|
||||
var txtCol = whiteBg ? Color.Black : Color.White;
|
||||
using (var titleFont = new Font("Segoe UI", 8.5f, FontStyle.Bold))
|
||||
using (var itemFont = new Font("Segoe UI", 8f))
|
||||
{
|
||||
using (var b = new SolidBrush(txtCol))
|
||||
g.DrawString("Legenda:", titleFont, b, lx, ly);
|
||||
ly += 18;
|
||||
foreach (var (name, color, cnt) in unique)
|
||||
{
|
||||
using (var b = new SolidBrush(color))
|
||||
g.FillRectangle(b, lx, ly, 12, 12);
|
||||
using (var p = new Pen(Color.Black, 0.5f))
|
||||
g.DrawRectangle(p, lx, ly, 12, 12);
|
||||
using (var b = new SolidBrush(txtCol))
|
||||
g.DrawString($"{name} (×{cnt})", itemFont, b, lx + 16, ly);
|
||||
ly += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInfo(Graphics g, int w, int h, Box box, int count, bool whiteBg)
|
||||
{
|
||||
string info = $"Škatuľa: {box.W} × {box.D} × {box.H} mm | Kusov: {count}";
|
||||
var txtCol = whiteBg ? Color.FromArgb(60, 60, 60) : Color.FromArgb(120, 120, 140);
|
||||
using (var font = new Font("Segoe UI", 8.5f))
|
||||
using (var brush = new SolidBrush(txtCol))
|
||||
{
|
||||
var sf = new StringFormat { Alignment = StringAlignment.Center };
|
||||
g.DrawString(info, font, brush, new RectangleF(0, h - 22, w, 20), sf);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<(double YMin, double YMax)> GetLayers(List<PackedItem> packed)
|
||||
{
|
||||
if (packed == null || packed.Count == 0) return new List<(double, double)>();
|
||||
|
||||
var yVals = new SortedSet<double>();
|
||||
yVals.Add(0);
|
||||
foreach (var p in packed)
|
||||
{
|
||||
yVals.Add(Math.Round(p.Y, 3));
|
||||
yVals.Add(Math.Round(p.Y + p.RH, 3));
|
||||
}
|
||||
|
||||
var sorted = yVals.ToList();
|
||||
var layers = new List<(double, double)>();
|
||||
for (int i = 0; i < sorted.Count - 1; i++)
|
||||
{
|
||||
double yMin = sorted[i], yMax = sorted[i + 1];
|
||||
bool hasItem = packed.Any(p =>
|
||||
p.Y < yMax - 0.001 && p.Y + p.RH > yMin + 0.001);
|
||||
if (hasItem)
|
||||
layers.Add((yMin, yMax));
|
||||
}
|
||||
|
||||
var merged = new List<(double, double)>();
|
||||
if (layers.Count == 0) return merged;
|
||||
double curMin = layers[0].Item1, curMax = layers[0].Item2;
|
||||
for (int i = 1; i < layers.Count; i++)
|
||||
{
|
||||
bool newItemStartsHere = packed.Any(p => Math.Abs(p.Y - layers[i].Item1) < 0.001);
|
||||
if (newItemStartsHere)
|
||||
{
|
||||
merged.Add((curMin, curMax));
|
||||
curMin = layers[i].Item1;
|
||||
}
|
||||
curMax = layers[i].Item2;
|
||||
}
|
||||
merged.Add((curMin, curMax));
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user