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 }