Koordinaten einer Linie berechnen



  • Guten Morgen,
    ich zeichne mittels MoveTo() und LineTo() eine Linie. Nun möchte ich jedes Pixel dieser Linie durchlaufen und die Farbe des Pixels auslesen. Meine Idee ist also jede Koordinate auszulesen, allerdings weiss ich nicht wie ich aus der Linie die einzelnen Koordinaten bekomme. Weiss vielleicht jemand wie die das am besten anstellen könnte?
    Gruß
    Daniel



  • Wenn du nur gerade Linien zeichnest, dürfte die Berechnung ja einfach sein -)

    Bei beliebigen Linien müßtest du ja wissen, welcher Rasterungsalgorithmus intern verwendet wird, um die Linie exakt (Pixel für Pixel) auszulesen.
    Der am meisten eingesetzte dafür ist der Bresenham-Algorithmus (http://de.wikipedia.org/wiki/Bresenham-Algorithmus).

    Ansonsten einfach die Linie selber Pixel für Pixel zeichnen (dann weißt du auch die einzelnen Pixelwerte)...

    Hier noch eine Klasse, welche ich selber mal entwickelt habe:

    //---------------------------------------------------------------------------
    #include <vcl\vcl.h>
    #pragma hdrstop
    
    #include "CBitmap.h"
    #include <stdlib>
    #include <math.h>
    //---------------------------------------------------------------------------
    
    CBitmap::CBitmap(TCanvas *cv)
      :	m_cv(cv)
    {
    }
    
    inline void CBitmap::SetPixel(int x, int y)
    {
    	m_cv->Pixels[x][y] = m_cl;
    }
    
    inline TColor CBitmap::GetPixel(int x, int y)
    {
    	return m_cv->Pixels[x][y];
    }
    
    void CBitmap::DrawLine(int x1, int y1, int x2, int y2)
    {
    	if(x2-x1 >= y2-y1)
    	{
    		double y = y1,
    			  dy = double(y2-y1+1) / double(x2-x1+1);
    
    		for(int x=x1; x<=x2; x++)
    		{
    			SetPixel(x, y);
    			y += dy;
    		}
    	}
    	else
    	{
    		double x = x1,
    			  dx = double(x2-x1+1) / double(y2-y1+1);
    
    		for(int y=y1; y<=y2; y++)
    		{
    			SetPixel(x, y);
    			x += dx;
    		}
    	}
    }
    
    void CBitmap::DrawRect(int x1, int y1, int x2, int y2)
    {
    	DrawLine(x1, y1, x2, y1);
    	DrawLine(x2, y1, x2, y2);
    	DrawLine(x1, y1, x1, y2);
    	DrawLine(x1, y2, x2, y2);
    }
    
    void CBitmap::DrawEllipse(int x, int y, int rx, int ry)
    {
    	int px, py;
    	double delta_angle = 1.0 / max(x, y);
    	for(double angle=0; angle<2*M_PI; angle += delta_angle)
    	{
    		px = x + floor(rx * sin(angle) + 0.5);
    		py = y - floor(ry * cos(angle) + 0.5);
    		SetPixel(px, py);
    	}
    
    }
    
    void CBitmap::Fill(int x, int y)
    {
    	m_fill_cl = GetPixel(x, y);
    	if(m_fill_cl != m_cl)
    		Fill1(x, y);
    }
    
    void CBitmap::Fill1(int x, int y)
    {
    	TRect &r = m_cv->ClipRect;
    	int xx, yy;
    
    	xx = x, yy = y;
    	while(yy >= r.Top && GetPixel(xx, yy) == m_fill_cl)
    	{
    		Fill1_Line(xx, yy);
    		yy--;
    	}
    
    	xx = x+1, yy = y+1;
    	while(yy <= r.Bottom && GetPixel(xx, yy) == m_fill_cl)
    	{
    		Fill1_Line(xx, yy);
    		yy++;
    	}
    }
    
    void CBitmap::Fill1_Line(int x, int y)
    {
    	TRect &r = m_cv->ClipRect;
    	int xx, yy = y;
    
    	xx = x;
    	while(xx >= r.Left && GetPixel(xx, yy) == m_fill_cl)
    	{
    		SetPixel(xx, yy);
    		xx--;
    	}
    
    	xx = x + 1;
    	while(xx <= r.Right && GetPixel(xx, yy) == m_fill_cl)
    	{
    		SetPixel(xx, yy);
    		xx++;
    	}
    }
    
    /*
    void CBitmap::Fill1(int x, int y)
    {
    	static int nDepth = 0;
    
    	nDepth++;
    	if(nDepth < 10000)
    	{
    		TRect &r = m_cv->ClipRect;
    		if(x >= r.Left && x <= r.Right &&
    		   y >= r.Top && y <= r.Bottom &&
    		   GetPixel(x, y) == m_fill_cl)
    		{
    			SetPixel(x, y);
    			Fill1(x-1, y);
    			Fill1(x+1, y);
    			Fill1(x, y-1);
    			Fill1(x, y+1);
    		}
    	}
    	nDepth--;
    }
    */
    
    void CBitmap::Fill(int x, int y, TColor clOutline)
    {
    	m_fill_cl = clOutline;
    	Fill2(x, y);
    }
    
    void CBitmap::Fill2(int x, int y)
    {
    	TRect &r = m_cv->ClipRect;
    	int xx, yy;
    
    	xx = x, yy = y;
    	while(yy >= r.Top && GetPixel(xx, yy) != m_fill_cl)
    	{
    		Fill2_Line(xx, yy);
    		yy--;
    	}
    
    	xx = x+1, yy = y+1;
    	while(yy <= r.Bottom && GetPixel(xx, yy) != m_fill_cl)
    	{
    		Fill2_Line(xx, yy);
    		yy++;
    	}
    }
    
    void CBitmap::Fill2_Line(int x, int y)
    {
    	TRect &r = m_cv->ClipRect;
    	int xx, yy = y;
    
    	xx = x;
    	while(xx >= r.Left && GetPixel(xx, yy) != m_fill_cl)
    	{
    		SetPixel(xx, yy);
    		xx--;
    	}
    
    	xx = x + 1;
    	while(xx <= r.Right && GetPixel(xx, yy) != m_fill_cl)
    	{
    		SetPixel(xx, yy);
    		xx++;
    	}
    }
    
    /*
    void CBitmap::Fill2(int x, int y)
    {
    	static int nDepth = 0;
    
    	nDepth++;
    	if(nDepth < 10000)
    	{
    		TRect &r = m_cv->ClipRect;
    		if(x >= r.Left && x <= r.Right &&
    		   y >= r.Top && y <= r.Bottom &&
    		   GetPixel(x, y) != m_fill_cl)
    		{
    			SetPixel(x, y);
    			Fill2(x-1, y);
    			Fill2(x+1, y);
    			Fill2(x, y-1);
    			Fill2(x, y+1);
    		}
    	}
    	nDepth--;
    }
    */
    
    void CBitmap::DrawRegularPolygon(int x, int y, int r, int n, int angle)
    {
    	if(n <= 2) return;	// No Polygon
    
    	m_cv->Pen->Color = m_cl;
    
    	double d_angle = angle * M_PI / 180.0;
    	int sx = x + floor(r * sin(d_angle) + 0.5);
    	int sy = y - floor(r * cos(d_angle) + 0.5);
    
    	m_cv->MoveTo(sx, sy);
    
    	double delta_angle = 2 * M_PI / n;
    	int px, py;
    	for(int i=0; i<n; i++)
    	{
    		d_angle += delta_angle;
    		px = x + floor(r * sin(d_angle) + 0.5);
    		py = y - floor(r * cos(d_angle) + 0.5);
    		m_cv->LineTo(px, py);
    	}
    
    	m_cv->LineTo(sx, sy);
    }
    


  • d@niel schrieb:

    ...
    ich zeichne mittels MoveTo() und LineTo() eine Linie. Nun möchte ich jedes Pixel dieser Linie durchlaufen und die Farbe des Pixels auslesen.

    Hi,

    warum machst du dir die Mühe? Bei MoveTo/LineTo wird die Linie in der Farbe
    gezeichnet, die dem aktuellen Pen-Wert entspricht. Der Farbwert steht also bereits fest und ist für jedes Pixel der Linie gleich.

    mfg
    kpeter



  • kpeter schrieb:

    Der Farbwert steht also bereits fest und ist für jedes Pixel der Linie gleich.

    Hallo,

    und selbst wenn nicht (wenn er die Linie durch viele einzelne Punkte erzeugt), ist die Farbe im Voraus bekannt und kann "zwischengespeichert" werden - um sie im Nachhinein weiter zu verwenden. Aber vielleicht erkennen wir auch den Sinn der Aktion noch nicht 😃

    LG, Micha



  • RandomAccess85 schrieb:

    Aber vielleicht erkennen wir auch den Sinn der Aktion noch nicht 😃

    Wird so sein 😉

    Vielleicht will er ja die Pixels einzeln umfärben.
    Im übrigen errechnet die Funktion selbst die zu zeichnenden Pixel. Also
    fragt man während der Draw-Messages die Pixelpositionen ab und wechselt ggf.
    den Pen.

    mfg
    kpeter



  • Hi,

    anstatt MoveTo/LineTo kommt die WinAPI-Funktion LineDDA kommt dem Vorhaben am
    nächsten.

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       LineDDA( 200, 0, 5, 255, (LINEDDAPROC)LineDDACallBack, NULL );
       // oder andere Werte
    }
    //---------------------------------------------------------------------------
    
    VOID CALLBACK LineDDACallBack( int X, int Y, LPARAM lParam )
    {
       Form1->Image1->Canvas->Pixels[X][Y] = RGB(0, 0, 0);
       // und hier zur Kontrolle die Pixel, in denen gezeichnet wurde:
       Form1->Memo1->Lines->Add("X: " + IntToStr(X) + ", Y: " + IntToStr(Y));
    }
    

    Die Callbackfunktion wird solange aufgerufen, bis die Linie gezeichnet ist.

    mfg
    kpeter



  • Hallo,
    vielen Dank für die Antworten und sorry für meine späte Antwort.
    Mal kurz etwas zu dem Hintergrund meiner Frage. Ich lade ein Bild und ziehe darauf eine Linie. Nun möchte ich halt diese Linie durchgehen und nicht die Farbe der Linie auslesen, sondern die Farbe der einzelnen Pixel die unter dieser Linie sind.
    Werde mir Eure Antworten mal in ruhe anschauen und ein wenig rumprobieren.
    Gruß
    Daniel



  • Hallo

    Dann ist LineDDA das richtige für dich. Denn in der CallBack-Funktion kannst du statt einen Farbwert zu setzen ja den bestehenden Farbwert auslesen.

    bis bald
    akari



  • So,
    verwende nun LineDDA und es funktioniert alles bestens.Vielen Dank!
    Gruß


Anmelden zum Antworten