Laden...

Berechnung von Schnittpunkten auf 2 Geraden des Polygons

Erstellt von Garzec vor 7 Jahren Letzter Beitrag vor 7 Jahren 7.090 Views
G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren
Berechnung von Schnittpunkten auf 2 Geraden des Polygons

Hallo 🙂

ich versuche den Schnittpunkt von zwei Geraden zu berechnen. Benötigen tue ich das für eine Berechnung einer Fläche eines zufällig generierten Polygons. Mir geht es hierbei aber erstmal nur um die Schnittpunktberechnung. Momentan sieht diese so aus:



private void SchnittpunktBerechnung(int startIndex1, int startIndex2)
        {
            //Strecke AB = Punkt1 + s * (Punkt2 - Punkt1)
            //Strecke CD = Punkt3 + t * (Punkt4 - Punkt3)

            int endeIndex1 = startIndex1 + 1;
            int endeIndex2 = startIndex2 + 1;

            Point start1 = punktListe[startIndex1];
            Point ende1 = punktListe[endeIndex1];
            Point start2 = punktListe[startIndex2];
            Point ende2 = punktListe[endeIndex2];

            // Streckenfarben

            Color farbe1 = farbenListe[startIndex1];
            Color farbe2 = farbenListe[startIndex2];

            // Punkte

            int x1 = start1.X;      //Punkt1 X
            int x2 = ende1.X;       //Punkt2 X
            int x3 = start2.X;      //Punkt3 X
            int x4 = ende2.X;       //Punkt4 X

            int y1 = start1.Y;      //Punkt1 Y
            int y2 = ende1.Y;       //Punkt2 Y
            int y3 = start2.Y;      //Punkt3 Y
            int y4 = ende2.Y;       //Punkt4 Y

            // Konstanten

            int mx = x2 - x1;
            int nx = x3 - x4;  //x4 - x3;
            int ox = x3 - x4;  //x3 - x1;

            int my = y2 - y1;
            int ny = y3 - y4;  //y4 - y3;
            int oy = y3 - y4;  //y3 - y1;

            // Determinanten

            int d1 = mx * ny - my * nx;
            int d2 = ox * ny - oy * nx;
            int d3 = mx * oy - my * ox;

            // Fallunterscheidung

            if (d1 == d2 && d1 == d3 && d1 == 0)
            {
                Console.WriteLine("Strecken liegen aufeinander");    //------- TEST
            }
            else if (d1 == 0 && d2 != 0 && d3 != 0)
            {
                Console.WriteLine("kein Schnittpunkt");    //------- TEST
            }
            else if (d1 != 0)
            {
                Console.WriteLine("Schnittpunkt");    //------- TEST
            }

            // s und t

            double s = 1F * d2 / d1;
            double t = 1F * d3 / d1;

            // Überprüfung s und t

            Console.WriteLine("Strecke: " + farbe1 + "Strecke: " + farbe2);    //------- TEST

            if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
            {
                Console.WriteLine("Schnittpunkt auf den Strecken");    //------- TEST
            }
            else
            {
                Console.WriteLine("Schnittpunkt auf den Geraden aber nicht auf den Strecken");    //------- TEST
            }

            // Schnittpunktberechnung

            int sx = Round(x1 + s * (x2 - x1));
            int sy = Round(y1 + s * (y2 - y1));

            // Schnittpunkt

            Point schnittPunkt = new Point(sx, sy);

            Console.WriteLine(schnittPunkt);    //------- TEST

            Console.WriteLine("s: " + s + " t: " + t);

            Console.WriteLine("************************************************************");    //------- TEST
        }


Das Problem an der Sache ist, das bei meiner Testroutine immer s=0 und t=1 ist. Und das Problem liegt wohl oben bei den Konstanten. Rechts auskommentiert habe ich meine vorherige Berechnung, diese stimmte aber auch nicht ganz. Kennt ein Mathe-Ass die richtige Rechnung? 😜

3.003 Beiträge seit 2006
vor 7 Jahren
  
