Initial commit
This commit is contained in:
commit
d596db7e29
BIN
__debug_bin1038044772.exe
Normal file
BIN
__debug_bin1038044772.exe
Normal file
Binary file not shown.
BIN
__debug_bin3681850586.exe
Normal file
BIN
__debug_bin3681850586.exe
Normal file
Binary file not shown.
33
go.mod
Normal file
33
go.mod
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
module container-packing
|
||||||
|
|
||||||
|
go 1.23.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/bytedance/sonic v1.11.6 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/gin-gonic/gin v1.10.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/crypto v0.23.0 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.20.0 // indirect
|
||||||
|
golang.org/x/text v0.15.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
79
go.sum
Normal file
79
go.sum
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||||
|
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
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/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
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/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
166
index.html
Normal file
166
index.html
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>集装箱装箱优化系统</title>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
|
||||||
|
<style>
|
||||||
|
body { margin: 0; }
|
||||||
|
#container { width: 100vw; height: 100vh; }
|
||||||
|
#inputPanel {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
background: rgba(255,255,255,0.8);
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
#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; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="inputPanel">
|
||||||
|
<h3>参数输入</h3>
|
||||||
|
<div>
|
||||||
|
集装箱尺寸(mm):<br>
|
||||||
|
长:<input type="number" id="conLen" value="12014"><br>
|
||||||
|
宽:<input type="number" id="conWid" value="2337"><br>
|
||||||
|
高:<input type="number" id="conHei" value="2388"><br>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
纸箱尺寸(mm):<br>
|
||||||
|
长:<input type="number" id="boxLen" value="685"><br>
|
||||||
|
宽:<input type="number" id="boxWid" value="548"><br>
|
||||||
|
高:<input type="number" id="boxHei" value="489"><br>
|
||||||
|
</div>
|
||||||
|
<button onclick="calculate()">开始计算</button>
|
||||||
|
<div id="result"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="axisInfo" class="axis">视角:前视图</div>
|
||||||
|
<div id="container"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let scene, camera, renderer, controls;
|
||||||
|
let containerMesh, boxMeshes = [];
|
||||||
|
let activeCamera = 'front';
|
||||||
|
|
||||||
|
function initThree() {
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 1, 100000);
|
||||||
|
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||||
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
document.getElementById('container').appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||||
|
camera.position.set(15000, 5000, 15000);
|
||||||
|
controls.update();
|
||||||
|
|
||||||
|
const gridHelper = new THREE.GridHelper(20000, 20, 0x888888, 0x888888);
|
||||||
|
scene.add(gridHelper);
|
||||||
|
|
||||||
|
const axesHelper = new THREE.AxesHelper(5000);
|
||||||
|
scene.add(axesHelper);
|
||||||
|
|
||||||
|
animate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
controls.update();
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function calculate() {
|
||||||
|
const data = {
|
||||||
|
container: {
|
||||||
|
length: parseFloat(document.getElementById('conLen').value),
|
||||||
|
width: parseFloat(document.getElementById('conWid').value),
|
||||||
|
height: parseFloat(document.getElementById('conHei').value)
|
||||||
|
},
|
||||||
|
box: {
|
||||||
|
length: parseFloat(document.getElementById('boxLen').value),
|
||||||
|
width: parseFloat(document.getElementById('boxWid').value),
|
||||||
|
height: parseFloat(document.getElementById('boxHei').value)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch('/calculate', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
document.getElementById('result').innerHTML = `最优装箱数:${result.count}`;
|
||||||
|
|
||||||
|
scene.remove(containerMesh);
|
||||||
|
boxMeshes.forEach(mesh => scene.remove(mesh));
|
||||||
|
boxMeshes = [];
|
||||||
|
|
||||||
|
const containerGeo = new THREE.BoxGeometry(
|
||||||
|
data.container.length,
|
||||||
|
data.container.height,
|
||||||
|
data.container.width
|
||||||
|
);
|
||||||
|
const containerMat = new THREE.MeshBasicMaterial({
|
||||||
|
color: 0x333333,
|
||||||
|
wireframe: true,
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.3
|
||||||
|
});
|
||||||
|
containerMesh = new THREE.Mesh(containerGeo, containerMat);
|
||||||
|
containerMesh.position.set(data.container.length/2, data.container.height/2, data.container.width/2);
|
||||||
|
scene.add(containerMesh);
|
||||||
|
|
||||||
|
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 light = new THREE.DirectionalLight(0xffffff, 1);
|
||||||
|
light.position.set(10000, 10000, 10000);
|
||||||
|
scene.add(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('keydown', (e) => {
|
||||||
|
switch(e.key) {
|
||||||
|
case '1':
|
||||||
|
camera.position.set(15000, 5000, 15000);
|
||||||
|
activeCamera = 'front';
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
camera.position.set(-15000, 5000, 15000);
|
||||||
|
activeCamera = 'back';
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
camera.position.set(0, 15000, 0);
|
||||||
|
activeCamera = 'top';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
document.getElementById('axisInfo').innerHTML = `视角:${activeCamera}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
initThree();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
190
main.go
Normal file
190
main.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Container struct {
|
||||||
|
Length float64 `json:"length"`
|
||||||
|
Width float64 `json:"width"`
|
||||||
|
Height float64 `json:"height"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Box struct {
|
||||||
|
Length float64 `json:"length"`
|
||||||
|
Width float64 `json:"width"`
|
||||||
|
Height float64 `json:"height"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Placement struct {
|
||||||
|
X, Y, Z float64 `json:"x"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 := optimizePacking(data.Container, data.Box)
|
||||||
|
count := len(layout)
|
||||||
|
|
||||||
|
response := struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
Layout []Placement `json:"layout"`
|
||||||
|
}{
|
||||||
|
Count: count,
|
||||||
|
Layout: layout,
|
||||||
|
}
|
||||||
|
|
||||||
|
json.NewEncoder(w).Encode(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func optimizePacking(con Container, box Box) []Placement {
|
||||||
|
var bestLayout []Placement
|
||||||
|
maxCount := 0
|
||||||
|
|
||||||
|
rotations := generateRotations(box)
|
||||||
|
|
||||||
|
for _, r := range rotations {
|
||||||
|
for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} {
|
||||||
|
var xCount, yCount, zCount float64
|
||||||
|
switch strategy {
|
||||||
|
case "XY":
|
||||||
|
xCount = math.Floor(con.Length / r.Length)
|
||||||
|
yCount = math.Floor(con.Width / r.Width)
|
||||||
|
zCount = math.Floor(con.Height / r.Height)
|
||||||
|
case "XZ":
|
||||||
|
xCount = math.Floor(con.Length / r.Length)
|
||||||
|
zCount = math.Floor(con.Height / r.Height)
|
||||||
|
yCount = math.Floor(con.Width / r.Width)
|
||||||
|
case "YX":
|
||||||
|
yCount = math.Floor(con.Width / r.Length)
|
||||||
|
xCount = math.Floor(con.Length / r.Width)
|
||||||
|
zCount = math.Floor(con.Height / r.Height)
|
||||||
|
case "YZ":
|
||||||
|
yCount = math.Floor(con.Width / r.Length)
|
||||||
|
zCount = math.Floor(con.Height / r.Height)
|
||||||
|
xCount = math.Floor(con.Length / r.Width)
|
||||||
|
case "ZX":
|
||||||
|
zCount = math.Floor(con.Height / r.Length)
|
||||||
|
xCount = math.Floor(con.Length / r.Width)
|
||||||
|
yCount = math.Floor(con.Width / r.Height)
|
||||||
|
case "ZY":
|
||||||
|
zCount = math.Floor(con.Height / r.Length)
|
||||||
|
yCount = math.Floor(con.Width / r.Height)
|
||||||
|
xCount = math.Floor(con.Length / r.Width)
|
||||||
|
}
|
||||||
|
|
||||||
|
total := int(xCount * yCount * zCount)
|
||||||
|
if total > maxCount && total > 0 {
|
||||||
|
maxCount = total
|
||||||
|
layout := generateLayout(r, xCount, yCount, zCount, strategy)
|
||||||
|
bestLayout = layout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRotations(box Box) []Box {
|
||||||
|
return []Box{
|
||||||
|
{box.Length, box.Width, box.Height},
|
||||||
|
{box.Length, box.Height, box.Width},
|
||||||
|
{box.Width, box.Length, box.Height},
|
||||||
|
{box.Width, box.Height, box.Length},
|
||||||
|
{box.Height, box.Length, box.Width},
|
||||||
|
{box.Height, box.Width, box.Length},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Placement {
|
||||||
|
var layout []Placement
|
||||||
|
switch strategy {
|
||||||
|
case "XY":
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Length,
|
||||||
|
Y: z * r.Height,
|
||||||
|
Z: y * r.Width,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "XZ":
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Length,
|
||||||
|
Y: z * r.Height,
|
||||||
|
Z: y * r.Width,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "YX":
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Width,
|
||||||
|
Y: z * r.Height,
|
||||||
|
Z: y * r.Length,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "YZ":
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Width,
|
||||||
|
Y: z * r.Height,
|
||||||
|
Z: y * r.Length,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "ZX":
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Width,
|
||||||
|
Y: z * r.Length,
|
||||||
|
Z: y * r.Height,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "ZY":
|
||||||
|
for z := 0.0; z < zCount; z++ {
|
||||||
|
for y := 0.0; y < yCount; y++ {
|
||||||
|
for x := 0.0; x < xCount; x++ {
|
||||||
|
layout = append(layout, Placement{
|
||||||
|
X: x * r.Width,
|
||||||
|
Y: z * r.Length,
|
||||||
|
Z: y * r.Height,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return layout
|
||||||
|
}
|
||||||
66
static/index.html
Normal file
66
static/index.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<!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
Normal file
107
static/main.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
4
templates/404.html
Normal file
4
templates/404.html
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
</h1>
|
||||||
|
<p>Sorry, the page you are looking for does not exist.</p>
|
||||||
|
<a href="/">Go back to the homepage</a>
|
||||||
|
</div>
|
||||||
196
templates/index.html
Normal file
196
templates/index.html
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
<!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
templates/login.html
Normal file
1
templates/login.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
login
|
||||||
Loading…
x
Reference in New Issue
Block a user