编辑代码

# coding:utf-8
#JSRUN引擎2.0,支持多达30种语言在线运行,全仿真在线交互输入输出。 
import math
import matplotlib.pyplot as plt
import matplotlib.patches as patches

# 工件类(增加旋转功能)
class Piece:
    def __init__(self, id, width, height, quantity):
        self.id = id
        self.width = width
        self.height = height
        self.quantity = quantity
        self.rotated = False  # 是否旋转90°

    def get_dim(self):
        return (self.height, self.width) if self.rotated else (self.width, self.height)

# 板材类(增加边距和间距约束)
class Plate:
    def __init__(self, id, width, height):
        self.id = id
        self.width = width - 20  # 左右各10mm边距
        self.height = height - 20  # 上下各10mm边距
        self.pieces = []  # 存储工件及坐标 (piece, x, y, rotated)
        self.used_width = 0  # 当前行已用宽度
        self.current_y = 10  # 当前行Y坐标(已预留上边距)

    def can_place(self, piece, x, y):
        w, h = piece.get_dim()
        # 检查横向边界和行内间距
        if x + w > self.width + 10: return False  # 行内最大宽度+间距
        if y + h > self.height + 10: return False  # 纵向边界
        # 检查与已放置工件的间距(简化为行内左右间距)
        if self.pieces:
            last_x, last_w = self.pieces[-1][1], self.pieces[-1][2]
            if x < last_x + last_w + 10: return False  # 横向间距<10mm
        return True

    def place_piece(self, piece, rotate=False):
        if piece.quantity <= 0: return False
        piece.rotated = rotate
        w, h = piece.get_dim()
        # 换行判断
        if self.used_width + w + 10 > self.width:  # +10为行内间距
            self.current_y += h + 10  # 换行,预留行间距
            self.used_width = 0
        x = self.used_width + 10  # 行内起始X(含间距)
        y = self.current_y
        if self.can_place(piece, x, y):
            self.pieces.append((piece, x, h, y))  # 存储(x, 宽度, 高度, y)
            self.used_width += w + 10  # 更新行内已用宽度(含间距)
            piece.quantity -= 1
            return True
        return False

# 创建工件列表(10种,数量调整为测试值)
pieces = [    Piece(1, 101.5, 72.5, 5),   # 小尺寸
    Piece(2, 420, 250, 5),     # 中尺寸
    Piece(3, 180, 125, 5),     # 中小尺寸
    Piece(4, 157.1, 100, 5),   # 中小尺寸
    Piece(5, 388.5, 195, 5),   # 中尺寸
    Piece(6, 778, 126, 5),     # 长条形
    Piece(7, 300, 300, 5),     # 方形
    Piece(8, 2323.56, 240.54, 3),  # 大长条形
    Piece(9, 680, 680, 3),     # 大方形
    Piece(10, 130, 80, 5),     # 小尺寸
]

# 创建板材列表(按题目修正尺寸)
plates = [    Plate('A', 8000, 3000),  # 8000×3000(用户指定尺寸)
    Plate('B', 6000, 2000),
    Plate('C', 7000, 2500),
]

# 分组策略:按尺寸降序,每个板材至少4种工件
sorted_pieces = sorted(pieces, key=lambda p: p.width*p.height, reverse=True)
group_idx = [0, 5, 9]  # 分组索引(示例:A[0-4], B[5-8], C[9-])

# 填充板材A(大尺寸为主,至少4种)
plate = plates[0]
for p in sorted_pieces[:5]:  # 前5种(包含≥4种)
    while p.quantity > 0:
        # 尝试不旋转放置
        if not plate.place_piece(p):
            # 尝试旋转
            if not plate.place_piece(p, rotate=True):
                break  # 无法放置,跳过

# 填充板材B(中尺寸,至少4种)
plate = plates[1]
for p in sorted_pieces[5:9]:  # 中间4种
    while p.quantity > 0:
        if not plate.place_piece(p):
            if not plate.place_piece(p, rotate=True):
                break

# 填充板材C(剩余工件,至少4种:可能包含小尺寸和未分完的)
plate = plates[2]
for p in sorted_pieces[9:] + sorted_pieces[:5][:1]:  # 补充1种大尺寸确保≥4种
    while p.quantity > 0:
        if not plate.place_piece(p):
            if not plate.place_piece(p, rotate=True):
                break

# 可视化函数
def visualize_plate(plate):
    fig, ax = plt.subplots(figsize=(8, 4))
    ax.set_xlim(0, plate.width + 20)  # 恢复边距
    ax.set_ylim(0, plate.height + 20)
    ax.add_patch(patches.Rectangle((10, 10), plate.width, plate.height, 
                                   edgecolor='r', fill=False, lw=2))  # 板材边框
    
    for data in plate.pieces:
        piece, x, w, y = data
        ax.add_patch(patches.Rectangle((x, y), w, piece.get_dim()[1], 
                                       edgecolor='b', fill=False, lw=1))
        ax.text(x+5, y+5, f'ID:{piece.id}', fontsize=6, color='red')
    
    ax.set_title(f"板材{plate.id}排版图({len(set(p.id for p,_,_,_ in plate.pieces))}种工件)")
    ax.set_xlabel("宽度(mm)")
    ax.set_ylabel("高度(mm)")
    ax.grid(True, linestyle='--', alpha=0.5)
    plt.show()

# 生成可视化
for plate in plates:
    visualize

_plate(plate)