PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Computergrafik - Bezierkurven


piepre
2003-04-10, 14:32:14
Moin, hat von euch zufällig jmd ein komplettes javaprogramm rumliegen, welches die bezierkurven nach dem algorithmus von casteljau berechnet?

unser programm funzt zwar schon fast, nur ist mittlerweile alles ziemlich unübersichtlich geworden...

Abe Ghiran
2003-04-10, 22:24:00
Hi!
Es geht so... ich habe das mal im letzten Semester für graphische Systeme gemacht. Dabei hatten wir ein Framework vorgegeben und mussten nur noch einzelne Methoden implementieren; der Code ist nicht so schön...
Der Algho steckt in der ersten Klasse, in der Methode getCurvePoint.
Aber vielleicht hilft es dir ja:

BezierCurve.java, repräsentiert eine Bezierkurve:


package grog;

/**
* <p>
* Die Klasse BezierCurve realisiert eine Bezierkurve in einem beliebig
* dimensionalen Raum. Die Kontrollpunkte der Kurve werden einmal
* bei der Konstruktion festgelegt.
* </p>
*
* <p>
* Es gibt Methoden zum Berechnen eines Kurvenpunktes und
* zum Unterteilen einer Kurve in zwei Teilkurven.
* </p>
*
* @author Robert Garmann
* @version 0.9
*/
public class BezierCurve {

/**
* Konstruktor. Definiert die Kontrollpunkte, und damit auch den Grad.
*/
public BezierCurve(Point[] p) {
controlPoints= p;
}

private Point[] controlPoints;


/**
* Grad der Bezierkurve.
*/
public int degree() {
if (controlPoints == null) { return -1; }
return controlPoints.length -1;
}

/**
* Selektor. Liefert den i-ten Kontrollpunkt (i=0..Grad-1).
*/
public Point getControlPoint(int i) {
if ( (i<0) || (i>degree()) ) {
throw new java.lang.IndexOutOfBoundsException
("BezierCurve.getControlPoint("+i+"), degree is "+degree()+".");
}
return controlPoints[i];
}

public Point[] getControlPoints(){
return controlPoints;
}

/**
* Textausgabe. Formatiert einen String, der das Kontrollpolygon
* zur Textausgabe enth&auml;lt.
*/
public String toString() {
String s= " i | control point \n";
s = s + "----------------------\n";
for (int j=0; j<=degree(); j++) {
Point pt= getControlPoint(j);
s = s + " "+j+" | "+pt + "\n";
}
return s;
}

/**
* Berechnet zwei neue Bezierkurven durch Unterteilung am Parameterwert t.
* Der Parameter t sollte in [0,1] liegen. die beiden zur"uckzugebenden
* Kurven werden alls Array von 2 Kurven geliefert.
*/
public BezierCurve[] subdivide(double t) {
if ( (t<0.0) || (t>1.0) ){
System.out.println("BezierCurve.subdivide: t = "+t+
" should be in [0,1]");
}

// kontrollpunkte der subkurven
Point2D[] curve1 = new Point2D[controlPoints.length];
Point2D[] curve2 = new Point2D[controlPoints.length];

curve1[0] = (Point2D) controlPoints[0];
curve2[curve2.length - 1] = (Point2D) controlPoints[curve2.length - 1];

// array mit temporären werten vorbereiten
Point2D[] temp = new Point2D[controlPoints.length];
for(int i=0; i<temp.length; i++)
temp[i] = (Point2D)controlPoints[i];

for(int j=1; j<temp.length; j++){

// unterteilung
for(int i=0; i < (temp.length-j); i++){
double x = ((1-t)*temp[i].getX()) + (t*temp[i+1].getX());
double y = ((1-t)*temp[i].getY()) + (t*temp[i+1].getY());
temp[i] = new Point2D(x, y);
}
curve1[j] = temp[0];
curve2[(curve2.length-1)-j] = temp[(temp.length-1)-j];
}

BezierCurve[] result = new BezierCurve[2];
result[0]= new BezierCurve(curve1);
result[1]= new BezierCurve(curve2);

return result;
}


/**
* Berechnet einen Kurvenpunkt. Der Parameterwert t soll zwischen 0 und
* 1 liegen.
*/
public Point getCurvePoint(double t) {
if((t < 0.0) || (t > 1.0)){
System.out.println("BezierCurve.getCurvePoint: t = "+t+
" should be in [0,1]");
}
Point result;

// array mit temporären werten vorbereiten
Point2D[] temp = new Point2D[controlPoints.length];
for(int i=0; i<temp.length; i++)
temp[i] = (Point2D)controlPoints[i];

for(int j=1; j<temp.length; j++){

// unterteilung
for(int i=0; i < (temp.length-j); i++){
double x = ((1-t)*temp[i].getX()) + (t*temp[i+1].getX());
double y = ((1-t)*temp[i].getY()) + (t*temp[i+1].getY());
temp[i] = new Point2D(x, y);
}
}


return temp[0];
}
}


BezierDrawer.java, malt so eine Kurve, ist so eine Art Canvas... die Oberklasse Drawer stammt wohl aus gl4java, das wir dafür benutzt haben


package grog;