int mx = x2 - x1;  
int nx = x3 - x4;  //x4 - x3;  
int ox = x3 - x4;  //x3 - x1;  
  
int my = y2 - y1;  
int ny = y3 - y4;  //y4 - y3;  
int oy = y3 - y4;  //y3 - y1;  
  

Bisschen komisch, nicht? Copy&Paste ist NICHT dein Freund.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Das es sich bei nx und ox doppelt ist vom Abschreiben richtig, falls du das meinst.

Deswegen ja meine Frage nach dem Fehler in der Berechnung 😕

3.003 Beiträge seit 2006
vor 7 Jahren

Ich meinte nicht nur das, sondern auch, dass die Kommentare nicht dazu passen. Wenn wir das jetzt bei uns ausprobieren, sollen wir raten, was du uns sagen wolltest?

Ansonsten ist die Berechnung 1:1 so wie hier erklärt. Wenn du nachvollziehen möchtest, wo es schief geht: [Artikel] Debugger: Wie verwende ich den von Visual Studio? sollte dir helfen. Nur vom draufschaun wird einem bei deiner Wahl von Variablenbezeichnungen eher schwindlig, als dass man einen Fehler sieht - will sagen, letzten Endes können wir für dich auch nur debuggen, und das kannst du besser selber 😃.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Achso sorry, ich hatte unten noch geschrieben, dass die Kommentare rechts einfach nur meine ursprüngliche "Berechnung" war. Also das, was vorher da stand.

Den Debugger hatte ich schon benutzt, daher weiß ich ja das s immer 0 ist und t immer 1. Führe ich das ganze zurück sind oben die Startberechnungen falsch.

Du hast Recht, dass ich das am Besten selber rausfinden kann, trotzdem dachte ich vielleicht erkennt jemand oben schon den Fehler.

3.003 Beiträge seit 2006
vor 7 Jahren

Na, du sagst ihm doch, dass s immer null sein soll, und zwar hier:


int d2 = ox * ny - oy * nx; 
double s = 1F * d2 / d1;
 

und weil bei dir, wie ich schrieb, ox == nx und oy == ny, ist d2 immer null, und sist 0/irgendwas, was auch immer 0 ist. Deshalb nochmal die Frage, was du dort oben mit den ox, nx, oy, ny treibst.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Ich habe meine Berechnung abgeändert, s wird jetzt auch nicht mehr 0. mx,nx,ox, .... dienen eigentlich nur als Zwischenschritte. Ich könnte unten in die Rechnung ja auch direkt die variablen eingeben, aber dann würde es denke ich zu unübersichtlich und die Berechnung zu groß/lang.

Das Ganze sieht nun so aus:



            int x1 = start1.X;      //Punkt1 X
            int x2 = ende1.X;       //Punkt2 X
            int x3 = start2.X;      //Punkt3 X
            int x4 = ende2.X;       //Punkt4 X

            int y1 = start1.Y;      //Punkt1 Y
            int y2 = ende1.Y;       //Punkt2 Y
            int y3 = start2.Y;      //Punkt3 Y
            int y4 = ende2.Y;       //Punkt4 Y

            // Konstanten

            int mx = x2 - x1;
            int nx = x4 - x3;
            int ox = x3 - x1;

            int my = y2 - y1;
            int ny = y4 - y3;
            int oy = y3 - y1;

            // Determinanten

            int d1 = mx * ny - my * nx;
            int d2 = ox * ny - oy * nx;
            int d3 = mx * oy - my * ox;

            // s und t

            double s = 1F * d2 / d1;
            double t = 1F * d3 / d1;

            // Schnittpunktberechnung

            int sx = Round(x1 + s * (x2 - x1));
            int sy = Round(y1 + s * (y2 - y1));


Dennoch erkennt er die Schnittpunkte nicht richtig. Mache ich noch etwas falsch?

P
1.090 Beiträge seit 2011
vor 7 Jahren

Wenn du den Schnitt 2er Graden berechnen willst. Bestimme die beiden Graden Gleichungen.

