题目:
在直角坐标系平面上,给定一些点(个数大于2),这些点组成一个多边形。
给定一个数字k(k>=2),将多边形的边长平分成k份。
输出:k个点,这些点全部都是多边形上的。
我的思路如下:
先求出总长度,然后求出平均长度。
第一个点取输入的第一个顶点。
具体过程看我源代码(Java):
package com.learing.divingpolygon;
public class PolygonDivider {
/**
* Divide input polygon into parts evenly by side length.
* @param pts Input points.
* @param numOfParts How many parts to be divided to.
* @return null if failed, otherwise the points on polygon.
*/
public static Point [] divide(Point [] pts, int numOfParts) {
if (numOfParts <= 1 || pts == null || pts.length < 2) {
return null;
}
// the part length.
final float partLen = getDividingLen(pts, numOfParts);
Point [] result = new Point[numOfParts];
// set the first result point as pts[0].
result[0] = pts[0];
// count of currently found results.
int count = 1;
// index for source points.
int sourceIndex = 1;
// the current point from where to calculate.
Point cur = pts[0];
// accumulated length for current point calculation.
float accumulated = 0.0f;
while (true) {
if (sourceIndex >= pts.length) {
System.err.print("program error.");
return null;
}
Point dest = pts[sourceIndex];
float distance = getDistance(cur, dest);
if (distance < partLen - accumulated) {
cur = dest;
accumulated += distance;
++sourceIndex;
// the last segment 's target is the original point.
// here the original point is set to the first point.
if (sourceIndex == pts.length) {
sourceIndex = 0;
}
} else {
cur = getPointByDistance(cur, dest, partLen - accumulated);
accumulated = 0.0f;
result[count++] = cur;
if (count == numOfParts) {
break;
}
}
}
return result;
}
static float getDividingLen(Point [] pts, int numOfParts) {
float sum = 0.0f;
final int n = pts.length;
for (int i = 1; i < n; ++i) {
sum += getDistance(pts[i - 1], pts[i]);
}
float lastLen = getDistance(pts[n - 1], pts[0]);
sum += lastLen;
return sum / numOfParts;
}
/**
* Get a float point on segment(from start to end) which satisfies that
* the length between start and the point is len.
* @param start
* @param end
* @param len
* @return the point which satisfies
* that the length between start and the point is len.
*/
static Point getPointByDistance(Point start, Point end, float len) {
// special occasion : vertical line, the slant ratio doesn't exist.
if (start.x == end.x) {
return new Point(start.x, end.y > start.y ? start.y + len : start.y - len);
}
final float slant = (end.y - start.y) / (end.x - start.x);
// result point x:
float x = end.x > start.x ?
len / (float) Math.sqrt(1 + slant * slant) + start.x
: -len / (float) Math.sqrt(1 + slant * slant) + start.x;
// result point y:
float y = start.y + slant * (x - start.x);
return new Point(x, y);
}
private static float getDistance(Point pt1, Point pt2) {
return (float) Math.hypot(pt2.x - pt1.x, pt2.y - pt1.y);
}
}
测试代码如下:
@Test
public void testDividing() {
Point pts[] = new Point[] {
new Point(0, 0),
new Point(10, 0),
new Point(10, 10),
new Point(0, 10),
};
Point [] result = PolygonDivider.divide(pts, 5);
Assert.assertEquals(result.length, 5);
Assert.assertEquals("assert equals", result[0].x, 0, 0.01f);
Assert.assertEquals("assert equals", result[0].y, 0, 0.01f);
Assert.assertEquals("assert equals", result[1].x, 8, 0.01f);
Assert.assertEquals("assert equals", result[1].y, 0, 0.01f);
Assert.assertEquals("assert equals", result[2].x, 10, 0.01f);
Assert.assertEquals("assert equals", result[2].y, 6, 0.01f);
Assert.assertEquals("assert equals", result[3].x, 6, 0.01f);
Assert.assertEquals("assert equals", result[3].y, 10, 0.01f);
Assert.assertEquals("assert equals", result[4].x, 0, 0.01f);
Assert.assertEquals("assert equals", result[4].y, 8, 0.01f);
}