Wie zeichnet man "gedrehte" Ellipsen?
-
Einfach ein Kreis in einen VB packen und dann nach Belieben Verzerren und Drehen per Matrize. f'`8k
Gruß, TGGC (\-/ has leading)
-
hellihjb schrieb:
fuer jeden punkt (x,y) auf dem rand einer (nicht gedrehten) ellipse gibt es einen winkel a mit dem gilt:
x= sin(a) * radiusX + centerX y= cos(a) * radiusY + centerYwill man diese ellipse nun fuellen, loest man einfach nach a auf, macht eine schleife ueber alle scanlines
und berechnet daraus x bzw x1,x2 (rechter und linker rand, hier jeweils mit +/- radiusX):a= acos((y-centerY)/radiusY)fuer die rotation um einen winkel r fuegst du einfach noch die entsprechende matrix in die obere gleichung ein und loest das lgs wieder nach a auf.
um nur die outline zu erhalten, zeichnest du einfach horizontale linien vom aktuellen zum vorherigen x1/x2.mit Rotation (wobei beta der Rotationswinkel ist) ohne Verschiebung müsste die Gleichung doch so aussehen:
y = sin(beta)*sin(a)*radiusX + cos(beta) * cos(a) * radiusY
wenn ich die Gleichung jetzt mit einem Algebra System nach a auflöse kommt etwas sehr hässliches raus
- hab ich was falsch gemacht...?BTW das Ergebnis des Algebra Systems:
a=\arctan \left( \left( y+{\frac {\cos \left( \beta \right) \left( y \cos \left( \beta \right) {\it radiusY}+\sqrt {{y}^{2} \left( \cos \left( \beta \right) \right) ^{2}{{\it radiusY}}^{2}- \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}{y}^{2}+ \left( \sin \left( \beta \right) \right) ^{4}{{\it radiusX}}^{4}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}{y}^{2}-{{ \it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{4}{{\it radiusX}}^{2}-{{\it radiusY}}^{2}{y}^{2}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}} \right) { \it radiusY}}{- \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}-{{\it radiusY}}^{2}}} \right) \left( \sin \left( \beta \right) \right) ^{-1}{{\it radiusX}}^{-1},-{\frac {y\cos \left( \beta \right) {\it radiusY}+\sqrt {{y}^{2} \left( \cos \left( \beta \right) \right) ^{2}{{\it radiusY}}^{2}- \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}{y}^{2}+ \left( \sin \left( \beta \right) \right) ^{4}{{\it radiusX}}^{4}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}{y}^{2}-{{\it radiusY}} ^{2} \left( \sin \left( \beta \right) \right) ^{4}{{\it radiusX}}^{2} -{{\it radiusY}}^{2}{y}^{2}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}}}{- \left( \sin \left( \beta \right) \right) ^{2}{{\it radiusX}}^{2}+{{\it radiusY}}^{2} \left( \sin \left( \beta \right) \right) ^{2}-{{\it radiusY}}^{2}}} \right)
-
ein punkt (x,y) einer rotierten ellipse ist:
x= c*sin(a)*rx + s*cos(a)*ry + cx; y= s*sin(a)*rx - c*cos(a)*ry + cy;mit:
a= winkel auf der ellipse
c,s= komponenten der rotationsmatrix: cos(rotation), sin(rotation)
rx,ry= radius horizontal/vertikal
cx,cy= zentrum der ellipsedas ganze loest du nach a auf und bekommst a in abhaengigkeit von x, also zwei loesungen fuer anfang und ende jeder scanline y.
y kannst du einfach einsetzen in dem du die obere und untere grenze der ellipse anhand der rotationsmatrix berechnest.
-
das ganze loest du nach a auf und bekommst a in abhaengigkeit von x, also zwei loesungen fuer anfang und ende jeder scanline y.
sorry das ich mich so blöd stelle, aber genau das Auflösen nach a schaffe ich nicht
wenn ich jetzt y= s*sin(a)*rx - c*cos(a)*ry + cy nach a auflösen soll... mmh...
y-cy= s*sin(a)*rx - c*cos(a)*ry dann weiß ich nicht mehr weiter - nehme ich ein Algebra System zur Hilfe kommt eine Mördergleichung raus
mir fällt nicht ein wie ich sin(a) duruch cos(...) ersetzen kann und dann auf irgendwas quadratsiches kommme um daraus die Wurzel zu ermitteln... mmh...
-
da du jeweils eine gleichung fuer x und y hast, kannst du die ueblichen schemata fuer lineare gleichungssysteme anwenden.
-
da du jeweils eine gleichung fuer x und y hast, kannst du die ueblichen schemata fuer lineare gleichungssysteme anwenden.
wenn man da einfach drauflos rechnet kommt am Ende nur mist raus - hab heute 2 Stunden rumgerechnet und bin auf keinen grünen Zweig gekommen - hab jetzt eine gute Herleitung gefunden - werde es mal die nächsten Tage implementerien
-
Öhm. Vorweg: ich bin kein Mathe-Crack. Aber. Du kannst ja aus einem Einheitskreis eine Elipse machen, indem du den Kreis (=alle Punkte des Kreises) einfach mit einer Matrixmultiplikation stauchst + rotierst, oder?
Dann müsste es doch gehen wenn du für jede Scanline (Bildschirmzeile) eine Line ziehst (Punkt + Vektor), und dann diese Linie (also den Punkt und den Vektor) mit der inversen Matrix transformierst. Dann hast du die Scanline die die Ellipse schneiden soll so transformiert dass du die Schnittpunkt einfach mit dem Einheitskreis ermitteln kannst (d.h. du hast sie quasi in ein Koordinatensystem überführt indem das zu schneidende Objekt nunmehr keine Ellipse sondern ein Einheitskreis ist). Der Schnitt mit dem Einheitskreis sollte relativ einfach durchführbar sein. Wenn du die Schnittpunkte in diesem Koordinatensystem (oder "Raum" oder wie man es richtig nennt - keinen Ahnung) hast, dann transformierst du die Schnittpunkte mittels der ursprünglichen Matrix (der "vorwärts" Matrix) wieder zurück in den Bildschirm-Raum, und fertig. Dann hast du für jede Zeile ein oder zwei Schnittpunkte - und damit lässt sich die Ellipse zeichnen (du musst halt u.U. mehrere Punkte nebeneinander in eine Zeile packen wenn die Punkte darunter mehr als 1 Pixel versetzt sind - aber das ist trivial wie ich denke).
Ich weiss nicht ob das die schnellste Lösung ist (wohl eher nicht), dafür sollte sie halbwegs überschaubar bleiben. Denke ich.
Sach mal was du davon hältst.
-
dann transformierst du die Schnittpunkte mittels der ursprünglichen Matrix (der "vorwärts" Matrix) wieder zurück in den Bildschirm-Raum,
das Problem ist das Rotieren - bei der Rotation landen die meisten Pixel nicht genau auf einem anderen Pixel, sondern irgendwie "dazwischen" - das macht es Problematisch
ich arbeite derzeit mit folgendem code:
float tx = 200; float ty = 200; float a = 100; float bs = 100/2; Matrix22f R = Matrix22fRotationOrgin(DegreeToRad(30.0f)); Matrix22f I = Matrix22fTranspose(R); Matrix22f E; E.m_11 = 1.0f/(a*a); E.m_22 = 1.0f/(bs*bs); Matrix22f S = R * E * I; for (int x = -a; x <= a; x++) { float dummy1 = ((S.m_12*x+S.m_21*x)*(S.m_12*x+S.m_21*x))-4.0f*S.m_22*(S.m_11*x*x-1); float wurzel = sqrt(dummy1); float y1 = (-((S.m_12*x+S.m_21*x)+wurzel))/(2.0f*S.m_22); float y2 = (-((S.m_12*x+S.m_21*x)-wurzel))/(2.0f*S.m_22); b.setPixelColorWithClipping(tx+x,ty+y1+0.5f,ColorA8R8G8B8(0,255,0)); b.setPixelColorWithClipping(tx+x,ty+y2+0.5f,ColorA8R8G8B8(0,255,0)); } for (int y = -bs; y <= bs; y++) { float dummy1 = ((S.m_12*y+S.m_21*y)*(S.m_12*y+S.m_21*y))-4.0f*S.m_11*(S.m_22*y*y-1); float wurzel = sqrt(dummy1); float x1 = (-((S.m_12*y+S.m_21*y)+wurzel))/(2.0f*S.m_11); float x2 = (-((S.m_12*y+S.m_21*y)-wurzel))/(2.0f*S.m_11); b.setPixelColorWithClipping(tx+x1+0.5f,ty+y,ColorA8R8G8B8(0,255,0)); b.setPixelColorWithClipping(tx+x2+0.5f,ty+y,ColorA8R8G8B8(0,255,0)); }
-
Hier die Beschreibung dazu:
http://loop.servehttp.com/~vertexwahn/uploads/Mittelpunkt.pdf
-
ich zeichne Kreisbögen so. wenn xRadius und yRadius sowie DegreeBegin und DegreeEnd entsprechend gesetzt sind, zeichnet das nen Ellipse (oder Kreis, wenn die Radii übereinstimmen). Phi gibt den Rotationswinkel an. Kreise selber zeichne ich in eine Extrafunktion mittels Bresenham.
//--------------------------------------------------------------------------- // Funktion zeichnet einen Kreisbogen. // -> 'X' und 'Y' bilden den Mittelpunkt // -> 'RadiusX' und 'RadiusY' legen den Radius in x- bzw. y-Richtung fest // -> 'Phi' bestimmt den Winkel um den der Kreisbogen gedreht werden soll // -> 'Color' ist ein RGB-Triple // -> 'Opacity' Deckungsgrad //--------------------------------------------------------------------------- template <typename T> void Image<T>::DrawArc(int xCenter, int yCenter, const double xRadius, const double yRadius, const double Phi, const int DegreeBegin, const int DegreeEnd, const T &Color, const float Opacity) { int LastX = 0; int LastY = 0; bool Closed = aiLibMath::Abs(DegreeEnd - DegreeBegin) == 360; // Tortenstücke zeichnen double SinPhi = aiLibMath::Sin(Phi); double CosPhi = aiLibMath::Cos(Phi); double SinPos; double CosPos; int NextX; int NextY; double Pos; // Kreisbogen zwischen 'DegreeBegin' und 'DegreeEnd' zeichnen for (int i = DegreeBegin; i <= DegreeEnd; ++i) { // Schrittweite pro Punkt Pos = aiLibMath::DegreeToArc(i); SinPos = aiLibMath::Sin(Pos) * yRadius; CosPos = aiLibMath::Cos(Pos) * xRadius; // neue x und y Koordinaten berechnen und zusaetzlich um 'Phi' drehen NextX = aiLibMath::Round(xCenter + (CosPos * CosPhi) + (SinPos * SinPhi)); NextY = aiLibMath::Round(yCenter - (SinPos * CosPhi) + (CosPos * SinPhi)); // ist Position innerhalb des Bildes? if (!InRange(NextX, 0, (int) this->xDim) || !InRange(NextY, 0, (int) this->yDim)) continue; if (!InRange(LastX, 0, (int) this->xDim) || !InRange(LastY, 0, (int) this->yDim)) continue; if ((i == DegreeBegin) && !Closed) DrawLine(xCenter, yCenter, NextX, NextY, Color, Opacity); // Linie zum Zielpunkt zeichnen if (i != DegreeBegin) DrawLine(LastX, LastY, NextX, NextY, Color, Opacity); LastX = NextX; LastY = NextY; } if (!Closed) DrawLine(xCenter, yCenter, LastX, LastY, Color, Opacity); }