修复超重问题

This commit is contained in:
admin 2025-04-21 14:12:26 +08:00
parent 441a7d1bd7
commit ae1d3459d9
6 changed files with 293 additions and 173 deletions

BIN
__debug_bin1826320692.exe Normal file

Binary file not shown.

BIN
container-packing.exe Normal file

Binary file not shown.

2
go.mod
View File

@ -23,6 +23,8 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
github.com/vugu/vugu v0.4.0 // indirect
github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019 // indirect
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect

4
go.sum
View File

@ -56,6 +56,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/vugu/vugu v0.4.0 h1:ijU94l+qELec5f+Bb9R8m4fvZkhm4sKhawfmQVCV9a8=
github.com/vugu/vugu v0.4.0/go.mod h1:JU3YFROwFOqodkf1q8c1IRcx92j/dq258cqpaCsDlM8=
github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019 h1:8NGiD5gWbVGObr+lnqcbM2rcOQBO6mr+m19BIblCdho=
github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019/go.mod h1:PrBK6+LJXwb+3EnJTHo43Uh4FhjFFwvN4jKk4Zc5zZ8=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=

View File

@ -28,6 +28,8 @@
transition: opacity 0.3s; transition: opacity 0.3s;
} }
.layer-checkbox { margin-bottom: 10px; } .layer-checkbox { margin-bottom: 10px; }
#weightLimit { margin-top: 10px; }
.layer-checkboxes { margin-top: 20px; }
</style> </style>
</head> </head>
<body> <body>
@ -38,22 +40,22 @@
长:<input type="number" id="conLen" value="12014"><br> 长:<input type="number" id="conLen" value="12014"><br>
宽:<input type="number" id="conWid" value="2337"><br> 宽:<input type="number" id="conWid" value="2337"><br>
高:<input type="number" id="conHei" value="2388"><br> 高:<input type="number" id="conHei" value="2388"><br>
承重上限kg<input type="number" id="weightLimit" value="2000"><br>
</div> </div>
<div> <div>
纸箱尺寸mm<br> 纸箱尺寸mm<br>
长:<input type="number" id="boxLen" value="685"><br> 长:<input type="number" id="boxLen" value="685"><br>
宽:<input type="number" id="boxWid" value="548"><br> 宽:<input type="number" id="boxWid" value="548"><br>
高:<input type="number" id="boxHei" value="489"><br> 高:<input type="number" id="boxHei" value="489"><br>
重量kg<input type="number" id="boxWeight" value="10"><br>
</div> </div>
<button onclick="calculate()">开始计算</button> <button onclick="calculate()">开始计算</button>
<div id="result"></div> <div id="result"></div>
<div id="instructions" style="margin-top:20px; max-width:300px; line-height:1.5;"></div> <div id="instructions" style="margin-top:20px; max-width:300px; line-height:1.5;"></div>
<div class="layer-checkboxes"></div> <div class="layer-checkboxes"></div>
</div> </div>
<div id="axisInfo" class="axis">视角:前视图</div> <div id="axisInfo" class="axis">视角:前视图</div>
<div id="container"></div> <div id="container"></div>
<script> <script>
let scene, camera, renderer, controls; let scene, camera, renderer, controls;
let containerMesh, boxMeshes = []; let containerMesh, boxMeshes = [];
@ -64,19 +66,29 @@
function initThree() { function initThree() {
scene = new THREE.Scene(); scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 1, 100000); camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 100000);
renderer = new THREE.WebGLRenderer({ antialias: true }); renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight); renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('container').appendChild(renderer.domElement); document.getElementById('container').appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement); controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableZoom = true;
controls.enablePan = true;
controls.enableRotate = true;
// 初始化相机位置
camera.position.set(15000, 5000, 15000); camera.position.set(15000, 5000, 15000);
controls.target.set(0, 0, 0);
controls.update(); controls.update();
const gridHelper = new THREE.GridHelper(20000, 20, 0x888888, 0x888888); // 添加网格辅助线
const gridHelper = new THREE.GridHelper(20000, 20, 0xffffff, 0x444444);
gridHelper.material.opacity = 0.5;
gridHelper.material.transparent = true;
scene.add(gridHelper); scene.add(gridHelper);
// 添加坐标轴辅助线
const axesHelper = new THREE.AxesHelper(5000); const axesHelper = new THREE.AxesHelper(5000);
axesHelper.material.color.set(0xff0000); // 红色坐标轴
scene.add(axesHelper); scene.add(axesHelper);
animate(); animate();
@ -86,7 +98,6 @@
requestAnimationFrame(animate); requestAnimationFrame(animate);
controls.update(); controls.update();
renderer.render(scene, camera); renderer.render(scene, camera);
// 更新提示信息 // 更新提示信息
if (document.querySelector('.tooltip')) { if (document.querySelector('.tooltip')) {
document.body.removeChild(document.querySelector('.tooltip')); document.body.removeChild(document.querySelector('.tooltip'));
@ -100,100 +111,110 @@
container: { container: {
length: parseFloat(document.getElementById('conLen').value), length: parseFloat(document.getElementById('conLen').value),
width: parseFloat(document.getElementById('conWid').value), width: parseFloat(document.getElementById('conWid').value),
height: parseFloat(document.getElementById('conHei').value) height: parseFloat(document.getElementById('conHei').value),
weightLimit: parseFloat(document.getElementById('weightLimit').value)
}, },
box: { box: {
length: parseFloat(document.getElementById('boxLen').value), length: parseFloat(document.getElementById('boxLen').value),
width: parseFloat(document.getElementById('boxWid').value), width: parseFloat(document.getElementById('boxWid').value),
height: parseFloat(document.getElementById('boxHei').value) height: parseFloat(document.getElementById('boxHei').value),
weight: parseFloat(document.getElementById('boxWeight').value)
} }
}; };
try {
const response = await fetch('/calculate', { const response = await fetch('/calculate', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data) body: JSON.stringify(data)
}); });
if (!response.ok) {
result = await response.json(); throw new Error(`HTTP error! Status: ${response.status}`);
document.getElementById('result').innerHTML = `最优装箱数:${result.count}`; }
result = await response.json();
// 显示装箱说明 console.log(result); // 添加日志
const instructions = ` document.getElementById('result').innerHTML = `最优装箱数:${result.count}`;
装箱方案说明:<br>
1. 选择最优旋转方式:长${result.boxLength}mm × 宽${result.boxWidth}mm × 高${result.boxHeight}mm<br> // 显示说明
2. 排列策略:${result.strategy}<br> const instructions = `
3. 排列密度:${result.density.toFixed(2)}%<br> 装箱方案说明:<br>
4. 空间利用率:${result.spaceUtilization.toFixed(2)}%<br> 1. 纸箱尺寸:长${result.boxLength}mm × 宽${result.boxWidth}mm × 高${result.boxHeight}mm<br>
5. 实际占用体积:${(result.usedVolume/1000000000).toFixed(2)} m³ 2. 排列策略:${result.strategy}<br>
`; 3. 空间利用率:${result.spaceUtilization.toFixed(2)}%<br>
document.getElementById('instructions').innerHTML = instructions; 4. 总重量:${result.totalWeight.toFixed(2)} kg承重上限${data.container.weightLimit} kg<br>
${result.totalWeight > data.container.weightLimit ? "⚠️ 超重!" : ""}
// 清理现有场景 `;
scene.remove(containerMesh); document.getElementById('instructions').innerHTML = instructions;
boxMeshes.forEach(mesh => scene.remove(mesh));
boxMeshes = []; // 清理场景
scene.remove(containerMesh);
// 创建集装箱 boxMeshes.forEach(mesh => scene.remove(mesh));
const containerGeo = new THREE.BoxGeometry( boxMeshes = [];
data.container.length,
data.container.height, // 创建集装箱
data.container.width const containerGeo = new THREE.BoxGeometry(
); data.container.length,
const containerMat = new THREE.MeshBasicMaterial({ data.container.height,
color: 0x333333, data.container.width
wireframe: true, );
transparent: true, const containerMat = new THREE.MeshBasicMaterial({
opacity: 0.3 color: 0xAAAAAA, // 浅灰色线框
}); wireframe: true,
containerMesh = new THREE.Mesh(containerGeo, containerMat); opacity: 0.5
containerMesh.position.set(data.container.length/2, data.container.height/2, data.container.width/2); });
scene.add(containerMesh); containerMesh = new THREE.Mesh(containerGeo, containerMat);
containerMesh.position.set(
// 创建分层控制 data.container.length / 2,
const layerCheckboxes = document.querySelector('.layer-checkboxes'); data.container.height / 2,
layerCheckboxes.innerHTML = ''; data.container.width / 2
result.layers.forEach((layer, index) => { );
const div = document.createElement('div'); scene.add(containerMesh);
const checkbox = document.createElement('input');
checkbox.type = 'checkbox'; // 创建分层控制
checkbox.id = `layer-${index}`; const layerCheckboxes = document.querySelector('.layer-checkboxes');
checkbox.checked = true; layerCheckboxes.innerHTML = '';
checkbox.addEventListener('change', updateVisibility); result.layers.forEach((layer, index) => {
const div = document.createElement('div');
const label = document.createElement('label'); const checkbox = document.createElement('input');
label.htmlFor = `layer-${index}`; checkbox.type = 'checkbox';
label.textContent = `第${index+1}层 (${layer.count}箱)`; checkbox.id = `layer-${index}`;
checkbox.checked = true;
div.appendChild(checkbox); checkbox.addEventListener('change', updateVisibility);
div.appendChild(label); const label = document.createElement('label');
layerCheckboxes.appendChild(div); label.htmlFor = `layer-${index}`;
}); label.textContent = `第${index + 1}层 (${layer.count}箱)`;
div.appendChild(checkbox);
// 初始显示所有层 div.appendChild(label);
updateVisibility(); layerCheckboxes.appendChild(div);
});
// 添加光源
const light = new THREE.DirectionalLight(0xffffff, 1); // 显示所有层
light.position.set(10000, 10000, 10000); updateVisibility();
scene.add(light);
// 添加光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10000, 10000, 10000);
scene.add(directionalLight);
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
} catch (error) {
console.error('Error:', error);
document.getElementById('result').innerHTML = '计算失败,请检查输入参数。';
}
} }
function updateVisibility() { function updateVisibility() {
// 移除现有箱子
boxMeshes.forEach(mesh => scene.remove(mesh)); boxMeshes.forEach(mesh => scene.remove(mesh));
boxMeshes = []; boxMeshes = [];
const boxMat = new THREE.MeshLambertMaterial({ // 纸箱材质:鲜艳的红色,不透明
color: 0x00ff00, const boxMat = new THREE.MeshLambertMaterial({
transparent: true, color: 0xff0000, // 红色
opacity: 0.6 transparent: false
}); });
// 根据选中层创建箱子
const checkedLayers = Array.from(document.querySelectorAll('.layer-checkboxes input:checked')) const checkedLayers = Array.from(document.querySelectorAll('.layer-checkboxes input:checked'))
.map(cb => parseInt(cb.id.split('-')[1])); .map(cb => parseInt(cb.id.split('-')[1]));
checkedLayers.forEach(layerIndex => { checkedLayers.forEach(layerIndex => {
const layer = result.layers[layerIndex]; const layer = result.layers[layerIndex];
layer.layout.forEach(pos => { layer.layout.forEach(pos => {
@ -203,19 +224,24 @@
result.boxWidth result.boxWidth
); );
const box = new THREE.Mesh(boxGeo, boxMat); const box = new THREE.Mesh(boxGeo, boxMat);
// 设置箱子中心位置
box.position.set( box.position.set(
pos.x + result.boxLength/2, pos.x + result.boxLength / 2,
pos.y + result.boxHeight/2, pos.y + result.boxHeight / 2,
pos.z + result.boxWidth/2 pos.z + result.boxWidth / 2
); );
// 应用旋转角度
box.rotation.set( box.rotation.set(
THREE.MathUtils.degToRad(pos.rotationX), THREE.MathUtils.degToRad(pos.rotationX),
THREE.MathUtils.degToRad(pos.rotationY), THREE.MathUtils.degToRad(pos.rotationY),
THREE.MathUtils.degToRad(pos.rotationZ) THREE.MathUtils.degToRad(pos.rotationZ)
); );
box.userData.index = pos.boxNumber; box.userData.index = pos.boxNumber;
box.on('pointerover', showTooltip); box.addEventListener('pointerover', showTooltip);
box.on('pointerout', hideTooltip); box.addEventListener('pointerout', hideTooltip);
scene.add(box); scene.add(box);
boxMeshes.push(box); boxMeshes.push(box);
}); });
@ -227,14 +253,13 @@
const position = box.position; const position = box.position;
const rotation = box.rotation; const rotation = box.rotation;
const dimensions = box.geometry.parameters; const dimensions = box.geometry.parameters;
tooltip.innerHTML = ` tooltip.innerHTML = `
箱号:${box.userData.index}<br> 箱号:${box.userData.index}<br>
位置:(${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z.toFixed(0)})<br> 位置:(${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z.toFixed(0)})<br>
尺寸:${dimensions.width}×${dimensions.height}×${dimensions.depth}<br> 尺寸:${dimensions.width}×${dimensions.height}×${dimensions.depth}<br>
旋转X=${(rotation.x * 180/Math.PI).toFixed(0)}°, 旋转X=${(rotation.x * 180 / Math.PI).toFixed(0)}°,
Y=${(rotation.y * 180/Math.PI).toFixed(0)}°, Y=${(rotation.y * 180 / Math.PI).toFixed(0)}°,
Z=${(rotation.z * 180/Math.PI).toFixed(0)}° Z=${(rotation.z * 180 / Math.PI).toFixed(0)}°
`; `;
tooltip.style.left = `${event.clientX + 10}px`; tooltip.style.left = `${event.clientX + 10}px`;
tooltip.style.top = `${event.clientY - 30}px`; tooltip.style.top = `${event.clientY - 30}px`;
@ -246,24 +271,35 @@
} }
window.addEventListener('keydown', (e) => { window.addEventListener('keydown', (e) => {
switch(e.key) { const data = {
case '1': container: {
camera.position.set(15000, 5000, 15000); length: parseFloat(document.getElementById('conLen').value),
width: parseFloat(document.getElementById('conWid').value),
height: parseFloat(document.getElementById('conHei').value),
}
};
switch (e.key) {
case '1': // 前视图
camera.position.set(data.container.length * 2, data.container.height / 2, data.container.width / 2);
activeCamera = 'front'; activeCamera = 'front';
break; break;
case '2': case '2': // 后视图
camera.position.set(-15000, 5000, 15000); camera.position.set(-data.container.length * 2, data.container.height / 2, data.container.width / 2);
activeCamera = 'back'; activeCamera = 'back';
break; break;
case '3': case '3': // 顶视图
camera.position.set(0, 15000, 0); camera.position.set(data.container.length / 2, data.container.height * 2, data.container.width / 2);
activeCamera = 'top'; activeCamera = 'top';
break; break;
} }
controls.update();
document.getElementById('axisInfo').innerHTML = `视角:${activeCamera}`; document.getElementById('axisInfo').innerHTML = `视角:${activeCamera}`;
}); });
initThree(); // 确保在页面加载完成后初始化Three.js
window.onload = function() {
initThree();
};
</script> </script>
</body> </body>
</html> </html>

218
main.go
View File

@ -2,36 +2,36 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"math" "math"
"net/http" "net/http"
) )
type Container struct { type Container struct {
Length float64 `json:"length"` Length float64 `json:"length"`
Width float64 `json:"width"` Width float64 `json:"width"`
Height float64 `json:"height"` Height float64 `json:"height"`
WeightLimit float64 `json:"weightLimit"`
} }
type Box struct { type Box struct {
Length float64 `json:"length"` Length float64 `json:"length"`
Width float64 `json:"width"` Width float64 `json:"width"`
Height float64 `json:"height"` Height float64 `json:"height"`
Weight float64 `json:"weight"`
} }
type Placement struct { type Placement struct {
X, Y, Z float64 `json:"x"` X, Y, Z float64 `json:"x"`
RotationX float64 `json:"rotationX"`
RotationY float64 `json:"rotationY"`
RotationZ float64 `json:"rotationZ"`
BoxNumber int `json:"boxNumber"`
} }
type Response struct { type Layer struct {
Count int `json:"count"` Count int `json:"count"`
Layout []Placement `json:"layout"` Layout []Placement `json:"layout"`
BoxLength float64 `json:"boxLength"`
BoxWidth float64 `json:"boxWidth"`
BoxHeight float64 `json:"boxHeight"`
Strategy string `json:"strategy"`
Density float64 `json:"density"`
SpaceUtilization float64 `json:"spaceUtilization"`
UsedVolume float64 `json:"usedVolume"`
} }
func main() { func main() {
@ -46,19 +46,43 @@ func main() {
} }
json.NewDecoder(r.Body).Decode(&data) json.NewDecoder(r.Body).Decode(&data)
layout, bestRotation, strategy, density, spaceUtilization, usedVolume := optimizePacking(data.Container, data.Box) layout, strategy, count := optimizePacking(data.Container, data.Box)
count := len(layout)
response := Response{ layerMap := make(map[float64][]Placement)
for _, pos := range layout {
layerMap[pos.Z] = append(layerMap[pos.Z], pos)
}
var layers []Layer
for _, layer := range layerMap { // 修正:删除未使用的变量 z
layers = append(layers, Layer{
Count: len(layer),
Layout: layer,
})
}
response := struct {
Count int `json:"count"`
Layers []Layer `json:"layers"`
Strategy string `json:"strategy"`
Density float64 `json:"density"`
SpaceUtilization float64 `json:"spaceUtilization"`
UsedVolume float64 `json:"usedVolume"`
TotalWeight float64 `json:"totalWeight"`
BoxLength float64 `json:"boxLength"`
BoxWidth float64 `json:"boxWidth"`
BoxHeight float64 `json:"boxHeight"`
}{
Count: count, Count: count,
Layout: layout, Layers: layers,
BoxLength: bestRotation.Length,
BoxWidth: bestRotation.Width,
BoxHeight: bestRotation.Height,
Strategy: strategy, Strategy: strategy,
Density: density, Density: calculateDensity(data.Container, data.Box, count),
SpaceUtilization: spaceUtilization, SpaceUtilization: calculateSpaceUtilization(data.Container, data.Box, count),
UsedVolume: usedVolume, UsedVolume: float64(count) * data.Box.Length * data.Box.Width * data.Box.Height,
TotalWeight: float64(count) * data.Box.Weight,
BoxLength: data.Box.Length,
BoxWidth: data.Box.Width,
BoxHeight: data.Box.Height,
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
@ -67,17 +91,17 @@ func main() {
http.ListenAndServe(":8080", nil) http.ListenAndServe(":8080", nil)
} }
func optimizePacking(con Container, box Box) ([]Placement, Box, string, float64, float64, float64) { func optimizePacking(con Container, box Box) ([]Placement, string, int) {
var bestLayout []Placement rotations := generateRotations(con, box)
var bestRotation Box
var bestStrategy string
maxCount := 0
var bestDensity float64
var bestSpaceUtilization float64
var bestUsedVolume float64
rotations := generateRotations(box) type candidate struct {
conVolume := con.Length * con.Width * con.Height layout []Placement
count int
weight float64
strategy string
}
var candidates []candidate
for _, r := range rotations { for _, r := range rotations {
for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} { for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} {
@ -110,32 +134,56 @@ func optimizePacking(con Container, box Box) ([]Placement, Box, string, float64,
} }
total := int(xCount * yCount * zCount) total := int(xCount * yCount * zCount)
if total > maxCount && total > 0 { totalWeight := float64(total) * box.Weight
maxCount = total
bestRotation = r
bestStrategy = strategy
bestLayout = generateLayout(r, xCount, yCount, zCount, strategy)
boxVolume := r.Length * r.Width * r.Height if total > 0 {
bestUsedVolume = float64(total) * boxVolume fmt.Printf("Rotation: %v | Strategy: %s | Total: %d | Weight: %.2f kg\n", r, strategy, total, totalWeight)
bestDensity = (bestUsedVolume / conVolume) * 100 candidates = append(candidates, candidate{
bestSpaceUtilization = bestDensity layout: generateLayout(r, xCount, yCount, zCount, strategy),
count: total,
weight: totalWeight,
strategy: strategy,
})
} }
} }
} }
return bestLayout, bestRotation, bestStrategy, bestDensity, bestSpaceUtilization, bestUsedVolume maxCountUnderLimit := 0
var finalLayout []Placement
var finalStrategy string
for _, c := range candidates {
if c.count > maxCountUnderLimit && c.weight <= con.WeightLimit {
maxCountUnderLimit = c.count
finalLayout = c.layout
finalStrategy = c.strategy
}
}
if maxCountUnderLimit == 0 {
return candidates[0].layout, candidates[0].strategy, candidates[0].count
}
return finalLayout, finalStrategy, maxCountUnderLimit
} }
func generateRotations(box Box) []Box { func generateRotations(con Container, box Box) []Box {
return []Box{ validRotations := make([]Box, 0)
{box.Length, box.Width, box.Height}, for _, r := range []Box{
{box.Length, box.Height, box.Width}, {box.Length, box.Width, box.Height, box.Weight},
{box.Width, box.Length, box.Height}, {box.Length, box.Height, box.Width, box.Weight},
{box.Width, box.Height, box.Length}, {box.Width, box.Length, box.Height, box.Weight},
{box.Height, box.Length, box.Width}, {box.Width, box.Height, box.Length, box.Weight},
{box.Height, box.Width, box.Length}, {box.Height, box.Length, box.Width, box.Weight},
{box.Height, box.Width, box.Length, box.Weight},
} {
if r.Length <= con.Length &&
r.Width <= con.Width &&
r.Height <= con.Height {
validRotations = append(validRotations, r)
}
} }
return validRotations
} }
func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Placement { func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Placement {
@ -146,9 +194,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for y := 0.0; y < yCount; y++ { for y := 0.0; y < yCount; y++ {
for z := 0.0; z < zCount; z++ { for z := 0.0; z < zCount; z++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Length, X: x * r.Length,
Y: z * r.Height, Y: z * r.Height,
Z: y * r.Width, Z: y * r.Width,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
@ -158,9 +209,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for z := 0.0; z < zCount; z++ { for z := 0.0; z < zCount; z++ {
for y := 0.0; y < yCount; y++ { for y := 0.0; y < yCount; y++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Length, X: x * r.Length,
Y: z * r.Height, Y: z * r.Height,
Z: y * r.Width, Z: y * r.Width,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
@ -170,9 +224,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for x := 0.0; x < xCount; x++ { for x := 0.0; x < xCount; x++ {
for z := 0.0; z < zCount; z++ { for z := 0.0; z < zCount; z++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Width, X: x * r.Width,
Y: z * r.Height, Y: z * r.Height,
Z: y * r.Length, Z: y * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
@ -182,9 +239,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for z := 0.0; z < zCount; z++ { for z := 0.0; z < zCount; z++ {
for x := 0.0; x < xCount; x++ { for x := 0.0; x < xCount; x++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Width, X: x * r.Width,
Y: z * r.Height, Y: z * r.Height,
Z: y * r.Length, Z: y * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
@ -194,9 +254,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for x := 0.0; x < xCount; x++ { for x := 0.0; x < xCount; x++ {
for y := 0.0; y < yCount; y++ { for y := 0.0; y < yCount; y++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Width, X: x * r.Width,
Y: z * r.Length, Y: z * r.Length,
Z: y * r.Height, Z: y * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
@ -206,13 +269,28 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for y := 0.0; y < yCount; y++ { for y := 0.0; y < yCount; y++ {
for x := 0.0; x < xCount; x++ { for x := 0.0; x < xCount; x++ {
layout = append(layout, Placement{ layout = append(layout, Placement{
X: x * r.Width, X: x * r.Width,
Y: z * r.Length, Y: z * r.Length,
Z: y * r.Height, Z: y * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
}) })
} }
} }
} }
default:
fmt.Println("无效排列策略")
} }
return layout return layout
} }
func calculateDensity(con Container, box Box, count int) float64 {
containerVolume := con.Length * con.Width * con.Height
boxVolume := float64(count) * box.Length * box.Width * box.Height
return (boxVolume / containerVolume) * 100
}
func calculateSpaceUtilization(con Container, box Box, count int) float64 {
return calculateDensity(con, box, count)
}