stream_app/main.go
2025-04-23 13:08:05 +08:00

305 lines
9.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"encoding/json"
"fmt"
"math"
"net/http"
)
type Container struct {
Length float64 `json:"length"`
Width float64 `json:"width"`
Height float64 `json:"height"`
WeightLimit float64 `json:"weightLimit"`
}
type Box struct {
Length float64 `json:"length"`
Width float64 `json:"width"`
Height float64 `json:"height"`
Weight float64 `json:"weight"`
}
type Placement struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
RotationX float64 `json:"rotationX"`
RotationY float64 `json:"rotationY"`
RotationZ float64 `json:"rotationZ"`
BoxNumber int `json:"boxNumber"`
}
type Layer struct {
Count int `json:"count"`
Layout []Placement `json:"layout"`
}
func main() {
fmt.Println("集装箱装箱系统已启动,监听端口 :8080")
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"`
}
err := json.NewDecoder(r.Body).Decode(&data)
if err != nil {
http.Error(w, "参数解析失败", http.StatusBadRequest)
fmt.Printf("⚠️ 错误:参数解析失败 - %v\n", err)
return
}
fmt.Printf("🚀 收到请求:\n集装箱参数长%fmm × 宽%fmm × 高%fmm承重%fkg\n纸箱参数长%fmm × 宽%fmm × 高%fmm重量%fkg\n",
data.Container.Length, data.Container.Width, data.Container.Height, data.Container.WeightLimit,
data.Box.Length, data.Box.Width, data.Box.Height, data.Box.Weight)
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 {
layers = append(layers, Layer{
Count: len(layer),
Layout: layer,
})
}
response := struct {
Count int `json:"count"`
Layers []Layer `json:"layers"`
Strategy string `json:"strategy"`
SpaceUtilization float64 `json:"spaceUtilization"`
TotalWeight float64 `json:"totalWeight"`
BoxLength float64 `json:"boxLength"`
BoxWidth float64 `json:"boxWidth"`
BoxHeight float64 `json:"boxHeight"`
}{
Count: count,
Layers: layers,
Strategy: strategy,
SpaceUtilization: calculateDensity(data.Container, data.Box, count),
TotalWeight: float64(count) * data.Box.Weight,
BoxLength: data.Box.Length,
BoxWidth: data.Box.Width,
BoxHeight: data.Box.Height,
}
json.NewEncoder(w).Encode(response)
fmt.Printf("✅ 返回结果:\n最优装箱数%d\n策略%s\n空间利用率%.2f%%\n", count, strategy, response.SpaceUtilization)
})
http.ListenAndServe(":8080", nil)
}
func optimizePacking(con Container, box Box) ([]Placement, string, int) {
fmt.Printf("📦 开始装箱优化\n容器尺寸长%fmm × 宽%fmm × 高%fmm\n纸箱尺寸长%fmm × 宽%fmm × 高%fmm\n",
con.Length, con.Width, con.Height, box.Length, box.Width, box.Height)
rotations := generateRotations(con, box)
fmt.Printf("🔧 生成有效旋转方式:共%d种\n", len(rotations))
type candidate struct {
layout []Placement
count int
strategy string
}
var candidates []candidate
for _, r := range rotations {
fmt.Printf("正在尝试旋转方式:%f×%f×%f\n", r.Length, r.Width, r.Height)
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)
}
totalByVolume := int(xCount * yCount * zCount)
maxCountByWeight := int(math.Floor(con.WeightLimit / box.Weight))
actualCount := totalByVolume
if actualCount > maxCountByWeight {
actualCount = maxCountByWeight
}
if actualCount > 0 {
layout := generateLayout(r, xCount, yCount, zCount, strategy)
candidates = append(candidates, candidate{
layout: layout[:actualCount],
count: actualCount,
strategy: strategy,
})
fmt.Printf("💡 新增方案:策略[%s] 可装载%d箱尺寸%dx%dx%d\n",
strategy, actualCount, xCount, yCount, zCount)
}
}
}
if len(candidates) == 0 {
fmt.Printf("❗️ 未找到有效装箱方案\n")
return nil, "", 0
}
maxCount := 0
var finalLayout []Placement
var finalStrategy string
for _, c := range candidates {
if c.count > maxCount {
maxCount = c.count
finalLayout = c.layout
finalStrategy = c.strategy
}
}
fmt.Printf("🏆 最优方案:策略[%s] 可装载%d箱\n", finalStrategy, maxCount)
return finalLayout, finalStrategy, maxCount
}
func generateRotations(con Container, box Box) []Box {
validRotations := make([]Box, 0)
rotations := []Box{
{Length: box.Length, Width: box.Width, Height: box.Height, Weight: box.Weight},
{Length: box.Length, Width: box.Height, Height: box.Width, Weight: box.Weight},
{Length: box.Width, Width: box.Length, Height: box.Height, Weight: box.Weight},
{Length: box.Width, Width: box.Height, Height: box.Length, Weight: box.Weight},
{Length: box.Height, Width: box.Length, Height: box.Width, Weight: box.Weight},
{Length: box.Height, Width: box.Width, Height: box.Length, Weight: box.Weight},
}
for _, r := range rotations {
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 {
fmt.Printf("正在生成布局:策略[%s](尺寸:%dx%dx%d\n", strategy, xCount, yCount, zCount)
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: y * r.Width,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
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: y * r.Width,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
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: y * r.Length,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
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: y * r.Length,
Z: z * r.Height,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
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: y * r.Height,
Z: z * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
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: y * r.Height,
Z: z * r.Length,
RotationX: 0.0,
RotationY: 0.0,
RotationZ: 0.0,
BoxNumber: len(layout),
})
}
}
}
default:
fmt.Printf("❗️ 无效策略:%s\n", strategy)
}
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
density := (boxVolume / containerVolume) * 100
fmt.Printf("📊 体积利用率计算:%.2f%%(箱子总容积%fmm³ / 集装箱容积%fmm³\n",
density, boxVolume, containerVolume)
return density
}