test
This commit is contained in:
parent
d596db7e29
commit
441a7d1bd7
Binary file not shown.
Binary file not shown.
141
index.html
141
index.html
@ -18,6 +18,16 @@
|
||||
}
|
||||
#result { margin-top: 20px; font-weight: bold; }
|
||||
.axis { position: absolute; bottom: 20px; left: 20px; background: rgba(255,255,255,0.8); padding: 10px; border-radius: 4px; }
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
background: rgba(0,0,0,0.7);
|
||||
color: white;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
.layer-checkbox { margin-bottom: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -37,6 +47,8 @@
|
||||
</div>
|
||||
<button onclick="calculate()">开始计算</button>
|
||||
<div id="result"></div>
|
||||
<div id="instructions" style="margin-top:20px; max-width:300px; line-height:1.5;"></div>
|
||||
<div class="layer-checkboxes"></div>
|
||||
</div>
|
||||
|
||||
<div id="axisInfo" class="axis">视角:前视图</div>
|
||||
@ -46,6 +58,9 @@
|
||||
let scene, camera, renderer, controls;
|
||||
let containerMesh, boxMeshes = [];
|
||||
let activeCamera = 'front';
|
||||
let tooltip = document.createElement('div');
|
||||
tooltip.className = 'tooltip';
|
||||
let result = {};
|
||||
|
||||
function initThree() {
|
||||
scene = new THREE.Scene();
|
||||
@ -71,6 +86,13 @@
|
||||
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() {
|
||||
@ -93,13 +115,26 @@
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
result = await response.json();
|
||||
document.getElementById('result').innerHTML = `最优装箱数:${result.count}`;
|
||||
|
||||
// 显示装箱说明
|
||||
const instructions = `
|
||||
装箱方案说明:<br>
|
||||
1. 选择最优旋转方式:长${result.boxLength}mm × 宽${result.boxWidth}mm × 高${result.boxHeight}mm<br>
|
||||
2. 排列策略:${result.strategy}<br>
|
||||
3. 排列密度:${result.density.toFixed(2)}%<br>
|
||||
4. 空间利用率:${result.spaceUtilization.toFixed(2)}%<br>
|
||||
5. 实际占用体积:${(result.usedVolume/1000000000).toFixed(2)} m³
|
||||
`;
|
||||
document.getElementById('instructions').innerHTML = instructions;
|
||||
|
||||
// 清理现有场景
|
||||
scene.remove(containerMesh);
|
||||
boxMeshes.forEach(mesh => scene.remove(mesh));
|
||||
boxMeshes = [];
|
||||
|
||||
// 创建集装箱
|
||||
const containerGeo = new THREE.BoxGeometry(
|
||||
data.container.length,
|
||||
data.container.height,
|
||||
@ -115,31 +150,99 @@
|
||||
containerMesh.position.set(data.container.length/2, data.container.height/2, data.container.width/2);
|
||||
scene.add(containerMesh);
|
||||
|
||||
// 创建分层控制
|
||||
const layerCheckboxes = document.querySelector('.layer-checkboxes');
|
||||
layerCheckboxes.innerHTML = '';
|
||||
result.layers.forEach((layer, index) => {
|
||||
const div = document.createElement('div');
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = `layer-${index}`;
|
||||
checkbox.checked = true;
|
||||
checkbox.addEventListener('change', updateVisibility);
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.htmlFor = `layer-${index}`;
|
||||
label.textContent = `第${index+1}层 (${layer.count}箱)`;
|
||||
|
||||
div.appendChild(checkbox);
|
||||
div.appendChild(label);
|
||||
layerCheckboxes.appendChild(div);
|
||||
});
|
||||
|
||||
// 初始显示所有层
|
||||
updateVisibility();
|
||||
|
||||
// 添加光源
|
||||
const light = new THREE.DirectionalLight(0xffffff, 1);
|
||||
light.position.set(10000, 10000, 10000);
|
||||
scene.add(light);
|
||||
}
|
||||
|
||||
function updateVisibility() {
|
||||
// 移除现有箱子
|
||||
boxMeshes.forEach(mesh => scene.remove(mesh));
|
||||
boxMeshes = [];
|
||||
|
||||
const boxMat = new THREE.MeshLambertMaterial({
|
||||
color: 0x00ff00,
|
||||
transparent: true,
|
||||
opacity: 0.6
|
||||
});
|
||||
|
||||
result.layout.forEach(pos => {
|
||||
const boxGeo = new THREE.BoxGeometry(
|
||||
data.box.length,
|
||||
data.box.height,
|
||||
data.box.width
|
||||
);
|
||||
const box = new THREE.Mesh(boxGeo, boxMat);
|
||||
box.position.set(
|
||||
pos.x + data.box.length/2,
|
||||
pos.y + data.box.height/2,
|
||||
pos.z + data.box.width/2
|
||||
);
|
||||
scene.add(box);
|
||||
boxMeshes.push(box);
|
||||
});
|
||||
// 根据选中层创建箱子
|
||||
const checkedLayers = Array.from(document.querySelectorAll('.layer-checkboxes input:checked'))
|
||||
.map(cb => parseInt(cb.id.split('-')[1]));
|
||||
|
||||
const light = new THREE.DirectionalLight(0xffffff, 1);
|
||||
light.position.set(10000, 10000, 10000);
|
||||
scene.add(light);
|
||||
checkedLayers.forEach(layerIndex => {
|
||||
const layer = result.layers[layerIndex];
|
||||
layer.layout.forEach(pos => {
|
||||
const boxGeo = new THREE.BoxGeometry(
|
||||
result.boxLength,
|
||||
result.boxHeight,
|
||||
result.boxWidth
|
||||
);
|
||||
const box = new THREE.Mesh(boxGeo, boxMat);
|
||||
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)
|
||||
);
|
||||
box.userData.index = pos.boxNumber;
|
||||
box.on('pointerover', showTooltip);
|
||||
box.on('pointerout', hideTooltip);
|
||||
scene.add(box);
|
||||
boxMeshes.push(box);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function showTooltip(event) {
|
||||
const box = event.target;
|
||||
const position = box.position;
|
||||
const rotation = box.rotation;
|
||||
const dimensions = box.geometry.parameters;
|
||||
|
||||
tooltip.innerHTML = `
|
||||
箱号:${box.userData.index}<br>
|
||||
位置:(${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z.toFixed(0)})<br>
|
||||
尺寸:${dimensions.width}×${dimensions.height}×${dimensions.depth}<br>
|
||||
旋转:X=${(rotation.x * 180/Math.PI).toFixed(0)}°,
|
||||
Y=${(rotation.y * 180/Math.PI).toFixed(0)}°,
|
||||
Z=${(rotation.z * 180/Math.PI).toFixed(0)}°
|
||||
`;
|
||||
tooltip.style.left = `${event.clientX + 10}px`;
|
||||
tooltip.style.top = `${event.clientY - 30}px`;
|
||||
tooltip.style.opacity = 1;
|
||||
}
|
||||
|
||||
function hideTooltip() {
|
||||
tooltip.style.opacity = 0;
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
|
||||
50
main.go
50
main.go
@ -22,6 +22,18 @@ type Placement struct {
|
||||
X, Y, Z float64 `json:"x"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Count int `json:"count"`
|
||||
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() {
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "index.html")
|
||||
@ -34,15 +46,19 @@ func main() {
|
||||
}
|
||||
json.NewDecoder(r.Body).Decode(&data)
|
||||
|
||||
layout := optimizePacking(data.Container, data.Box)
|
||||
layout, bestRotation, strategy, density, spaceUtilization, usedVolume := optimizePacking(data.Container, data.Box)
|
||||
count := len(layout)
|
||||
|
||||
response := struct {
|
||||
Count int `json:"count"`
|
||||
Layout []Placement `json:"layout"`
|
||||
}{
|
||||
Count: count,
|
||||
Layout: layout,
|
||||
response := Response{
|
||||
Count: count,
|
||||
Layout: layout,
|
||||
BoxLength: bestRotation.Length,
|
||||
BoxWidth: bestRotation.Width,
|
||||
BoxHeight: bestRotation.Height,
|
||||
Strategy: strategy,
|
||||
Density: density,
|
||||
SpaceUtilization: spaceUtilization,
|
||||
UsedVolume: usedVolume,
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(response)
|
||||
@ -51,11 +67,17 @@ func main() {
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
||||
|
||||
func optimizePacking(con Container, box Box) []Placement {
|
||||
func optimizePacking(con Container, box Box) ([]Placement, Box, string, float64, float64, float64) {
|
||||
var bestLayout []Placement
|
||||
var bestRotation Box
|
||||
var bestStrategy string
|
||||
maxCount := 0
|
||||
var bestDensity float64
|
||||
var bestSpaceUtilization float64
|
||||
var bestUsedVolume float64
|
||||
|
||||
rotations := generateRotations(box)
|
||||
conVolume := con.Length * con.Width * con.Height
|
||||
|
||||
for _, r := range rotations {
|
||||
for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} {
|
||||
@ -90,13 +112,19 @@ func optimizePacking(con Container, box Box) []Placement {
|
||||
total := int(xCount * yCount * zCount)
|
||||
if total > maxCount && total > 0 {
|
||||
maxCount = total
|
||||
layout := generateLayout(r, xCount, yCount, zCount, strategy)
|
||||
bestLayout = layout
|
||||
bestRotation = r
|
||||
bestStrategy = strategy
|
||||
bestLayout = generateLayout(r, xCount, yCount, zCount, strategy)
|
||||
|
||||
boxVolume := r.Length * r.Width * r.Height
|
||||
bestUsedVolume = float64(total) * boxVolume
|
||||
bestDensity = (bestUsedVolume / conVolume) * 100
|
||||
bestSpaceUtilization = bestDensity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestLayout
|
||||
return bestLayout, bestRotation, bestStrategy, bestDensity, bestSpaceUtilization, bestUsedVolume
|
||||
}
|
||||
|
||||
func generateRotations(box Box) []Box {
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>集装箱装箱计算器</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<style>
|
||||
#container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
#controls {
|
||||
width: 300px;
|
||||
padding: 20px;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.input-group {
|
||||
margin: 10px 0;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
#visualization {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="controls">
|
||||
<h2>集装箱参数</h2>
|
||||
<div class="input-group">
|
||||
<label>长度: <input type="number" id="contLength" step="0.1"></label>
|
||||
<label>宽度: <input type="number" id="contWidth" step="0.1"></label>
|
||||
<label>高度: <input type="number" id="contHeight" step="0.1"></label>
|
||||
<label>承重上限: <input type="number" id="contWeight" step="0.1"></label>
|
||||
</div>
|
||||
|
||||
<h2>纸箱参数</h2>
|
||||
<div class="input-group">
|
||||
<label>长度: <input type="number" id="boxLength" step="0.1"></label>
|
||||
<label>宽度: <input type="number" id="boxWidth" step="0.1"></label>
|
||||
<label>高度: <input type="number" id="boxHeight" step="0.1"></label>
|
||||
<label>重量: <input type="number" id="boxWeight" step="0.1"></label>
|
||||
</div>
|
||||
|
||||
<button onclick="calculate()">开始计算</button>
|
||||
</div>
|
||||
|
||||
<div id="visualization"></div>
|
||||
</div>
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
107
static/main.js
107
static/main.js
@ -1,107 +0,0 @@
|
||||
let scene, camera, renderer, controls;
|
||||
|
||||
function initThree() {
|
||||
// 初始化场景
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(75,
|
||||
window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(800, 600);
|
||||
document.getElementById('visualization').appendChild(renderer.domElement);
|
||||
|
||||
// 添加光源
|
||||
const light = new THREE.AmbientLight(0xffffff, 0.8);
|
||||
scene.add(light);
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
|
||||
directionalLight.position.set(0, 1, 1);
|
||||
scene.add(directionalLight);
|
||||
|
||||
// 设置相机位置
|
||||
camera.position.set(10, 10, 10);
|
||||
camera.lookAt(0, 0, 0);
|
||||
|
||||
// 添加轨道控制器
|
||||
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||
}
|
||||
|
||||
function clearScene() {
|
||||
while(scene.children.length > 0){
|
||||
scene.remove(scene.children[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function renderContainer(container) {
|
||||
// 绘制集装箱线框
|
||||
const geometry = new THREE.BoxGeometry(
|
||||
container.Length,
|
||||
container.Width,
|
||||
container.Height
|
||||
);
|
||||
const edges = new THREE.EdgesGeometry(geometry);
|
||||
const line = new THREE.LineSegments(
|
||||
edges,
|
||||
new THREE.LineBasicMaterial({ color: 0x000000 })
|
||||
);
|
||||
scene.add(line);
|
||||
}
|
||||
|
||||
function renderBoxes(placements) {
|
||||
placements.forEach(pos => {
|
||||
const geometry = new THREE.BoxGeometry(pos.Length, pos.Width, pos.Height);
|
||||
const material = new THREE.MeshPhongMaterial({
|
||||
color: 0x00ff00,
|
||||
transparent: true,
|
||||
opacity: 0.7
|
||||
});
|
||||
const cube = new THREE.Mesh(geometry, material);
|
||||
cube.position.set(
|
||||
pos.X + pos.Length/2,
|
||||
pos.Y + pos.Width/2,
|
||||
pos.Z + pos.Height/2
|
||||
);
|
||||
scene.add(cube);
|
||||
});
|
||||
}
|
||||
|
||||
async function calculate() {
|
||||
// 获取输入值
|
||||
const container = {
|
||||
Length: parseFloat(document.getElementById('contLength').value),
|
||||
Width: parseFloat(document.getElementById('contWidth').value),
|
||||
Height: parseFloat(document.getElementById('contHeight').value),
|
||||
MaxWeight: parseFloat(document.getElementById('contWeight').value)
|
||||
};
|
||||
|
||||
const box = {
|
||||
Length: parseFloat(document.getElementById('boxLength').value),
|
||||
Width: parseFloat(document.getElementById('boxWidth').value),
|
||||
Height: parseFloat(document.getElementById('boxHeight').value),
|
||||
Weight: parseFloat(document.getElementById('boxWeight').value)
|
||||
};
|
||||
|
||||
// 发送请求
|
||||
const response = await fetch('/api/calculate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ container, box })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// 更新可视化
|
||||
clearScene();
|
||||
renderContainer(container);
|
||||
renderBoxes(result.placements);
|
||||
}
|
||||
|
||||
// 初始化
|
||||
initThree();
|
||||
animate();
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
</h1>
|
||||
<p>Sorry, the page you are looking for does not exist.</p>
|
||||
<a href="/">Go back to the homepage</a>
|
||||
</div>
|
||||
@ -1,196 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>装货方案计算</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-100">
|
||||
<div class="container mx-auto p-4">
|
||||
<h1 class="text-3xl font-bold text-center text-blue-600 mb-8">装货方案计算</h1>
|
||||
<div class="bg-white p-6 rounded-md shadow-md">
|
||||
<h2 class="text-xl font-bold mb-4">输入纸箱信息</h2>
|
||||
<div id="cartons" class="mb-4">
|
||||
<div class="flex mb-2">
|
||||
<input type="number" placeholder="长" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="宽" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="高" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="重量" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<button onclick="addCartonInput()" class="bg-blue-500 text-white p-2 rounded-md hover:bg-blue-600">添加纸箱</button>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="text-xl font-bold mb-4">输入集装箱信息</h2>
|
||||
<div id="containers" class="mb-4">
|
||||
<div class="flex mb-2">
|
||||
<input type="number" placeholder="长" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="宽" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="高" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="最大载重" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<button onclick="addContainerInput()" class="bg-blue-500 text-white p-2 rounded-md hover:bg-blue-600">添加集装箱</button>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="calculate()" class="bg-green-500 text-white p-2 rounded-md hover:bg-green-600">计算最优方案</button>
|
||||
</div>
|
||||
<div id="result" class="mt-8 bg-white p-6 rounded-md shadow-md"></div>
|
||||
<div class="mt-8 bg-white p-6 rounded-md shadow-md">
|
||||
<h3 class="text-xl font-bold mb-4">3D摆放视图</h3>
|
||||
<div id="3d-view"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function addCartonInput() {
|
||||
const cartonsDiv = document.getElementById('cartons');
|
||||
const newCarton = document.createElement('div');
|
||||
newCarton.classList.add('flex', 'mb-2');
|
||||
newCarton.innerHTML = `
|
||||
<input type="number" placeholder="长" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="宽" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="高" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="重量" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
`;
|
||||
cartonsDiv.appendChild(newCarton);
|
||||
}
|
||||
|
||||
function addContainerInput() {
|
||||
const containersDiv = document.getElementById('containers');
|
||||
const newContainer = document.createElement('div');
|
||||
newContainer.classList.add('flex', 'mb-2');
|
||||
newContainer.innerHTML = `
|
||||
<input type="number" placeholder="长" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="宽" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="高" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
<input type="number" placeholder="最大载重" class="border border-gray-300 p-2 mr-2 w-1/4 rounded-md">
|
||||
`;
|
||||
containersDiv.appendChild(newContainer);
|
||||
}
|
||||
|
||||
function calculate() {
|
||||
const cartonsInputs = document.querySelectorAll('#cartons input');
|
||||
const containersInputs = document.querySelectorAll('#containers input');
|
||||
|
||||
let cartons = [];
|
||||
for (let i = 0; i < cartonsInputs.length; i += 4) {
|
||||
const length = parseFloat(cartonsInputs[i].value);
|
||||
const width = parseFloat(cartonsInputs[i + 1].value);
|
||||
const height = parseFloat(cartonsInputs[i + 2].value);
|
||||
const weight = parseFloat(cartonsInputs[i + 3].value);
|
||||
if (!isNaN(length) && !isNaN(width) && !isNaN(height) && !isNaN(weight)) {
|
||||
cartons.push({ length, width, height, weight });
|
||||
}
|
||||
}
|
||||
|
||||
let containers = [];
|
||||
for (let i = 0; i < containersInputs.length; i += 4) {
|
||||
const length = parseFloat(containersInputs[i].value);
|
||||
const width = parseFloat(containersInputs[i + 1].value);
|
||||
const height = parseFloat(containersInputs[i + 2].value);
|
||||
const maxWeight = parseFloat(containersInputs[i + 3].value);
|
||||
if (!isNaN(length) && !isNaN(width) && !isNaN(height) && !isNaN(maxWeight)) {
|
||||
containers.push({ length, width, height, maxWeight });
|
||||
}
|
||||
}
|
||||
|
||||
fetch('/calculate', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ cartons, containers })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const resultDiv = document.getElementById('result');
|
||||
resultDiv.innerHTML = '';
|
||||
data.forEach((container, index) => {
|
||||
const containerDiv = document.createElement('div');
|
||||
containerDiv.classList.add('border', 'border-gray-300', 'p-4', 'mb-4', 'rounded-md');
|
||||
containerDiv.innerHTML = `
|
||||
<h3 class="text-lg font-bold">集装箱 ${index + 1}</h3>
|
||||
<p>当前重量: ${container.currentWeight}</p>
|
||||
<h4 class="text-md font-bold">装入的纸箱:</h4>
|
||||
<ul>
|
||||
${container.cartons.map(carton => `<li>长: ${carton.length}, 宽: ${carton.width}, 高: ${carton.height}, 重量: ${carton.weight}</li>`).join('')}
|
||||
</ul>
|
||||
`;
|
||||
resultDiv.appendChild(containerDiv);
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<script>
|
||||
let scene, camera, renderer;
|
||||
let containerGroup;
|
||||
|
||||
function initThree() {
|
||||
scene = new THREE.Scene();
|
||||
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(800, 500);
|
||||
document.getElementById('3d-view').appendChild(renderer.domElement);
|
||||
|
||||
// 灯光设置
|
||||
const light = new THREE.DirectionalLight(0xffffff, 1);
|
||||
light.position.set(10, 10, 10);
|
||||
scene.add(light);
|
||||
scene.add(new THREE.AmbientLight(0x404040));
|
||||
|
||||
camera.position.z = 15;
|
||||
camera.position.y = 10;
|
||||
camera.lookAt(0, 0, 0);
|
||||
}
|
||||
|
||||
function renderContainer(container) {
|
||||
if(containerGroup) scene.remove(containerGroup);
|
||||
containerGroup = new THREE.Group();
|
||||
|
||||
// 绘制集装箱
|
||||
const geometry = new THREE.BoxGeometry(
|
||||
container.length,
|
||||
container.height,
|
||||
container.width
|
||||
);
|
||||
const edges = new THREE.EdgesGeometry(geometry);
|
||||
const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x000000 }));
|
||||
containerGroup.add(line);
|
||||
|
||||
// 绘制纸箱
|
||||
container.cartons.forEach(c => {
|
||||
const box = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(c.length, c.height, c.width),
|
||||
new THREE.MeshPhongMaterial({ color: 0x2194f3 })
|
||||
);
|
||||
box.position.set(c.position[0], c.position[1], c.position[2]);
|
||||
containerGroup.add(box);
|
||||
});
|
||||
|
||||
scene.add(containerGroup);
|
||||
stopAnimation();
|
||||
animate();
|
||||
}
|
||||
|
||||
let animationId;
|
||||
function animate() {
|
||||
animationId = requestAnimationFrame(animate);
|
||||
renderer.render(scene, camera);
|
||||
containerGroup.rotation.y += 0.005;
|
||||
}
|
||||
function stopAnimation() {
|
||||
if(animationId) cancelAnimationFrame(animationId);
|
||||
}
|
||||
|
||||
// 初始化3D场景
|
||||
window.addEventListener('load', initThree);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1 +0,0 @@
|
||||
login
|
||||
Loading…
x
Reference in New Issue
Block a user