修复纸箱不展示问题

This commit is contained in:
admin 2025-04-22 18:59:06 +08:00
parent 3bcbffb16e
commit 8238d35d3a
2 changed files with 77 additions and 91 deletions

View File

@ -59,9 +59,6 @@
<script>
let scene, camera, renderer, controls;
let containerMesh, boxMeshes = [];
let activeCamera = 'front';
let tooltip = document.createElement('div');
tooltip.className = 'tooltip';
let result = {};
function initThree() {
@ -78,19 +75,23 @@
// 初始化相机位置
camera.position.set(15000, 5000, 15000);
controls.target.set(0, 0, 0);
controls.update();
// 添加网格辅助线
const gridHelper = new THREE.GridHelper(20000, 20, 0xffffff, 0x444444);
gridHelper.material.opacity = 0.5;
gridHelper.material.transparent = true;
scene.add(gridHelper);
// 添加坐标轴辅助线
// 添加坐标轴
const axesHelper = new THREE.AxesHelper(5000);
axesHelper.material.color.set(0xff0000); // 红色坐标轴
scene.add(axesHelper);
// 自适应窗口
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
animate();
}
@ -98,12 +99,6 @@
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
// 更新提示信息
if (document.querySelector('.tooltip')) {
document.body.removeChild(document.querySelector('.tooltip'));
}
document.body.appendChild(tooltip);
tooltip.style.opacity = 0;
}
async function calculate() {
@ -121,17 +116,15 @@
weight: parseFloat(document.getElementById('boxWeight').value)
}
};
try {
const response = await fetch('/calculate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
result = await response.json();
console.log(result); // 添加日志
document.getElementById('result').innerHTML = `最优装箱数:${result.count}`;
// 显示说明
@ -157,9 +150,8 @@
data.container.width
);
const containerMat = new THREE.MeshBasicMaterial({
color: 0xAAAAAA, // 浅灰色线框
wireframe: true,
opacity: 0.5
color: 0xAAAAAA,
wireframe: true
});
containerMesh = new THREE.Mesh(containerGeo, containerMat);
containerMesh.position.set(
@ -191,9 +183,9 @@
updateVisibility();
// 添加光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10000, 10000, 10000);
scene.add(directionalLight);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1).normalize();
scene.add(light);
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
} catch (error) {
@ -206,12 +198,6 @@
boxMeshes.forEach(mesh => scene.remove(mesh));
boxMeshes = [];
// 纸箱材质:鲜艳的红色,不透明
const boxMat = new THREE.MeshLambertMaterial({
color: 0xff0000, // 红色
transparent: false
});
const checkedLayers = Array.from(document.querySelectorAll('.layer-checkboxes input:checked'))
.map(cb => parseInt(cb.id.split('-')[1]));
@ -223,23 +209,24 @@
result.boxHeight,
result.boxWidth
);
const boxMat = new THREE.MeshLambertMaterial({ color: 0xff0000 });
const box = new THREE.Mesh(boxGeo, boxMat);
// 设置箱子中心位置
// 设置中心坐标Three.js坐标系
box.position.set(
pos.x + result.boxLength / 2,
pos.y + result.boxHeight / 2,
pos.z + result.boxWidth / 2
);
// 应用旋转角度
// 应用旋转角度(弧度转角度)
box.rotation.set(
THREE.MathUtils.degToRad(pos.rotationX),
THREE.MathUtils.degToRad(pos.rotationY),
THREE.MathUtils.degToRad(pos.rotationZ)
pos.rotationX * Math.PI / 180,
pos.rotationY * Math.PI / 180,
pos.rotationZ * Math.PI / 180
);
box.userData.index = pos.boxNumber;
box.addEventListener('pointerover', showTooltip);
box.addEventListener('pointerout', hideTooltip);
scene.add(box);
@ -253,6 +240,8 @@
const position = box.position;
const rotation = box.rotation;
const dimensions = box.geometry.parameters;
const tooltip = document.createElement('div');
tooltip.className = 'tooltip';
tooltip.innerHTML = `
箱号:${box.userData.index}<br>
位置:(${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z.toFixed(0)})<br>
@ -261,13 +250,15 @@
Y=${(rotation.y * 180 / Math.PI).toFixed(0)}°,
Z=${(rotation.z * 180 / Math.PI).toFixed(0)}°
`;
document.body.appendChild(tooltip);
tooltip.style.left = `${event.clientX + 10}px`;
tooltip.style.top = `${event.clientY - 30}px`;
tooltip.style.opacity = 1;
}
function hideTooltip() {
tooltip.style.opacity = 0;
const tooltips = document.querySelectorAll('.tooltip');
tooltips.forEach(t => t.remove());
}
window.addEventListener('keydown', (e) => {
@ -280,23 +271,30 @@
};
switch (e.key) {
case '1': // 前视图
camera.position.set(data.container.length * 2, data.container.height / 2, data.container.width / 2);
activeCamera = 'front';
camera.position.set(
data.container.length * 2,
data.container.height / 2,
data.container.width / 2
);
break;
case '2': // 后视图
camera.position.set(-data.container.length * 2, data.container.height / 2, data.container.width / 2);
activeCamera = 'back';
case '2': // 顶视图
camera.position.set(
data.container.length / 2,
data.container.height * 2,
data.container.width / 2
);
break;
case '3': // 顶视图
camera.position.set(data.container.length / 2, data.container.height * 2, data.container.width / 2);
activeCamera = 'top';
case '3': // 右视图
camera.position.set(
data.container.length / 2,
data.container.height / 2,
data.container.width * 2
);
break;
}
controls.update();
document.getElementById('axisInfo').innerHTML = `视角:${activeCamera}`;
});
// 确保在页面加载完成后初始化Three.js
window.onload = function() {
initThree();
};

