【发布时间】:2020-09-12 09:22:23
【问题描述】:
我想找到圆弧的中心点。 我有弧的起点、终点和偏移量。
我已经尝试了下面的代码。使用这段代码,我在 90% 的情况下得到了圆弧的中心点。但是对于某些数据,它无法找到中心点。
圆弧画我有这个定义
X169290Y2681101I90207J39371*
X267716Y2779527J98426*
X169290Y2877952I98425*
X79082Y2818897J98425*
以上四个圆心坐标的答案都是(4.299940599999999, 70.5999858)
private Coordinate findCenter(Coordinate start, Coordinate end, Coordinate offset) {
double twoPi = 2 * Math.PI;
if (quadrantMode.equals("single-quadrant")) {
// The Gerber spec says single quadrant only has one possible center,
// and you can detect it based on the angle. But for real files, this
// seems to work better - there is usually only one option that makes
// sense for the center (since the distance should be the same
// from start and end). We select the center with the least error in
// radius from all the options with a valid sweep angle.
double sqdistDiffMin = Double.MAX_VALUE;
Coordinate center = null;
List<Coordinate> qFactors = new ArrayList<Coordinate>();
qFactors.add(new Coordinate(1, 1));
qFactors.add(new Coordinate(1, -1));
qFactors.add(new Coordinate(-1, 1));
qFactors.add(new Coordinate(-1, -1));
for (Coordinate factors : qFactors) {
Coordinate testCenter = new Coordinate(start.getX() + offset.getX() * factors.getX(),
start.getY() + offset.getY() * factors.getY());
// Find angle from center to start and end points
double startAngleX = start.getX() - testCenter.getX();
double startAngleY = start.getY() - testCenter.getY();
double startAngle = Math.atan2(startAngleY, startAngleX);
double endAngleX = end.getX() - testCenter.getX();
double endAngleY = end.getY() - testCenter.getY();
double endAngle = Math.atan2(endAngleY, endAngleX);
// # Clamp angles to 0, 2pi
double theta0 = (startAngle + twoPi) % twoPi;
double theta1 = (endAngle + twoPi) % twoPi;
// # Determine sweep angle in the current arc direction
double sweepAngle;
if (direction.equals("counterclockwise") ) {
theta1 += twoPi;
// sweepAngle = Math.abs(theta1 - theta0);
sweepAngle = Math.abs(theta1 - theta0) % twoPi;
} else {
theta0 += twoPi;
sweepAngle = Math.abs(theta0 - theta1) % twoPi;
}
// # Calculate the radius error
double sqdistStart = sqDistance(start, testCenter);
double sqdistEnd = sqDistance(end, testCenter);
double sqdistDiff = Math.abs(sqdistStart - sqdistEnd);
// Take the option with the lowest radius error from the set of
// options with a valid sweep angle
// In some rare cases, the sweep angle is numerically (10**-14) above pi/2
// So it is safer to compare the angles with some tolerance
boolean isLowestRadiusError = sqdistDiff < sqdistDiffMin;
boolean isValidSweepAngle = sweepAngle >= 0 && sweepAngle <= Math.PI / 2.0 + 1e-6;
if (isLowestRadiusError && isValidSweepAngle) {
center = testCenter;
sqdistDiffMin = sqdistDiff;
}
}
return center;
}
else {
return new Coordinate(start.getX() + offset.getX(), start.getY() + offset.getY());
}
}
public static double sqDistance(Coordinate point1, Coordinate point2) {
double diff1 = point1.getX() - point2.getX();
double diff2 = point1.getY() - point2.getY();
return diff1 * diff1 + diff2 * diff2;
}
【问题讨论】:
-
如果算法适用于大多数情况,但不适用于某些情况,它看起来像是一个基于准确性的问题。您是否调试了代码并发现了任何无法预料的值?
-
如果偏移怎么办?
X169290Y2681101I90207J39371是什么意思?为什么另一个字符串只包含 I 或 J? -
您能详细说明输入格式吗?另外,圆弧是圆弧还是任意椭圆的弧?
-
@MBo I, J 表示 X 或 Y 方向的距离或偏移量的字符。 如果缺少 I 或 J,则使用 0 距离。
-
@Dominique,是的,我已经调试并在这一行发现了问题
boolean isValidSweepAngle = sweepAngle >= 0 && sweepAngle <= Math.PI / 2.0 + 1e-6;我在哪里得到了这些值 "sweepAngle" =1.5708064868152167 和 "Math 的值.PI / 2.0 + 1e-6" = 1.5707973267948965 对于这个微小的差异,它变成 isValidSweepAngle = false。
标签: java math geometry trigonometry coordinate-systems