diff --git a/__debug_bin1826320692.exe b/__debug_bin1826320692.exe new file mode 100644 index 0000000..ec6acd6 Binary files /dev/null and b/__debug_bin1826320692.exe differ diff --git a/container-packing.exe b/container-packing.exe new file mode 100644 index 0000000..54a285e Binary files /dev/null and b/container-packing.exe differ diff --git a/go.mod b/go.mod index f955d9e..42c168c 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,8 @@ require ( 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 + github.com/vugu/vugu v0.4.0 // indirect + github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019 // 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 diff --git a/go.sum b/go.sum index b657a9f..21d5cf7 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,10 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS 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= +github.com/vugu/vugu v0.4.0 h1:ijU94l+qELec5f+Bb9R8m4fvZkhm4sKhawfmQVCV9a8= +github.com/vugu/vugu v0.4.0/go.mod h1:JU3YFROwFOqodkf1q8c1IRcx92j/dq258cqpaCsDlM8= +github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019 h1:8NGiD5gWbVGObr+lnqcbM2rcOQBO6mr+m19BIblCdho= +github.com/vugu/xxhash v0.0.0-20191111030615-ed24d0179019/go.mod h1:PrBK6+LJXwb+3EnJTHo43Uh4FhjFFwvN4jKk4Zc5zZ8= 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= diff --git a/index.html b/index.html index eb471f4..c1dff30 100644 --- a/index.html +++ b/index.html @@ -28,6 +28,8 @@ transition: opacity 0.3s; } .layer-checkbox { margin-bottom: 10px; } + #weightLimit { margin-top: 10px; } + .layer-checkboxes { margin-top: 20px; } @@ -38,22 +40,22 @@ 长:
宽:
高:
+ 承重上限(kg):
纸箱尺寸(mm):
长:
宽:
高:
+ 重量(kg):
-
视角:前视图
- \ No newline at end of file diff --git a/main.go b/main.go index d81a016..f7cc335 100644 --- a/main.go +++ b/main.go @@ -2,36 +2,36 @@ package main import ( "encoding/json" + "fmt" "math" "net/http" ) type Container struct { - Length float64 `json:"length"` - Width float64 `json:"width"` - Height float64 `json:"height"` + 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, Y, Z float64 `json:"x"` + X, Y, Z float64 `json:"x"` + RotationX float64 `json:"rotationX"` + RotationY float64 `json:"rotationY"` + RotationZ float64 `json:"rotationZ"` + BoxNumber int `json:"boxNumber"` } -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"` +type Layer struct { + Count int `json:"count"` + Layout []Placement `json:"layout"` } func main() { @@ -46,19 +46,43 @@ func main() { } json.NewDecoder(r.Body).Decode(&data) - layout, bestRotation, strategy, density, spaceUtilization, usedVolume := optimizePacking(data.Container, data.Box) - count := len(layout) + layout, strategy, count := optimizePacking(data.Container, data.Box) - response := Response{ + 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 + 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, - Layout: layout, - BoxLength: bestRotation.Length, - BoxWidth: bestRotation.Width, - BoxHeight: bestRotation.Height, + Layers: layers, Strategy: strategy, - Density: density, - SpaceUtilization: spaceUtilization, - UsedVolume: usedVolume, + Density: calculateDensity(data.Container, data.Box, count), + SpaceUtilization: calculateSpaceUtilization(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) @@ -67,17 +91,17 @@ func main() { http.ListenAndServe(":8080", nil) } -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 +func optimizePacking(con Container, box Box) ([]Placement, string, int) { + rotations := generateRotations(con, box) - rotations := generateRotations(box) - conVolume := con.Length * con.Width * con.Height + type candidate struct { + layout []Placement + count int + weight float64 + strategy string + } + + var candidates []candidate for _, r := range rotations { for _, strategy := range []string{"XY", "XZ", "YX", "YZ", "ZX", "ZY"} { @@ -110,32 +134,56 @@ func optimizePacking(con Container, box Box) ([]Placement, Box, string, float64, } total := int(xCount * yCount * zCount) - if total > maxCount && total > 0 { - maxCount = total - bestRotation = r - bestStrategy = strategy - bestLayout = generateLayout(r, xCount, yCount, zCount, strategy) + totalWeight := float64(total) * box.Weight - boxVolume := r.Length * r.Width * r.Height - bestUsedVolume = float64(total) * boxVolume - bestDensity = (bestUsedVolume / conVolume) * 100 - bestSpaceUtilization = bestDensity + if total > 0 { + fmt.Printf("Rotation: %v | Strategy: %s | Total: %d | Weight: %.2f kg\n", r, strategy, total, totalWeight) + candidates = append(candidates, candidate{ + layout: generateLayout(r, xCount, yCount, zCount, strategy), + count: total, + weight: totalWeight, + strategy: strategy, + }) } } } - return bestLayout, bestRotation, bestStrategy, bestDensity, bestSpaceUtilization, bestUsedVolume + maxCountUnderLimit := 0 + var finalLayout []Placement + var finalStrategy string + + for _, c := range candidates { + if c.count > maxCountUnderLimit && c.weight <= con.WeightLimit { + maxCountUnderLimit = c.count + finalLayout = c.layout + finalStrategy = c.strategy + } + } + + if maxCountUnderLimit == 0 { + return candidates[0].layout, candidates[0].strategy, candidates[0].count + } + + return finalLayout, finalStrategy, maxCountUnderLimit } -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 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 { @@ -146,9 +194,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Length, + Y: z * r.Height, + Z: y * r.Width, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } @@ -158,9 +209,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Length, + Y: z * r.Height, + Z: y * r.Width, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } @@ -170,9 +224,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Width, + Y: z * r.Height, + Z: y * r.Length, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } @@ -182,9 +239,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Width, + Y: z * r.Height, + Z: y * r.Length, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } @@ -194,9 +254,12 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Width, + Y: z * r.Length, + Z: y * r.Height, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } @@ -206,13 +269,28 @@ func generateLayout(r Box, xCount, yCount, zCount float64, strategy string) []Pl 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, + X: x * r.Width, + Y: z * r.Length, + Z: y * r.Height, + RotationX: 0.0, + RotationY: 0.0, + RotationZ: 0.0, }) } } } + 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 +} + +func calculateSpaceUtilization(con Container, box Box, count int) float64 { + return calculateDensity(con, box, count) +}