划分多边形 Java
Divide Polygon Shape Java
我有一个简单的 2D 多边形,有 4 个点。
int[] x = {38, 100, 80, 18};
int[] y = {50, 50, 100, 100};
Polygon poly = new Polygon(x, y, 4);
上面的多边形只是一个例子。上面的多边形实际上可以是任何东西,只要多边形总是凸的,总是有 4 个点,并且是平行四边形。我需要将它分成任意数量的偶数部分,所有部分都与较大的多边形成比例,只要数字是平方数即可。有什么简单的方法可以做到这一点吗?如果这很重要,我正在 Jframe 上使用图形。
下面的代码适用于任何凸 4 边形。当初始多边形是平行四边形时,结果 sub-polygons 本质上也是 所有平行四边形,都具有相同的大小,即它们是 even-sized.
由于需要的parts
个数必须是平方数,所以我们可以简单地将4边形水平和垂直分割成partsPerSide = sqrt(parts)
.
当我们将一个 4 边形分成多个部分时,我们最终得到的坐标可能不是精确的整数。我们可以简单地将值四舍五入 为一个整数,但是这些部分的大小不会完全均匀。这是否可以接受是一个选择问题。在视觉上,可以注意到四舍五入,因为线条不会 100% 直。
在下面的代码中,我们假设四舍五入是不可接受的,即我们想要精确偶数的大小。如果四舍五入没问题,只需在末尾注释掉 if (rounded != delta) throw new ArithmeticException()
代码,然后调用 splitFourSided()
所需的 partsPerSide
.
废话少说,代码如下:
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% 直的。
我有一个简单的 2D 多边形,有 4 个点。
int[] x = {38, 100, 80, 18};
int[] y = {50, 50, 100, 100};
Polygon poly = new Polygon(x, y, 4);
上面的多边形只是一个例子。上面的多边形实际上可以是任何东西,只要多边形总是凸的,总是有 4 个点,并且是平行四边形。我需要将它分成任意数量的偶数部分,所有部分都与较大的多边形成比例,只要数字是平方数即可。有什么简单的方法可以做到这一点吗?如果这很重要,我正在 Jframe 上使用图形。
下面的代码适用于任何凸 4 边形。当初始多边形是平行四边形时,结果 sub-polygons 本质上也是 所有平行四边形,都具有相同的大小,即它们是 even-sized.
由于需要的parts
个数必须是平方数,所以我们可以简单地将4边形水平和垂直分割成partsPerSide = sqrt(parts)
.
当我们将一个 4 边形分成多个部分时,我们最终得到的坐标可能不是精确的整数。我们可以简单地将值四舍五入 为一个整数,但是这些部分的大小不会完全均匀。这是否可以接受是一个选择问题。在视觉上,可以注意到四舍五入,因为线条不会 100% 直。
在下面的代码中,我们假设四舍五入是不可接受的,即我们想要精确偶数的大小。如果四舍五入没问题,只需在末尾注释掉 if (rounded != delta) throw new ArithmeticException()
代码,然后调用 splitFourSided()
所需的 partsPerSide
.
废话少说,代码如下:
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% 直的。