修复纸箱不展示问题
This commit is contained in:
parent
3bcbffb16e
commit
8238d35d3a
90
index.html
90
index.html
@ -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
58
main.go
@ -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)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user