F1(x) = m1x + b1 und F1(x) = m1x + b2

wobei

m1 = (y2-y1) / (x2-x2)

und

b1 = y1 - m*x1

(Für F2 natürlich auch bestimmen)

Und setze diese gleich.
F1(x) = F2(x)
m1x + b1 = m2x +b2

=>
x = (b2-b1) / (m1 - m2)

x dann in F1 oder F1 einsetzen und den y Wert bestimmen.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

3.003 Beiträge seit 2006
vor 7 Jahren

Edit, @palin: sein Algo stimmt schon^^

Rundungsfehler, 100%.


int sx = Round(x1 + s * (x2 - x1));
int sy = Round(y1 + s * (y2 - y1));

Erstens ist int denkbar ungeeignet für Schnittpunkte, zweitens habe ich keine Ahnung, welches Round() du da aufrufst. Für sx/sy als float oder double liefert er mir ausreichend genaue Ergebnisse.

Du kannst deine Ergebnisse übrigens gegen Wolfram Alpha prüfen. (Beispiel).

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Sorry, meine Rundungsmethode:


private int Round(double d)
        {
            if (double.IsPositiveInfinity(d))
                return int.MaxValue;
            if (double.IsNegativeInfinity(d))
                return int.MinValue;
            return Convert.ToInt32(Math.Round(d, MidpointRounding.AwayFromZero));
        }

3.003 Beiträge seit 2006
vor 7 Jahren

Ja, wie gesagt, wenn du auf Ganzzahlen rundest, wenn gebrochene Zahlen rauskommen, musst du dich nicht wundern.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Tut mir leid ich bin ein Programmieranfänger.

Der Punkt kann nur Int-Werte annehmen, wie könnte ich das Ganze umbauen das er die richtigen Werte entgegen nimmt?

Ich versuche ja schon erst am Ende zu runden.

3.003 Beiträge seit 2006
vor 7 Jahren

Wenn ich willkürlich in einem Koordinatensystem vier Punkte eintrage und dann Linien zeichne, wird deren Schnittpunkt so gut wie nie genau auf einem ganzzahligen Punkt liegen...

Der Punkt kann nur Int-Werte annehmen.

Im Gegenteil, er nimmt nur ganz, ganz selten int-Werte an.

LaTino
EDIT: oh, warte, du willst ein Point-Struct draus machen? PointF

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Damit meinte ich die Parameter die man mitgeben kann,



            // Schnittpunktberechnung

            int sx = Round(start1.X + s * x1);
            int sy = Round(start1.Y + s * y1);

            // Schnittpunkt

            Point schnittPunkt = new Point(sx, sy);


sx und sy müssen integer sein, bei double etc. meckert er

3.003 Beiträge seit 2006
vor 7 Jahren

Klick mal auf den Link. Ich denke, soviel können wir erwarten 😉.

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Sorry dein Edit kam erst nach meiner Antwort 😃 bzw. hatte die Seite noch nicht neu geladen

Edit: Du hast Recht, das Runden führt zu Fehlern. Aber eigentlich habe ich dann nur vor dem


Point schnittPunkt = new Point(sx, sy);

exakte Werte zu übergeben. Und da muss ichs ja irgendwie hinbekommen, dass sx und sy von Kommazahlen zu Integern übergehen =?

3.003 Beiträge seit 2006
vor 7 Jahren

Ich denke, wir drehen uns im Kreis. Ich sage dir, dass du das Ergebnis nicht in Ganzzahlen speichern kannst, du sagst, "aber irgendwie muss das doch gehen". Dann sage ich wieder, dass Schnittpunkte nunmal nicht ganzzahlig sind, und du machst eine Konvertierung nach int und wunderst dich, wieso das Ergebnis dann nicht stimmt.

Du kannst runden, abschneiden, casten - völlig egal, wenn du das Endergebnis als Ganzzahl nimmst, wird es falsch sein, weil es eben keine Ganzzahl ist.


