Java で指定された 3 つのポイントを通過する曲線を作成しようとしています (JPanel を拡張するクラスを介して曲線を描画しています)。どうすれば作れますか?
10488 次
5 に答える
4
これを堅牢な方法で機能させるのに少し時間を費やしました。円の 3 点から Arc2D を作成する関数が続きます。私の目的のために、開始点と終了点、および中間の「中間」点があります (実際には中間にある必要はありませんが、その目的は、必要な円の弧を教えてくれることです)。 )。
ソースへの直接リンクは次のとおりです。
org.six11.util.gui.shape.ShapeFactory
public static Pt getCircleCenter(Pt a, Pt b, Pt c) {
double ax = a.getX();
double ay = a.getY();
double bx = b.getX();
double by = b.getY();
double cx = c.getX();
double cy = c.getY();
double A = bx - ax;
double B = by - ay;
double C = cx - ax;
double D = cy - ay;
double E = A * (ax + bx) + B * (ay + by);
double F = C * (ax + cx) + D * (ay + cy);
double G = 2 * (A * (cy - by) - B * (cx - bx));
if (G == 0.0)
return null; // a, b, c must be collinear
double px = (D * E - B * F) / G;
double py = (A * F - C * E) / G;
return new Pt(px, py);
}
public static double makeAnglePositive(double angleDegrees) {
double ret = angleDegrees;
if (angleDegrees < 0) {
ret = 360 + angleDegrees;
}
return ret;
}
public static double getNearestAnglePhase(double limitDegrees, double sourceDegrees, int dir) {
double value = sourceDegrees;
if (dir > 0) {
while (value < limitDegrees) {
value += 360.0;
}
} else if (dir < 0) {
while (value > limitDegrees) {
value -= 360.0;
}
}
return value;
}
public static Arc2D makeArc(Pt s, Pt mid, Pt e) {
Pt c = Functions.getCircleCenter(s, mid, e);
double radius = c.distance(s);
double startAngle = Functions.makeAnglePositive(Math.toDegrees(-Math
.atan2(s.y - c.y, s.x - c.x)));
double midAngle = Functions.makeAnglePositive(Math.toDegrees(-Math.atan2(mid.y - c.y, mid.x
- c.x)));
double endAngle = Functions
.makeAnglePositive(Math.toDegrees(-Math.atan2(e.y - c.y, e.x - c.x)));
// Now compute the phase-adjusted angles begining from startAngle, moving positive and negative.
double midDecreasing = Functions.getNearestAnglePhase(startAngle, midAngle, -1);
double midIncreasing = Functions.getNearestAnglePhase(startAngle, midAngle, 1);
double endDecreasing = Functions.getNearestAnglePhase(midDecreasing, endAngle, -1);
double endIncreasing = Functions.getNearestAnglePhase(midIncreasing, endAngle, 1);
// Each path from start -> mid -> end is technically, but one will wrap around the entire
// circle, which isn't what we want. Pick the one that with the smaller angular change.
double extent = 0;
if (Math.abs(endDecreasing - startAngle) < Math.abs(endIncreasing - startAngle)) {
extent = endDecreasing - startAngle;
} else {
extent = endIncreasing - startAngle;
}
return new Arc2D.Double(c.x - radius, c.y - radius, radius * 2, radius * 2, startAngle, extent,
Arc2D.OPEN);
}
于 2010-01-28T22:18:43.197 に答える