[Python] Find NFP for container and polygon with pyclipper library

Discussão em 'Python' iniciado por Stack, Maio 29, 2025.

  1. Stack

    Stack Membro Participativo

    I'm playing with the library and trying to build an NFP polygon that shows possible positions of a figure inside a container. But my code doesn't give the result I need. The code is below. If anyone has experience with such a library, tell me what's wrong with me?

    import pyclipper
    import matplotlib.pyplot as plt
    from matplotlib.patches import Polygon as MplPolygon
    from matplotlib.collections import PatchCollection


    # Функция проверки и кооретировки замкнутости полигона
    def close_poly(polygon):
    if not polygon:
    return []
    if len(polygon) < 2:
    return polygon
    if polygon[0] != polygon[-1]:
    return polygon + [polygon[0]]
    return polygon


    # Функция корректировки направления полигона
    def orient_poly(polygon, ccw=False):
    if len(polygon) < 3:
    return polygon

    area = sum(
    (x1 * y2) - (x2 * y1)
    for (x1, y1), (x2, y2) in zip(polygon, polygon[1:] + [polygon[0]])
    )

    is_currently_ccw = area < 0
    return list(reversed(polygon)) if (ccw ^ is_currently_ccw) else polygon


    # Функция отражения полигона относительно центра масс (центроида)
    def reflect_poly(polygon):
    # Вычисляем центроид
    centroid = (
    sum(x for x, y in polygon) / len(polygon),
    sum(y for x, y, in polygon) / len(polygon),
    )

    # Возвращаем отраженный полигон
    return [(2 * centroid[0] - x, 2 * centroid[1] - y) for x, y in polygon]


    # Функция масштабирования полигона
    def scale_poly(polygon, scale=100):
    return [(int(x * scale), int(y * scale)) for x, y in polygon]


    # Функция нахождения NFP для контейнера и полигона
    def nfp_container_poly(cont, poly):
    # Масштаб скалирования
    SCALE = 1000

    # Проверяем замкнутость полигонов
    cont = close_poly(cont)
    poly = close_poly(poly)

    # Корректируем ориентацию контейнера и фигуры
    cont = orient_poly(cont, ccw=True)
    poly = orient_poly(poly, ccw=False)

    # Отражаем полигон относительно центра масс
    r_poly = reflect_poly(poly)

    # Масштабируем полигоны
    c_scaled = scale_poly(cont, SCALE)
    r_scaled = scale_poly(r_poly, SCALE)

    # Вычисляем разность Минковского
    pc = pyclipper.Pyclipper()
    pc.AddPath(c_scaled, pyclipper.PT_SUBJECT, closed=True)
    pc.AddPath(r_scaled, pyclipper.PT_CLIP, closed=True)

    # Получаем результат
    solution = pc.Execute(
    # pyclipper.CT_DIFFERENCE, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO
    pyclipper.CT_INTERSECTION,
    pyclipper.PFT_NONZERO,
    pyclipper.PFT_NONZERO,
    )
    if not solution:
    return None

    nfp_scaled = solution[0]
    nfp = scale_poly(nfp_scaled, 1 / SCALE)

    return nfp


    def vizualize_poly(cont, poly, nfp):
    fig, ax = plt.subplots(figsize=(10, 8))
    ax.set_aspect("equal")
    ax.grid(True)

    cont = close_poly(cont)
    poly = close_poly(poly)

    # Создаем патчи для отрисовки
    patches = []

    # Контейнер — синий полиигон
    patches.append(MplPolygon(cont, closed=True, color="blue", alpha=0.0))

    # Деталь — зеленый полиигон
    patches.append(MplPolygon(poly, closed=True, color="green", alpha=0.5))

    # NFP — красный
    if nfp:
    nfp = close_poly(nfp)
    patches.append(MplPolygon(nfp, closed=True, color="red", alpha=0.5))

    # Добавляем патчи на график
    for patch in patches:
    ax.add_patch(patch)

    # Добавляем легенду
    legend_elements = [
    plt.Rectangle((0, 0), 1, 1, fc="blue", alpha=0.5, label="Container"),
    plt.Rectangle((0, 0), 1, 1, fc="green", alpha=0.5, label="Polygon"),
    ]

    if nfp:
    legend_elements.append(
    plt.Rectangle((0, 0), 1, 1, fc="red", alpha=0.5, label="NFP")
    )

    ax.legend(handles=legend_elements, loc="upper right")

    # Устанавливаем границы графика
    all_points = cont + poly
    if nfp:
    all_points += nfp

    x_coords, y_coords = zip(*all_points)
    ax.set_xlim(min(x_coords) - 1, max(x_coords) + 1)
    ax.set_ylim(min(y_coords) - 1, max(y_coords) + 1)

    plt.title("No-Fit Polygon Visualization")
    plt.show()


    container = [(0, 0), (600, 0), (600, 600), (0, 600)]
    polygon_a = [(0, 0), (200, 0), (200, 200), (0, 200)]

    nfp = nfp_container_poly(container, polygon_a)

    print(nfp)
    vizualize_poly(container, polygon_a, nfp)



    I need find NFP polygon_a inside container

    Continue reading...

Compartilhe esta Página