58
main.go
View File

@ -22,7 +22,9 @@ type Box struct {
}
type Placement struct {
X, Y, Z float64 `json:"x"`
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
RotationX float64 `json:"rotationX"`
RotationY float64 `json:"rotationY"`
RotationZ float64 `json:"rotationZ"`
@ -38,29 +40,24 @@ func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
http.HandleFunc("/calculate", func(w http.ResponseWriter, r *http.Request) {
var data struct {
Container Container `json:"container"`
Box Box `json:"box"`
}
json.NewDecoder(r.Body).Decode(&data)
layout, strategy, count := optimizePacking(data.Container, data.Box)
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
for _, layer := range layerMap {
layers = append(layers, Layer{
Count: len(layer),
Layout: layer,
})
}
response := struct {
Count int `json:"count"`
Layers []Layer `json:"layers"`
@ -77,31 +74,26 @@ func main() {
Layers: layers,
Strategy: strategy,
Density: calculateDensity(data.Container, data.Box, count),
SpaceUtilization: calculateSpaceUtilization(data.Container, data.Box, count),
SpaceUtilization: calculateDensity(data.Container, data.Box, count),
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)
})
http.ListenAndServe(":8080", nil)
}
func optimizePacking(con Container, box Box) ([]Placement, string, int) {
rotations := generateRotations(con, box)
type candidate struct {
layout []Placement
count int
strategy string
}
var candidates []candidate
for _, r := range rotations {
for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} {
var xCount, yCount, zCount float64
@ -131,14 +123,12 @@ func optimizePacking(con Container, box Box) ([]Placement, string, int) {
yCount = math.Floor(con.Width / r.Height)
xCount = math.Floor(con.Length / r.Width)
}
totalByVolume := int(xCount * yCount * zCount)
maxCountByWeight := int(math.Floor(con.WeightLimit / box.Weight))
actualCount := totalByVolume
if actualCount > maxCountByWeight {
actualCount = maxCountByWeight
}
if actualCount > 0 {
candidates = append(candidates, candidate{
layout: generateLayout(r, xCount, yCount, zCount, strategy)[:actualCount],
@ -148,15 +138,12 @@ func optimizePacking(con Container, box Box) ([]Placement, string, int) {
}
}
}
if len(candidates) == 0 {
return nil, "", 0
}
maxCount := 0
var finalLayout []Placement
var finalStrategy string
for _, c := range candidates {
if c.count > maxCount {
maxCount = c.count
@ -164,7 +151,6 @@ func optimizePacking(con Container, box Box) ([]Placement, string, int) {
finalStrategy = c.strategy
}
}
return finalLayout, finalStrategy, maxCount
}
@ -196,11 +182,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for z := 0.0; z < zCount; z++ {
layout = append(layout, Placement{
X: x * r.Length,
Y: z * r.Height,
Z: y * r.Width,
Y: y * r.Width,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -211,11 +198,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for y := 0.0; y < yCount; y++ {
layout = append(layout, Placement{
X: x * r.Length,
Y: z * r.Height,
Z: y * r.Width,
Y: y * r.Width,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -226,11 +214,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for z := 0.0; z < zCount; z++ {
layout = append(layout, Placement{
X: x * r.Width,
Y: z * r.Height,
Z: y * r.Length,
Y: y * r.Length,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -241,11 +230,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for x := 0.0; x < xCount; x++ {
layout = append(layout, Placement{
X: x * r.Width,
Y: z * r.Height,
Z: y * r.Length,
Y: y * r.Length,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -256,11 +246,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for y := 0.0; y < yCount; y++ {
layout = append(layout, Placement{
X: x * r.Width,
Y: z * r.Length,
Z: y * r.Height,
Y: y * r.Height,
Z: z * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -271,11 +262,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl
for x := 0.0; x < xCount; x++ {
layout = append(layout, Placement{
X: x * r.Width,
Y: z * r.Length,
Z: y * r.Height,
Y: y * r.Height,
Z: z * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
@ -291,7 +283,3 @@ func calculateDensity(con Container, box Box, count int) float64 {
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)
}