int intResult1 = (int)myFloat; //zahlen hinter dem Komma abschneiden
int intResult2 = Convert.ToInt32(myFloat); //rundet

//intResult1, intResult2 sind immer noch falsch, mit GLück in seltenen Fällen aber nicht _sehr_ falsch.

Beim programmieren musst du halt immer die Datentypen benutzen, die du brauchst, um das darzustellen, was du darstellen willst. Wenn du Kommazahlen darstellen willst, kannst du kein int (also auch kein Point) nehmen.

LaTino
EDIT: Convert.ToInt32 korrigiert

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Ich habe dich schon verstanden. Meine letzte Frage zielte darauf ab, ob es dann eine Möglichkeit gibt das ganze dann anders zu lösen. Wenn ich den Schnittpunkt in 2 float Werte aufteile müsste ich damit ja weiterrechnen und diese Werte dann mit der Geraden abgleichen.

2.298 Beiträge seit 2010
vor 7 Jahren

Hallo Garzec,

verwende wie angesprochen PointF, in diesem werden Koordinaten als Float-Werte eingefügt.

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Danke,

da ich mit double rechne wollte ich die Punkte, wie von LaTino schon vorgeschlagen, weglassen, um exakte Werte zu behalten. Nebenbei habe ich noch ein bisschen gekürzt und vereinfacht.

Das Ganze sieht nun so aus:



private void SchnittpunktBerechnung(int startIndex1, int startIndex2)
        {
            // Punktindex

            int endeIndex1 = startIndex1 + 1;
            int endeIndex2 = startIndex2 + 1;

            Point start1 = punktListe[startIndex1];
            Point ende1 = punktListe[endeIndex1];
            Point start2 = punktListe[startIndex2];
            Point ende2 = punktListe[endeIndex2];

            // Zwischenwerte

            int x1 = ende1.X - start1.X;
            int x2 = start2.X - ende2.X; 
            int x3 = start2.X - start1.X; 

            int y1 = ende1.Y - start1.Y; 
            int y2 = start2.Y - ende2.Y;   
            int y3 = start2.Y - start1.Y;  

            // Determinanten

            int d1 = x1 * y2 - y1 * x2; 
            int d2 = x3 * y2 - y3 * x2;    
            int d3 = x1 * y3 - y1 * x3;   

            // s und t

            double s = d2 / d1;
            double t = d3 / d1;

            // Schnittpunktberechnung

            double schnittpunktX = start1.X + s * x1;
            double schnittpunktY = start1.Y + t * y1;

            // Überprüfung

            if (s >= 0 && t <= 1)
            {
                                   //Schnittpunkt auf der Strecke
            }
        }


Dennoch kommen beim Testen nicht die gewünschten Ergebnisse raus, also Er findet nicht den exakten Schnittpunkt auf der Strecke.

Kann mir jemand sagen ob bei der Rechnung oben noch Fehler eingebaut sind? Das mathematische hier ins Programm umzuschreiben fand ich doch nicht so einfach wie gedacht 😁

2.298 Beiträge seit 2010
vor 7 Jahren

Wie stark ist denn die Abweichung vom von dir berechneten Schnittpunkt?

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Das ist immer unterschiedlich. Es wird ja abgeschnitten. Daher weichen die Punkte nicht so stark ab, aber er findet den Punkt ja dann nicht mehr auf der Strecke. Weil er ja nicht DIREKT drauf liegt, sondern ganz knapp daneben und dann findet er ihn nicht mehr. Daher erstmal meine Frage nach der Rechnung, ob diese richtig ist. Damit kann man dann ja weiterarbeiten.

T
415 Beiträge seit 2007
vor 7 Jahren

Verwende mal statt double den Datentyp decimal. Dieser hat eine höhere Genauigkeit.

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Hab 😃

Jetzt noch die Rechnung korrigieren 😛

3.170 Beiträge seit 2006
vor 7 Jahren

Hallo,


            // s und t

            double s = d2 / d1;
            double t = d3 / d1;

