【问题标题】:Divide Polygon Shape Java分割多边形形状Java
【发布时间】:2026-01-27 21:05:01
【问题描述】:

我有一个简单的 4 点二维多边形。

    int[] x = {38, 100, 80, 18};
    int[] y = {50, 50, 100, 100};
    
    Polygon poly = new Polygon(x, y, 4);

上面的多边形只是一个例子。上面的多边形实际上可以是任何东西,只要多边形总是凸的,总是有 4 个点,并且是一个平行四边形。我需要将它分成任意数量的偶​​数部分,所有部分都与较大的多边形成比例,只要数字是平方数。有什么简单的方法可以做到这一点吗?如果这很重要的话,我会在 Jframe 上使用 Graphics。

【问题讨论】:

  • "将其分成 8 个偶数部分" 这是什么意思?随意将多边形分成 8 块?
  • 分成2x4?还是 4x2?而且你有两个水平的边(y1 = y2 和 y3 = y4),这是必需的条件吗?
  • 不是 4, 9, 16... (n^2) 而是 2, 4, 8... (2^n) 对吗?如果要将形状分成 8 部分,则需要决定如何切割形状。
  • 分割成n块时,每个坐标要除以Math.sqrt(n)?
  • 是的,“square numbers”。如果你想把一个四边形分成四个部分,你可以通过获取它们的中点(因为四个是两个的正方形)将每个边切成两半,然后连接这些点以获得新的多边形。您可以通过 ((x0+x1)/2,(y0+y1)/2) 得到 (x0,y0)-(x1,y1) 的中点。

标签: java graphics polygon


【解决方案1】:

以下代码适用于任何凸 4 边多边形。当初始多边形是平行四边形时,生成的子多边形本质上也是平行四边形,都具有相同的大小,即它们是均匀大小的。

由于所需的parts 的数量必须是平方数,这意味着我们可以简单地将 4 边多边形水平和垂直分割成partsPerSide = sqrt(parts)

当我们将一个 4 边形多边形分割成多个部分时,我们最终可能会得到不是精确整数的坐标。我们可以简单地将值四舍五入为一个整数,但这样碎片的大小就不会完全均匀了。这是否可以接受是一个选择问题。在视觉上,可以注意到圆角,因为线条不会 100% 笔直。

在下面的代码中,我们假设舍入是不可接受的,即我们想要精确的偶数大小。如果四舍五入没问题,只需在末尾注释掉if (rounded != delta) throw new ArithmeticException() 代码,然后使用所需的partsPerSide 编号调用splitFourSided()

废话不多说,代码如下:

private static Polygon[][] splitFourSided(Polygon poly, int partsPerSide) {
    if (poly.npoints != 4)
        throw new IllegalArgumentException("Polygon must be 4-sided");
    if (partsPerSide <= 0)
        throw new IllegalArgumentException("There must be a positive number of parts per side");
    int[][] x = splitFourSided(poly.xpoints, partsPerSide);
    int[][] y = splitFourSided(poly.ypoints, partsPerSide);
    Polygon[][] pieces = new Polygon[partsPerSide][partsPerSide];
    for (int row = 0; row < partsPerSide; row++) {
        for (int col = 0; col < partsPerSide; col++) {
            pieces[row][col] = new Polygon(
                    new int[] { x[row][col], x[row][col+1], x[row+1][col+1], x[row+1][col] },
                    new int[] { y[row][col], y[row][col+1], y[row+1][col+1], y[row+1][col] },
                    4);
        }
    }
    return pieces;
}
private static int[][] splitFourSided(int[] xy, int parts) {
    // To visualize, assume values are [topLeft, topRight, bottomRight, bottomLeft].
    // The 'xy' array is either the x-coordinates or the y-coordinates.
    // First we split left and right sides, e.g. for 3 parts:
    //   From: ┌     To: ┐
    //         ├         ┤
    //         ├         ┤
    //         └         ┘
    // Then we split between those:
    //   ┌─┬─┬─┐
    //   ├─┼─┼─┤
    //   ├─┼─┼─┤
    //   └─┴─┴─┘
    int[] from = splitRange(xy[0], xy[3], parts);
    int[] to = splitRange(xy[1], xy[2], parts);
    int[][] grid = new int[parts + 1][];
    for (int i = 0; i <= parts; i++)
        grid[i] = splitRange(from[i], to[i], parts);
    return grid;
}
private static int[] splitRange(int from, int to, int parts) {
    int[] prorated = new int[parts + 1];
    for (int i = 0; i <= parts; i++)
        prorated[i] = prorate(from, to, i, parts);
    return prorated;
}
private static int prorate(int from, int to, int index, int parts) {
    if (index == 0)
        return from;
    if (index == parts)
        return to;
    double delta = (to - (double) from) * index / parts;
    int rounded = (int) Math.round(delta);
    if (rounded != delta)
        throw new ArithmeticException("Cannot prorate to integer value");
    return from + rounded;
}

测试

int[] x = {38, 100, 80, 18};
int[] y = {50, 50, 100, 100};
Polygon poly = new Polygon(x, y, 4);
splitAndDrawFourSided(g, poly, 2);
private static void splitAndDrawFourSided(Graphics g, Polygon poly, int partsPerSide) {
    Polygon[][] pieces = splitFourSided(poly, partsPerSide);
    for (int row = 0; row < partsPerSide; row++)
        for (int col = 0; col < partsPerSide; col++)
            g.drawPolygon(pieces[row][col]);
    Graphics gMain = g.create();
    try {
        gMain.setColor(Color.RED);
        gMain.drawPolygon(poly);
    } finally {
        gMain.dispose();
    }
}

结果


要搜索有效数量的零件,我们可以添加一个搜索循环,并更改坐标,使它们只能被 7 整除。

int[] x = {37, 100, 79, 16};
int[] y = {50, 50, 99, 99};
Polygon poly = new Polygon(x, y, 4);
for (int partsPerSide : new int[] { 2, 3, 5, 7, 11, 13, 17, 19 }) {
    try {
        splitAndDrawFourSided(g, poly, partsPerSide);
        break; // stop when successful
    } catch (@SuppressWarnings("unused") ArithmeticException ignored) {
        continue; // try next number of parts
    }
}

结果


如果我们删除舍入检查,该代码当然总是每边只分成 2 部分,即分成 4 部分。这显示了舍入的效果,例如在这种情况下,中心行坐标稍微偏右,导致黑线和红线不匹配。即使没有描绘输入平行四边形的红线,也可以注意到舍入。 Anti-aliasing 有帮助,但仍然可以注意到垂直线不是 100% 笔直的。

【讨论】: