2009-07-06 19 views
3

J'essaie de créer une courbe qui passe par trois points donnés en Java (je dessine les courbes à travers une classe qui étend JPanel). Comment puis-je le faire?Comment dessiner une courbe qui passe par trois points?

enter image description here

+0

-t-il importe quel type de courbe? Parce que si vous avez juste besoin de calculer le centre et le rayon du cercle défini par ces 3 points, vous pouvez vérifier: http://planetmath.org/encyclopedia/ThreePointFormulaForTheCircle.html –

Répondre

5

Vous devriez regarder dans quelque chose comme splines Catmull-Rom, qui sont essentiellement des courbes qui passent par un certain nombre de points de contrôle (dans votre cas vos trois points).

Voici un exemple que je trouve après un rapide Google: http://www.mvps.org/directx/articles/catmull/

Hope this helps :)

2

essayer une recherche Google sur splines Bézier. cela peut être une solution 2D, mais devrait être extensible à la 3D si vous en avez besoin. Fondamentalement, en utilisant les trois points comme paramètres, vous pouvez obtenir un polynôme de second ordre qui correspond aux trois points. Et son extensible, si vous avez N points, vous obtenez un polynôme d'ordre N-1 qui génère tous les points de façon paramétrique du 1er au dernier, lorsque vous «réglez» un paramètre scalaire, souvent désigné par «s».

modifier/ajouter:

comme l'a souligné (! CapBBeard de crédit), Béziers ne frappe pas vraiment les points médians. L'interpolation lagrangienne atteint réellement les points, mais devient moche encore plus rapidement à mesure que le nombre de points augmente. (quelque chose comme des fractions polynomiales O (n) chacune d'ordre N)

+0

Les splines de Bézier ne passent généralement pas par tous les points ils? Juste le premier/dernier IIRC – CapBBeard

+0

@CapBBeard - ah, vous avez peut-être raison à ce sujet. ils peuvent juste se rapprocher des intermédiaires. – JustJeff

+0

Ils ne peuvent même pas se rapprocher des intermédiaires. Il y a des garanties, mais elles n'incluent pas la proximité.Une courbe de Bézier avec trois points atteindra chaque point d'extrémité, mais se courbera de telle sorte qu'elle manquera celle du milieu (à moins qu'ils ne soient tous sur une ligne). –

4

Je viens juste de passer du temps à travailler dur. Il y a quelques fonctions de support, suivies par la chose qui crée un Arc2D sur trois points d'un cercle. Pour mes buts, j'ai un point de départ et un point final, ainsi qu'un point intermédiaire (bien qu'il ne doive pas être au milieu). Son but est de me dire quel arc de cercle je veux.).

Voici les liens directs à la source:

org.six11.util.gui.shape.ShapeFactory

org.six11.util.pen.Functions

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); 
} 
0

utilisation 2 courbes
curveLine1 créé avec 3 points: P1, C1, E1.
curveLine2 créé avec 3 points: P2 = E1, C2, E2.
faites C1, E1, C2 en 1 ligne.
Voir par exemple ici: http://i.stack.imgur.com/I901q.png

QuadCurve2D.Double curveLine1 = new QuadCurve2D.Double(30, 75, 195, 23, 280, 143); 
//QuadCurve2D.Double curveLine1 = new QuadCurve2D.Double(P1.x, P1.y, C1.x, C1.y, E1.x, E1.y); 
QuadCurve2D.Double curveLine2 = new QuadCurve2D.Double(280, 143, 366, 260, 466, 193); 
//QuadCurve2D.Double curveLine2 = new QuadCurve2D.Double(E1.x, E1.y, C2.x, C2.y, E2.x, E2.y); 
Graphics2D g2 = (Graphics2D) g; 
g2.draw(curveLine1); 
g2.draw(curveLine2); 
Questions connexes