You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

随多边形尺寸变化动态缩放内部填充圆的技术需求

动态调整多边形内填充圆半径以适配尺寸

我目前使用Shapely库创建多边形,并在内部按固定半径和间距生成填充圆,现有实现代码如下:

import matplotlib.pyplot as plt
from shapely.geometry import Polygon, Point
import numpy as np

def pack_circles_inside_polygon(polygon, radius, distance):
    circles = []
    
    # 计算行列可容纳的圆数量
    num_rows = int((polygon.bounds[3] - polygon.bounds[1] - 2 * radius) / (2 * radius + distance)) + 1
    num_cols = int((polygon.bounds[2] - polygon.bounds[0] - 2 * radius) / (2 * radius + distance)) + 1

    # 生成圆心坐标并筛选在多边形内的圆
    for i in range(num_rows):
        for j in range(num_cols):
            x = polygon.bounds[0] + (2 * radius + distance) * j + radius
            y = polygon.bounds[1] + (2 * radius + distance) * i + radius
            center = Point(x, y)
            if polygon.contains(center.buffer(radius)):
                circle = center.buffer(radius)
                circles.append(circle)

    return circles

# 原多边形与参数设置
polygon_vertices = [(2, 2), (5, 8), (10, 6), (7, 1)]
polygon = Polygon(polygon_vertices)
radius = 0.5
distance = 0.5
polygon2 = polygon.buffer(-distance, join_style=2)

# 生成填充圆并可视化
circles = pack_circles_inside_polygon(polygon2, radius, distance)
fig, ax = plt.subplots()
x, y = polygon.exterior.xy
ax.plot(x, y, color='blue', alpha=0.7, linewidth=2, solid_capstyle='round')
ax.fill(x, y, color='blue', alpha=0.3)

for circle in circles:
    x, y = circle.exterior.xy
    ax.plot(x, y, color='red', alpha=0.5)

ax.set_aspect('equal', 'datalim')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Circles Packed Inside Polygon')
plt.grid(True)
plt.show()

接下来需要基于原多边形生成多个变体多边形,核心需求是:当变体多边形尺寸与原多边形不同时,动态调整填充圆的半径,使圆的大小适配多边形尺寸。例如原多边形可容纳N个圆,若变体多边形无法容纳同半径同间距的N个圆,则减小圆半径,实现圆随多边形尺寸缩放的效果。


实现方案

核心逻辑

  1. 先计算原多边形能容纳的目标圆数量,以此为适配基准
  2. 保持圆间距与半径的比例(原设置中distance/radius=1,动态调整时该比例不变)
  3. 对变体多边形,从原半径开始逐步缩小半径,直到能容纳目标数量的圆,或达到预设的最小半径阈值

修改后的完整代码

import matplotlib.pyplot as plt
from shapely.geometry import Polygon, Point
import numpy as np

def pack_circles_inside_polygon(polygon, radius, distance):
    circles = []
    spacing = 2 * radius + distance
    
    # 计算行列可容纳的圆数量
    num_rows = int((polygon.bounds[3] - polygon.bounds[1] - 2 * radius) / spacing) + 1
    num_cols = int((polygon.bounds[2] - polygon.bounds[0] - 2 * radius) / spacing) + 1

    # 生成圆心坐标并筛选在多边形内的圆
    for i in range(num_rows):
        for j in range(num_cols):
            x = polygon.bounds[0] + spacing * j + radius
            y = polygon.bounds[1] + spacing * i + radius
            center = Point(x, y)
            if polygon.contains(center.buffer(radius)):
                circles.append(center.buffer(radius))

    return circles

def get_target_circle_count(original_polygon, original_radius, original_distance):
    # 计算原多边形的目标圆数量
    buffered_poly = original_polygon.buffer(-original_distance, join_style=2)
    circles = pack_circles_inside_polygon(buffered_poly, original_radius, original_distance)
    return len(circles)

def adjust_radius_for_variant(variant_polygon, target_count, original_radius, original_distance, min_radius=0.1):
    # 保持间距与半径的比例
    spacing_ratio = original_distance / original_radius
    current_radius = original_radius
    buffered_variant = variant_polygon.buffer(-(current_radius * spacing_ratio), join_style=2)
    
    # 迭代调整半径,直到满足数量要求或达到最小半径
    while current_radius >= min_radius:
        circles = pack_circles_inside_polygon(buffered_variant, current_radius, current_radius * spacing_ratio)
        if len(circles) >= target_count:
            return current_radius, circles
        # 每次减小10%的半径
        current_radius *= 0.9
        buffered_variant = variant_polygon.buffer(-(current_radius * spacing_ratio), join_style=2)
    
    # 达到最小半径时返回当前结果
    return current_radius, pack_circles_inside_polygon(buffered_variant, current_radius, current_radius * spacing_ratio)

# ------------------------------
# 示例:原多边形与变体多边形测试
# ------------------------------
# 原多边形设置
original_vertices = [(2, 2), (5, 8), (10, 6), (7, 1)]
original_polygon = Polygon(original_vertices)
original_radius = 0.5
original_distance = 0.5

# 获取目标圆数量
target_count = get_target_circle_count(original_polygon, original_radius, original_distance)
print(f"原多边形可容纳圆数量: {target_count}")

# 生成一个缩小的变体多边形(各顶点坐标乘以0.7)
variant_vertices = [(x*0.7, y*0.7) for x, y in original_vertices]
variant_polygon = Polygon(variant_vertices)

# 动态调整半径并生成填充圆
adjusted_radius, variant_circles = adjust_radius_for_variant(variant_polygon, target_count, original_radius, original_distance)
print(f"变体多边形适配后的圆半径: {round(adjusted_radius, 3)}")
print(f"变体多边形实际容纳圆数量: {len(variant_circles)}")

# 可视化原多边形与变体多边形的填充效果
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))

# 原多边形可视化
x, y = original_polygon.exterior.xy
ax1.plot(x, y, color='blue', alpha=0.7, linewidth=2)
ax1.fill(x, y, color='blue', alpha=0.3)
original_circles = pack_circles_inside_polygon(original_polygon.buffer(-original_distance, join_style=2), original_radius, original_distance)
for circle in original_circles:
    cx, cy = circle.exterior.xy
    ax1.plot(cx, cy, color='red', alpha=0.5)
ax1.set_aspect('equal')
ax1.set_title(f"原多边形 (半径={original_radius})")
ax1.grid(True)

# 变体多边形可视化
x, y = variant_polygon.exterior.xy
ax2.plot(x, y, color='green', alpha=0.7, linewidth=2)
ax2.fill(x, y, color='green', alpha=0.3)
for circle in variant_circles:
    cx, cy = circle.exterior.xy
    ax2.plot(cx, cy, color='orange', alpha=0.5)
ax2.set_aspect('equal')
ax2.set_title(f"变体多边形 (适配半径={round(adjusted_radius,3)})")
ax2.grid(True)

plt.tight_layout()
plt.show()

关键说明

  • get_target_circle_count:计算原多边形的基准圆数量,作为变体多边形的适配目标
  • adjust_radius_for_variant:通过迭代缩小半径(每次减少10%),保持间距与半径的比例不变,直到变体多边形能容纳目标数量的圆
  • 可通过调整min_radius参数设置最小允许半径,避免半径过小失去实际意义

内容的提问来源于stack exchange,提问作者Vismaya Hostcurator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 23:31:07