如何为凹多边形生成回声路径
How can I generate echo path for concave polygon
我需要一种算法来绘制任意多边形的回声路径。如果多边形是凸的,问题就很容易解决。要理解我的意思,请看下面的图片,黑色是原始多边形,红色是从原始多边形生成的回声多边形。
d
是给定的回声路径之间的距离
β
角度很容易计算知道我们有顶点的坐标
因此,正如您所见,对于每个顶点,我们可以计算 L
,从而为下一个回声路径提供新的顶点。
问题是当我们在某个点上有凹多边形时,我们会得到一张难看的自交叉多边形图片。请看看这张照片。
我想要做的是生成没有自交叉部分的回声多边形,即没有带有虚线的部分。算法或 java
代码会很有帮助。谢谢。
编辑
只需添加一段代码,按照评论中的要求为凸多边形生成回声路径。
public List<MyPath> createEchoCoCentral( List<Point> pointsOriginal, float encoderEchoDistance, int appliqueEchoCount){
List<Point> contourPoints = pointsOriginal;
List<MyPath> echoPaths = new ArrayList<>();
for (int round = 0; round < appliqueEchoCount; round++) {
List<Point> echoedPoints = new ArrayList<>();
int size = contourPoints.size()+1;//+1 because we connect end to start
Point previousPoint = contourPoints.get(contourPoints.size() - 1);
for (int i = 0; i < size; i++) {
Point currentPoint;
if (i == contourPoints.size()) {
currentPoint = new Point(contourPoints.get(0));
} else {
currentPoint = contourPoints.get(i);
}
final Point nextPoint;
if (i + 1 == contourPoints.size()) {
nextPoint = contourPoints.get(0);
} else if (i == contourPoints.size()) {
nextPoint = contourPoints.get(1);
} else {
nextPoint = contourPoints.get(i + 1);
}
if (currentPoint.x == previousPoint.x && currentPoint.y == previousPoint.y) continue;
if (currentPoint.x == nextPoint.x && currentPoint.y == nextPoint.y) continue;
// signs needed o determine to which side of polygon new point will go
float currentSlope = (float) (Math.atan((previousPoint.y - currentPoint.y) / (previousPoint.x - currentPoint.x)));
float signX = Math.signum((previousPoint.x - currentPoint.x));
float signY = Math.signum((previousPoint.y - currentPoint.y));
signX = signX == 0 ? 1 : signX;
signY = signY == 0 ? 1 : signY;
float nextSignX = Math.signum((currentPoint.x - nextPoint.x));
float nextSignY = Math.signum((currentPoint.y - nextPoint.y));
nextSignX = nextSignX == 0 ? 1 : nextSignX;
nextSignY = nextSignY == 0 ? 1 : nextSignY;
float nextSlope = (float) (Math.atan((currentPoint.y - nextPoint.y) / (currentPoint.x - nextPoint.x)));
float nextSlopeD = (float) Math.toDegrees(nextSlope);
//calculateMidAngle - is a bit tricky function that calculates angle between two adjacent edges
double S = calculateMidAngle(currentSlope, nextSlope, signX, signY, nextSignX, nextSignY);
Point p2 = new Point();
double ew = encoderEchoDistance / Math.cos(S - (Math.PI / 2));
p2.x = (int) (currentPoint.x + (Math.cos(currentSlope - S)) * ew * signX);
p2.y = (int) (currentPoint.y + (Math.sin(currentSlope - S)) * ew * signX);
echoedPoints.add(p2);
previousPoint = currentPoint;
}
//createPathFromPoints just creates MyPath objects from given Poins set
echoPaths.add(createPathFromPoints(echoedPoints));
//remove last point since it was just to connect end to first point
echoedPoints.remove(echoedPoints.size() - 1);
contourPoints = echoedPoints;
}
return echoPaths;
}
您正在寻找 straight skeleton:
(图片来自Wikipedia。)
好的,找到了一个可以满足我需要的库。它叫 Clipper
如果有人感兴趣,还有 java 实现 here。
用 Java 库几行代码就可以了
Path originalPath = new Path();
for (PointF areaPoint:pointsOriginal){
originalPath.add(new LongPoint((long)areaPoint.x, (long)areaPoint.y));
}
final ClipperOffset clo = new ClipperOffset();
Paths clips = new Paths();
Paths solution = new Paths();
clips.add(originalPath);
clo.addPaths( clips, Clipper.JoinType.SQUARE, Clipper.EndType.CLOSED_LINE );
float encoderEchoDistance = (float) UnitUtils.convertInchOrMmUnitsToEncoderUnits(this, inchOrMm, appliqueEchoDistance);
clo.execute( solution, encoderEchoDistance );
// Now solution.get(0) will contain path that has offset from original path
// and what is most important it will not have self intersections.
它是开源的,因此我将深入研究实现细节。感谢所有试图提供帮助的人。
这个问题叫做计算多边形偏移。有两种常见的方法可以解决这个问题:
1)最有效的方法是通过计算绕组数来计算偏移多边形(据我了解,该算法被 Clipper 库使用)
2) 计算直骨架图,帮助您构建偏移多边形
关于此主题的有趣文章:
陈,通过计算缠绕数进行多边形偏移
计算直骨架的 Felkel 算法
我需要一种算法来绘制任意多边形的回声路径。如果多边形是凸的,问题就很容易解决。要理解我的意思,请看下面的图片,黑色是原始多边形,红色是从原始多边形生成的回声多边形。
d
是给定的回声路径之间的距离
β
角度很容易计算知道我们有顶点的坐标
因此,正如您所见,对于每个顶点,我们可以计算 L
,从而为下一个回声路径提供新的顶点。
问题是当我们在某个点上有凹多边形时,我们会得到一张难看的自交叉多边形图片。请看看这张照片。
我想要做的是生成没有自交叉部分的回声多边形,即没有带有虚线的部分。算法或 java
代码会很有帮助。谢谢。
编辑
只需添加一段代码,按照评论中的要求为凸多边形生成回声路径。
public List<MyPath> createEchoCoCentral( List<Point> pointsOriginal, float encoderEchoDistance, int appliqueEchoCount){
List<Point> contourPoints = pointsOriginal;
List<MyPath> echoPaths = new ArrayList<>();
for (int round = 0; round < appliqueEchoCount; round++) {
List<Point> echoedPoints = new ArrayList<>();
int size = contourPoints.size()+1;//+1 because we connect end to start
Point previousPoint = contourPoints.get(contourPoints.size() - 1);
for (int i = 0; i < size; i++) {
Point currentPoint;
if (i == contourPoints.size()) {
currentPoint = new Point(contourPoints.get(0));
} else {
currentPoint = contourPoints.get(i);
}
final Point nextPoint;
if (i + 1 == contourPoints.size()) {
nextPoint = contourPoints.get(0);
} else if (i == contourPoints.size()) {
nextPoint = contourPoints.get(1);
} else {
nextPoint = contourPoints.get(i + 1);
}
if (currentPoint.x == previousPoint.x && currentPoint.y == previousPoint.y) continue;
if (currentPoint.x == nextPoint.x && currentPoint.y == nextPoint.y) continue;
// signs needed o determine to which side of polygon new point will go
float currentSlope = (float) (Math.atan((previousPoint.y - currentPoint.y) / (previousPoint.x - currentPoint.x)));
float signX = Math.signum((previousPoint.x - currentPoint.x));
float signY = Math.signum((previousPoint.y - currentPoint.y));
signX = signX == 0 ? 1 : signX;
signY = signY == 0 ? 1 : signY;
float nextSignX = Math.signum((currentPoint.x - nextPoint.x));
float nextSignY = Math.signum((currentPoint.y - nextPoint.y));
nextSignX = nextSignX == 0 ? 1 : nextSignX;
nextSignY = nextSignY == 0 ? 1 : nextSignY;
float nextSlope = (float) (Math.atan((currentPoint.y - nextPoint.y) / (currentPoint.x - nextPoint.x)));
float nextSlopeD = (float) Math.toDegrees(nextSlope);
//calculateMidAngle - is a bit tricky function that calculates angle between two adjacent edges
double S = calculateMidAngle(currentSlope, nextSlope, signX, signY, nextSignX, nextSignY);
Point p2 = new Point();
double ew = encoderEchoDistance / Math.cos(S - (Math.PI / 2));
p2.x = (int) (currentPoint.x + (Math.cos(currentSlope - S)) * ew * signX);
p2.y = (int) (currentPoint.y + (Math.sin(currentSlope - S)) * ew * signX);
echoedPoints.add(p2);
previousPoint = currentPoint;
}
//createPathFromPoints just creates MyPath objects from given Poins set
echoPaths.add(createPathFromPoints(echoedPoints));
//remove last point since it was just to connect end to first point
echoedPoints.remove(echoedPoints.size() - 1);
contourPoints = echoedPoints;
}
return echoPaths;
}
您正在寻找 straight skeleton:
(图片来自Wikipedia。)
好的,找到了一个可以满足我需要的库。它叫 Clipper
如果有人感兴趣,还有 java 实现 here。
用 Java 库几行代码就可以了
Path originalPath = new Path();
for (PointF areaPoint:pointsOriginal){
originalPath.add(new LongPoint((long)areaPoint.x, (long)areaPoint.y));
}
final ClipperOffset clo = new ClipperOffset();
Paths clips = new Paths();
Paths solution = new Paths();
clips.add(originalPath);
clo.addPaths( clips, Clipper.JoinType.SQUARE, Clipper.EndType.CLOSED_LINE );
float encoderEchoDistance = (float) UnitUtils.convertInchOrMmUnitsToEncoderUnits(this, inchOrMm, appliqueEchoDistance);
clo.execute( solution, encoderEchoDistance );
// Now solution.get(0) will contain path that has offset from original path
// and what is most important it will not have self intersections.
它是开源的,因此我将深入研究实现细节。感谢所有试图提供帮助的人。
这个问题叫做计算多边形偏移。有两种常见的方法可以解决这个问题:
1)最有效的方法是通过计算绕组数来计算偏移多边形(据我了解,该算法被 Clipper 库使用)
2) 计算直骨架图,帮助您构建偏移多边形
关于此主题的有趣文章:
陈,通过计算缠绕数进行多边形偏移
计算直骨架的 Felkel 算法