- function LineHitsCircle(const _LineStart, _LineEnd : TVector2; const _CircleCenter : TVector2; const _Radius : Single) : Boolean;
- var
- RadiusSq : Single;
- PMinusM : TVector2;
- LineDir : TVector2;
- UDotPMinusM : Single;
- LineDirSq : Single;
- d, s : Single;
- begin
- // r² vorberechnen
- RadiusSq := _Radius * _Radius;
- // (p - m) vorberechnen
- PMinusM := Vector2Sub(_LineStart, _CircleCenter);
- // Wenn der Startpunkt der Linie schon im Kreis liegt,
- // dann brechen wir sofort ab.
- if (PMinusM.Length <= RadiusSq) then
- begin
- // Als Schnittpunkt nehmen wir einfach
- // den Startpunkt der Linie.
- //if(pOut) *pOut = LineStart;
- Result := True;
- Exit;
- end;
- // Richtungsvektor der Linie berechnen (u)
- LineDir := Vector2Sub(_LineEnd, _LineStart);
- // u * (p - m) vorberechnen
- UDotPMinusM := Vector2DotProduct(LineDir, PMinusM);
- // u² vorberechnen
- LineDirSq := LineDir.Length;
- // Die Diskriminante berechnen:
- // (u * (p - m))²
- // - (u² * ((p - m)² - r²))
- d := UDotPMinusM * UDotPMinusM - LineDirSq * (PMinusM.Length - RadiusSq);
- // Ist die Diskriminante negativ, null oder positiv?
- if (d < 0.0) then
- begin
- Result := False;
- Exit;
- end
- else
- begin
- if (d < 0.0001) then
- begin
- // Die Diskriminante ist (ungefähr) null.
- // Die gesamte Wurzel entfällt und die Lösung ist:
- // (-u * (p - m)) / u².
- // Wir müssen nur noch prüfen, ob der Wert
- // im korrekten Bereich [0; 1] liegt.
- s := -UDotPMinusM / LineDirSq;
- if (s < 0.0) or (s > 1.0) then
- begin
- result := False;
- Exit;
- end
- else
- begin
- // Berührpunkt!
- //if(pOut) *pOut = LineStart + s * LineDir;
- result := True;
- Exit;
- end;
- end
- else
- begin
- // Die Gerade schneidet den Kreis zweimal.
- // Uns interessiert nur die kleinere Lösung für s,
- // denn das ist die Stelle, wo die Linie den Kreis
- // "zum ersten Mal" schneidet.
- // Diese Lösung berechnen wir nun.
- s := (-UDotPMinusM - sqrt(d)) / LineDirSq;
- if (s < 0.0) or (s > 1.0) then
- begin
- result := False;
- exit;
- end
- else
- begin
- //if(pOut) *pOut = LineStart + s * LineDir;
- result := True;
- Exit;
- end;
- end;
- end;
- end;