An der Stelle ist das, was in s und t steht, wieder ein ganzzahliger Wert, weil Du in der Rechenoperation nur mit Integern (d1, d2, d3) rechnest.
Sattdessen könntest Du d1, d2, d3 direkt als double deklarieren, oder eben einen der Werte in der Berechnung auf double casten:

            //-----------ENTWEDER SO------------:

            double d1 = x1 * y2 - y1 * x2;
            double d2 = x3 * y2 - y3 * x2;
            double d3 = x1 * y3 - y1 * x3;

            // s und t

            double s = d2 / d1;
            double t = d3 / d1;

            //-----------ODER SO------------:

            double s = d2 / (double)d1;
            double t = d3 / (double)d1;

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

3.003 Beiträge seit 2006
vor 7 Jahren

Wie MarsStein schrieb - ansonsten ist deine Rechnung, soweit ich sehen kann, in Ordnung. Eine Sache noch:

Wenn du am PC mit Gleitzahlen arbeitest (besonders bei float), dann überprüft man niemals mit "==", ob zwei Werte gleich sind. Der Grund dafür liegt in der Ungenauigkeit von float. Entweder du verwendest, wie vorgeschlagen, decimal, oder du machst einen sog. Delta-Vergleich:


const float DELTA = 0.001; //nach Bedarf anpassen
float float1, float2;

//berechnungen...

//Vergleich:
if(Math.Abs(float1 - float2) < DELTA) DoSomething() //wenn die Werte nah genug beinander liegen, sind sie gleich)

Das sollte man beim Arbeiten mit float IMMER machen, mit double im Hinterkopf behalten und mit decimal ignorieren 😉.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

C
224 Beiträge seit 2009
vor 7 Jahren

Float, double und decimal haben eines Gemeinsam: sie sind endliche Gleitkommazahlen. Dementsprechend sollte man denen Vertrauen.

Bei float und double wird intern im Binärzahlensystem gerechnet. Beim Darstellen ins Dezimalsystem entstehen dabei kleine Rundungsfehler. Da wir Menschen nicht binär denken, sind diese kleinen Fehler zum Teil schwer nachzuvollziehen. Beim decimal wird intern im Dezimalsystem gerechnet und ist auf Rechnungen mit Geldsystemen ausgelegt. Daher sind diese für uns Menschen wesentlich genauer und deren Rundungen entsprechen auch meist unseren Erwartungen.

Je nach Anwendung würde ich aber auch ein Delta für decimal verwenden.

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Also ich habe nun 2 Berechnungen, wobei ich weiß das die 2. Berechnung wohl das richtige Ergebnis liefert, die 1. Methode (meine Berechnung) noch nicht.

Meine Berechnung sieht momentan so aus:


private void SchnittpunktBerechnung(int startIndex1, int startIndex2)
        {
            // Punktindex

            int endeIndex1 = startIndex1 + 1;
            int endeIndex2 = startIndex2 + 1;

            Point start1 = punktListe[startIndex1];
            Point ende1 = punktListe[endeIndex1];
            Point start2 = punktListe[startIndex2];
            Point ende2 = punktListe[endeIndex2];

            // Zwischenwerte

            int x1 = ende1.X - start1.X;
            int x2 = start2.X - ende2.X;
            int x3 = start2.X - start1.X;

            int y1 = ende1.Y - start1.Y;
            int y2 = start2.Y - ende2.Y;
            int y3 = start2.Y - start1.Y;

            // Determinanten

            decimal d1 = x1 * y2 - y1 * x2;
            decimal d2 = x3 * y2 - y3 * x2;
            decimal d3 = x1 * y3 - y1 * x3;

            // s und t

            decimal s = d2 / d1;
            decimal t = d3 / d1;

            // Schnittpunktberechnung

            decimal schnittpunktX = start1.X + s * x1;
            decimal schnittpunktY = start1.Y + s * y1;

            // Überprüfung

            if (s >= 0 && t >= 0 && s <= 1 && t <= 1)
            {
                //Schnittpunkt auf der Strecke
            }
        }