/**
* Diese Klasse enth&auml;lt Zeichenroutinen, um eine
* Bezierkurve in der Ebene zu zeichnen. Dies geschieht durch wiederholte
* Unterteilung des Kontrollpolygonzuges. Die Tiefe der Wiederholungen
* kann angegeben werden.
*
* @author Robert Garmann
* @version 0.9
*/

public class Bezier2DDrawer
extends Drawer {
//
// interne Daten:
//
private BezierCurve myCurve;
private int myDepth;
private double red= 0.0, green= 0.0, blue= 0.0;

private BezierCurve[] curves; // die einzelnen kurven

/**
* Konstruktor. Die Kurve c soll durch rekursive Unterteilung
* bis zur Rekursionstiefe depth gezeichnet werden.
*/
public Bezier2DDrawer(BezierCurve c, int depth) {
myCurve= c;
myDepth= depth;

curves = new BezierCurve[1];
curves[0] = c;

while(depth > 0){
BezierCurve[] temp = new BezierCurve[curves.length*2];
for(int i=0; i<curves.length; i++){
BezierCurve[] subcurve = curves[i].subdivide(0.5);
temp[2*i] = subcurve[0];
temp[(2*i)+1] = subcurve[1];
}
curves = temp;
depth--;
}
}



/**
* Zeichenfarbe setzen.
*/
public void setColor(double r, double g, double b) {
red= r; green= g; blue= b;
}


/**
* Zeichnet die Kurve approximativ durch rekursives Unterteilen. <br>
* Falls depth=0, so wird einfach das Kontrollpolygon gezeichnet.<br>
* Falls depth=1, so wird einmal unterteilt und die beiden
* resultierenden Kontrollpolygonz&uuml;ge werden gezeichnet.<br>
* Falls depth=2, so werden 4 Kontrollpolygonz&uuml;ge gezeichnet.<br>
* usw.
*/
public void draw() {
glColor3d(red, green, blue);

for(int i=0; i<curves.length; i++){
glBegin(GL_LINE_STRIP);
Point[] cp = curves[i].getControlPoints();
for(int j=0; j < cp.length; j++){
Point2D p = (Point2D)cp[j];
glVertex2d(p.getX(), p.getY());
}
glEnd();
}
}
}


Und zu guter letzt die Klasse mit der main Methode, irgendwie über Umwege aus Frame bzw. dessen GL4Java Pendant abgeleitet.

package grog;
import java.awt.Dimension;

/**
* <p>
* Diese Klasse enth&auml;lt das Hauptprogramm zum Unterteilen von
* Bezierkurven und zum Zeichnen derselben.
* </p>
*
* @author Robert Garmann
* @version 0.9
* @see BezierCurve
* @see Bezier2DDrawer
*/

public class BezierMain {

public static void main( String args[] ) {
Point[] cp = {new Point2D(-5, -5), new Point2D(-6, 2),
new Point2D(0, 5), new Point2D(6, 2), new Point2D(5, -5)};

BezierCurve curve = new BezierCurve(cp);
Point2D point = (Point2D)curve.getCurvePoint(0.3);
BezierCurve[] subcurves = curve.subdivide(0.6);

System.out.println(point.toString());
System.out.println(subcurves[0].toString());
System.out.println(subcurves[1].toString());

Simple2DFrame frame = new Simple2DFrame("Bezierkurven",
-10f, 10f, -10f, 10f, 300, 300);

// x-achse
HyperPlane2DDrawer x_axis = new HyperPlane2DDrawer(new HyperPlane(
new Point2D(0.0d, 1.0d), 0.0d));
x_axis.setColor(0.5d, 0.5d, 0.5d);
frame.addDrawer(x_axis);

// y-achse
HyperPlane2DDrawer y_axis = new HyperPlane2DDrawer(new HyperPlane(
new Point2D(1.0d, 0.0d), 0.0d));
y_axis.setColor(0.5d, 0.5d, 0.5d);
frame.addDrawer(y_axis);

// bezierzeichner
Bezier2DDrawer bezier1 = new Bezier2DDrawer(curve, 0);
bezier1.setColor(0.0d, 0.0d, 0.0d);
frame.addDrawer(bezier1);

Bezier2DDrawer bezier2 = new Bezier2DDrawer(curve, 1);
bezier2.setColor(0.0d, 0.0d, 1.0d);
frame.addDrawer(bezier2);

Bezier2DDrawer bezier3 = new Bezier2DDrawer(curve, 2);
bezier3.setColor(1.0d, 0.0d, 0.0d);
frame.addDrawer(bezier3);

Bezier2DDrawer bezier4 = new Bezier2DDrawer(curve, 3);
bezier4.setColor(0.0d, 1.0d, 0.0d);
frame.addDrawer(bezier4);

frame.setSize(300, 300);
frame.setVisible(true);
}
}


Grüße, Jan

piepre
2003-04-14, 15:14:18
jo, danke erstmal.

werde mal gucken ob ich damit weiterkomme.

Frank
2003-04-15, 00:12:08
Ich kann dir dahingehend bis jetzt nur Fortran 95 Code anbieten. Aber eher sehr unübersichtlich. Bald auch C++. Wenn du noch n'bissl wartest gibts evtl bald was zu lesen dazu...

Noch ein Tip:
Bézierkurven mit den Standard de Casteljau Algo zu rechnen ist rechnerischer Overkill. Nimm den Unterteilungsalgo davon.