stream_app/main.go
2025-04-22 18:59:06 +08:00

286 lines
7.7 KiB
Go

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() {
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 {
layers = append(layers, Layer{
Count: len(layer),
Layout: layer,
})
}
response := struct {
Count int `json:"count"`
Layers []Layer `json:"layers"`
Strategy string `json:"strategy"`
Density float64 `json:"density"`
SpaceUtilization float64 `json:"spaceUtilization"`
UsedVolume float64 `json:"usedVolume"`
TotalWeight float64 `json:"totalWeight"`
BoxLength float64 `json:"boxLength"`
BoxWidth float64 `json:"boxWidth"`
BoxHeight float64 `json:"boxHeight"`
}{
Count: count,
Layers: layers,
Strategy: strategy,
Density: calculateDensity(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
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 {
candidates = append(candidates, candidate{
layout: generateLayout(r, xCount, yCount, zCount, strategy)[:actualCount],
count: actualCount,
strategy: strategy,
})
}
}
}
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
finalLayout = c.layout
finalStrategy = c.strategy
}
}
return finalLayout, finalStrategy, maxCount
}
func generateRotations(con Container, box Box) []Box {
validRotations := make([]Box, 0)
for _, r := range []Box{
{box.Length, box.Width, box.Height, box.Weight},
{box.Length, box.Height, box.Width, box.Weight},
{box.Width, box.Length, box.Height, box.Weight},
{box.Width, box.Height, box.Length, box.Weight},
{box.Height, box.Length, box.Width, box.Weight},
{box.Height, box.Width, box.Length, box.Weight},
} {
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 {
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.Println("无效排列策略")
}
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
return (boxVolume / containerVolume) * 100
}