Die neue Berechnung sieht wie folgt aus:


private void Tausche(float start, float ende)
        {
            float helper;
            helper = start;
            start = ende;
            ende = helper;
        }

        private bool LiegtDazwischen(float value, float start, float ende)
        {
            if (start > ende)
            {
                Tausche(start, ende);
            }
            return (start <= value) && (value <= ende);
        }

        private bool PunktLiegtDazwischen(PointF schnittpunkt, PointF punkt1, PointF punkt2)
        {
            return LiegtDazwischen(schnittpunkt.X, punkt1.X, punkt2.X) && LiegtDazwischen(schnittpunkt.Y, punkt1.Y, punkt2.Y);
        }

        private bool BerechneSchnittpunkt(PointF punkt1, PointF punkt2, PointF punkt3, PointF punkt4, PointF schnittpunkt)
        {
            float mx = punkt2.X - punkt1.X;
            float nx = punkt4.X - punkt3.X;
            float ox = punkt4.X * punkt3.Y - punkt3.X * punkt4.Y;

            float my = punkt2.Y - punkt1.Y;
            float ny = punkt4.Y - punkt3.Y;
            float oy = punkt2.X * punkt1.Y - punkt1.X * punkt2.Y;

            float d1 = mx * ny - my * nx;
            float d2 = nx * oy - mx * ox;
            float d3 = ny * oy - my * ox;

            if (d1 == 0)
            {
                //parallel
                schnittpunkt.X = 0;
                schnittpunkt.Y = 0;
                return false;
            }
            else
            {
                schnittpunkt.X = d2 / d1;
                schnittpunkt.Y = d3 / d1;
                return PunktLiegtDazwischen(schnittpunkt, punkt1, punkt2) && PunktLiegtDazwischen(schnittpunkt, punkt3, punkt4);
            }
        }

Aufgerufen wird meine Methode über eine Schleife, die dann über sämtliche Punkte geht:


  private void BerechneSchnittpunkte()
        {
            for (int i = 0; i < 5; i++)
            {
                for (int j = i + 2; j < 5; j++)
                {
                    SchnittpunktBerechnung(i, j);
                }
            }
        }

Würde es Sinn machen das Ganze hin zur 2. Berechnung umzubauen? Wenn ich versuche die 2. Berechnung mit 4 Methoden so abzuändern, dass diese Methode genauso wie meine Berechnung in der Schleife aufgerufen wird, dann komme ich als Anfänger sehr schnell mit den Parametern durcheinander, sodass es vorne und hinten nicht mehr stimmt.

Kann ich auch meine eigene Berechnung dahingehend abändern, dass die Methoden der 2. Berechnung greifen?

3.003 Beiträge seit 2006
vor 7 Jahren

Aus meiner Sicht würde eine grundsätzliche Umstrukturierung deines Codes Sinn ergeben. Nach meinem Empfinden ist das alles noch viel zu prozedural aufgebaut, also: beide Methoden, die du gepostet hast, sind wirklich nicht gut strukturiert.

Eine Klasse für einen Fixpunkt, eine Klasse für Vektoren (inkl. Normalisierung), ein paar überladene Operatoren und eine Klasse für Geraden (Fixpunkt und Richtungsvektor). Und dann kannst du den Schnittpunkt zweier Geraden sehr viel klarer darstellen.

Wenn du das jetzt noch erweitern willst - sagen wir, auf 3D - dann sitzt du doch wieder an derselben Methode und verlierst wieder den Überblick.

Und zum Probieren, ob und welche Methode das richtige errechnet, solltest du dir mal den Komponententest-Projekttyp im Visual Studio anschaun, der ist für sowas gemacht. So, wie es jetzt ist, weisst du doch zu keiner Zeit, ob eine Änderung den gewünschten Effekt hatte oder nicht.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

G
Garzec Themenstarter:in
50 Beiträge seit 2016
vor 7 Jahren

Danke für deine Hinweise, das Thema Klassen zu erlernen, da bin ich grade dran, nebenbei wollte ich aber erst die Funktionalität des Programmes sicherstellen.

Ich nutze nun die "neue" Berechnung, und versuche die 5 Parameter bei Methodenaufruf zu übergeben. Leider kommt es da zu Fehlern. Der Code:


            for (int i = 0; i < punktListe.Count; i++)
            {
                for (int j = i + 2; j < 5; j++)
                {
                    PointF schnittpunkt = new PointF();
                    BerechneSchnittpunkt(punktListe[i], punktListe[j], punktListe[i + 1], punktListe[j +       1], out schnittpunkt);
                }
            }

Ich habe 2 Schleifen genommen, da er eine Exception bei einer Schleife wirft. Der Index übersteigt das Maximum und es geht nicht weiter. Dennoch kommen bei dieser Methode noch falsche Schnittpunkte heraus, meistens sind es sogar zu viele, ich denke er erkennt manche Eckpunkte noch als Schnittpunkte.

Meine Frage:

Stimmt meine neue Berechnung immer noch nicht oder übergebe ich die Parameter einfach nur falsch?

Ich habe zum Testen eine Schnittpunktliste erstellt, lasse ich die Schnittpunkte dazu malen, gehen die Linien kreuz und quer durch das Bild, die Berechnung muss also noch falsch sein ...

3.003 Beiträge seit 2006
vor 7 Jahren

Die Sache ist die - sollte da noch ein Fehler vorliegen, müssten wir uns, um ihn zu finden, durch den ziemlich unübersichtlichen Code von dir wühlen - oder hier im Forum versuchen, durch draufschauen einen eventuellen Fehler zu finden.

Das ist so nicht praktikabel 😉.

Ich gebe dir mal einen Schubs in eine bessere Richtung.


public class Vector
{
    private const float DELTA = 0.0001f;

    public Vector(float x, float y, bool normalize) //erstellt einen Vektor und normalisiert ihn auch gleich. Für den Fall der Fälle merken wir uns den Normalisierungsfaktor.
    {
        X = x;
        Y = y;

        NormalizationFactor = (float)Math.Sqrt(x * x + y * y);
        if (normalize && NormalizationFactor > DELTA)
        {
            X /= NormalizationFactor;
            Y /= NormalizationFactor;
        }
    }
    public Vector(Point start, Point end) : this(end.X - start.X, end.Y - start.Y, true) { }
    public Vector(Point point, bool normalize) : this(point.X, point.Y, normalize) { }

    public float NormalizationFactor { get; private set; }
    public float X { get; private set; }
    public float Y { get; private set; }

    public Vector Reverse() //falls wir mal die Richtung wechseln müssen.
    {
        return new Vector(-1 * X ,-1 * Y, true);
    }
}

public class Line //wird in Parameterform gespeichert: startpunkt + t*Richtungsvektor
{
    public Vector Direction { get; private set; }
    public Vector Startpoint { get; private set; }

    public Vector Normal //der senkrecht auf der Richtung stehende Vektor. Praktisch, wenn man einen Schnittpunkt wissen will.
    {
        get
        {
            return new Vector(-1 * Direction.Y, Direction.X, false);
        }
    }

    public Line(Point startPoint, Point endPoint)
    {
        Startpoint = new Vector(startPoint, false);
        Direction = new Vector(startPoint, endPoint);
    }

    //für Umrechnung in Koordinatenform a*x + b*y = c 
    public float CoordinateA { get { return Normal.X; } } 
    public float CoordinateB { get { return Normal.Y; } }
    public float CoordinateC { get { return Startpoint.X*Normal.X + Startpoint.Y*Normal.Y; } }

    public PointF Intersection(Line other)
    {
        var xs = /* Zeile selber einfügen, Wikipedia hilft. */
        var ys = /* Zeile selber einfügen, Wikipedia hilft. */
        return new PointF(xs, ys);
    }
}

Schnittpunkt: WP - Schnittpunkt zweier Geraden
So etwas in der Art meinte ich damit, dass du deinen Code etwas organisieren solltest.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)