Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Ein bisschen lineare Algebra (https://www.delphipraxis.net/148398-ein-bisschen-lineare-algebra.html)

LDericher 1. Mär 2010 11:10


Ein bisschen lineare Algebra
 
Liste der Anhänge anzeigen (Anzahl: 1)
Also, eigentlich dürfte das kein Problem sein - habe ich mir gedacht...

Ich wollte mir einen Farb-Ring bauen; später will ich daraus auch ein Control machen. Was das Teil genau können soll, müsst ihr noch nicht wissen, denn es hakt schon deutlich vorher.

Ich will die Farbe jedes Pixels über den Winkel errechnen, und wenn ich den kennen würde, wäre das ganze auch kein Problem. Folgendermaßen gehe ich bis jetzt vor:

1. Ich zeichne einen schwarzen Ring auf weißem Grund. (Canvas.Ellipse, temporäres BMP)
2. Ich durchlaufe die einzelnen Pixel vom Bild (im Moment noch über Canvas.Pixels, aber das werde ich noch rausoptimieren) und schreibe auf das Zielcanvas (das von der Form) den berechneten Farbwert, sofern ich kein weißes Pixel habe.

Den Farbwert will ich berechnen, indem ich den Winkel "alpha" verarbeite (siehe angefügte Skizze).
Natürlich sind N, Z und M bekannt.

Meine Überlegung ist nun so:
Code:
N(aRadius, 0).
M(aRadius, aRadius).
Z(x, y).
n = N - M = (0, -aRadius).
z = Z - M = (x - aRadius, y - aRadius).
alpha = arccos( (n * z) / (|n| * |z|) ).
wobei n * z für das Skalarprodukt und |n| für den Betrag/die Länge steht.

In Quellcode habe ich das ganze nun so versucht umzusetzen:
Delphi-Quellcode:
function ScalarProduct(var pVec1, pVec2:TPoint):integer;
begin
Result:=(pVec1.X * pVec2.X) + (pVec1.Y * pVec2.Y);
end;

function Length(var pVec:TPoint):Extended;
begin
Result:=Sqrt(Sqr(pVec.X)+Sqr(pVec.Y));
end;
{...}
function TColorRing.getColor(X, Y: integer): TColor;
var
  vecN,
  vecZ:TPoint;
  Angle:Extended;
begin
vecN:=Point(0, -aRadius);
vecZ:=Point(X-aRadius, Y-aRadius);
Angle:=ScalarProduct(vecN, vecZ)/(Length(vecN)*Length(vecZ));
Angle:=ArcCos(Angle);
Result:=trunc(Angle*(360/Pi)); // Sollte Werte zwischen 0 und 360 geben.
end;
Aber leider scheint das ganze nicht so funktionieren zu wollen, wie ich das gern hätte, denn Result liegt zwar richtigerweise zwischen 0 und 360, aber die Werte sind "gespiegelt", also der rechte Halbkreis liefert 0..360 genau wie der Linke. Ich hätte aber gern oben die 0/360, rechts die 90, unten die 180 und links die 270; der Rest entsprechend dazwischen...

Wer kann mir helfen, meinen Fehler zu finden?

Gruß,
Euer LDer

gammatester 1. Mär 2010 11:15

Re: Ein bisschen lineare Algebra
 
Pi entspricht 180° nicht 360°!

LDericher 1. Mär 2010 11:17

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von gammatester
Pi entspricht 180° nicht 360°!

Wah!
Okay, danke, jetzt hab ich schonmal die 180 unten, das ist schonmal gut, danke :)
Aber jetzt ist immer noch die 90 links UND rechts, aber die soll nur rechts sein, links muss die 270 hin. Ein schöner Kreis solls werden, nicht zwei Halbkreise... irgendwo hakts da noch :cry:

Medium 1. Mär 2010 11:27

Re: Ein bisschen lineare Algebra
 
Das Problem ist, dass diese Art der Winkelbestimmung immer zum kleineren Winkel zwischen 2 Vektoren führt. Schau dir mal ATan2() an!

jfheins 1. Mär 2010 11:29

Re: Ein bisschen lineare Algebra
 
Kennst du Polarkooradinaten?

Um den Winkel alpha zu ermitteln: alpha = Math.arctan2(z.Y, z.X)

Der Winkel ist allerdings mathematisch - also gleich null wenn der Punkt ganz rechts liegt und dann im Uhrzeigersinn positiv (da ja die y-Achse nach unten geht)

gammatester 1. Mär 2010 11:30

Re: Ein bisschen lineare Algebra
 
arccos bildet [-1..1] auf [0..Pi] ab, also wirst Du niemals Winkel größer als 180° erhalten. Dies Situation muß Deine übergeordnete Logik behandeln. Vielleicht so (ohne Gewähr): wenn Winkel(n,z) > 180, dann 360 - Winkel(z,n), genaueres mußt Du eventuell in Deiner LA-Quelle nachlesen.

gammatester 1. Mär 2010 11:34

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von jfheins
Kennst du Polarkooradinaten?

Um den Winkel alpha zu ermitteln: alpha = Math.arctan2(z.Y, z.X)

Das ist aber nicht alpha, sondern der Winkel zwischen x-Achse und z!

jfheins 1. Mär 2010 11:39

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von gammatester
Zitat:

Zitat von jfheins
Kennst du Polarkooradinaten?

Um den Winkel alpha zu ermitteln: alpha = Math.arctan2(z.Y, z.X)

Das ist aber nicht alpha, sondern der Winkel zwischen x-Achse und z!

Ich hab ja auch extra dazugeschriben, dass der Winkel dann null ist, wenn der Punkt waagerecht rechts des Mittelpunkts liegt. Einen konstanten Winkel zu addieren sollte noch machbar sein ...

Aber, okay, hier die korrigierte Formel:

alpha = Math.arctan2(z.Y, z.X) + PI/2; // bzw. 90°
if alpha < 0 then alpha = alpha + 2*PI; // Danach ist alpha nicht mehr negativ

Medium 1. Mär 2010 11:41

Re: Ein bisschen lineare Algebra
 
atan2()-pi/2 sollte das fixen, wobei man dann natürlich ein Auge auf alpha<0 haben muss. Falls links/rechts dann noch vertauscht sind, den 2. Parameter negieren.

Edit: Negative Winkel kommen eh vor, stimmt ja. Die muss man also eh schon zurecht zuppeln :)

LDericher 1. Mär 2010 11:42

Re: Ein bisschen lineare Algebra
 
Das mit [0..Pi] ist mir dann auch aufgefallen... aber der arctan2 ist genau das was ich gebraucht habe! :)

Also hab ich was gebastelt, das genau das tut, was ich will:
Delphi-Quellcode:
function TColorRing.getAngle(X, Y: integer): integer;
var
  vecZ:TPoint;
  Angle:Extended;
begin
vecZ:=Point(X-aRadius, Y-aRadius);
Angle:=Math.ArcTan2(vecZ.X, vecZ.Y);
Result:=trunc(Angle*(180/Pi));
Result:=180-Result;
end;
Danke für eure Mühen!

Euer LDer

gammatester 1. Mär 2010 11:44

Re: Ein bisschen lineare Algebra
 
Leute, er will den Winkel alpha zwischen N und Z haben, nicht nur das argument von Z!

Medium 1. Mär 2010 11:46

Re: Ein bisschen lineare Algebra
 
Wenn einer der 2 Vektoren einer Achse entspricht, wo ist der Unterschied im Ergebnis?

jfheins 1. Mär 2010 11:46

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von gammatester
Leute, er will den Winkel alpha zwischen N und Z haben, nicht nur das argument von Z!

Jetzt beruhige dich mal ein wenig.
Wenn den Vektor N wirklich komplett frei sein soll, würde ich für beide Vektoren den Winkel mit arctan2 ausrechnen und davon dann die Differenz nehmen. Skalarprodukt mit arccos ist hier weder notwendig noch zielführend da es ja immer den kleinsten Winkel zwischen 2 Vektoren zurückgibt.

Ich hätte da noch ne Anregung:
Zitat:

Zitat von LDericher
1. Ich zeichne einen schwarzen Ring auf weißem Grund. (Canvas.Ellipse, temporäres BMP)
2. Ich durchlaufe die einzelnen Pixel vom Bild (im Moment noch über Canvas.Pixels, aber das werde ich noch rausoptimieren) und schreibe auf das Zielcanvas (das von der Form) den berechneten Farbwert, sofern ich kein weißes Pixel habe.

Das geht auch direkt: Prüfe ob der Radius (=> Pythagoras) zwischen einem inneren und einem äußeren Radius liegt ;)

gammatester 1. Mär 2010 11:55

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von Medium
Wenn einer der 2 Vektoren einer Achse entspricht, wo ist der Unterschied im Ergebnis?

Zumindest müßte man beide Winkel berechnen, etwa
Delphi-Quellcode:
alpha := ArcTan2(vecN.X, vecN.Y) - ArcTan2(vecZ.X, vecZ.Y)
, wobei das Problem mit Winkeln > 180° weiterhin zu beachten ist.

LDericher 1. Mär 2010 11:56

Re: Ein bisschen lineare Algebra
 
Liste der Anhänge anzeigen (Anzahl: 1)
Leute, kommt mal runter, es funktioniert :D

jfheins 1. Mär 2010 11:58

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von LDericher
Leute, kommt mal runter, es funktioniert :D

Dein "Grün" ist aber reichlich fad :P

Medium 1. Mär 2010 12:00

Re: Ein bisschen lineare Algebra
 
Nix, hier geht's um's Prinzip! :stupid: (schaut aber nett aus)

Den Winkel des (hier fixen) achsengleichen Vektors braucht man doch garnicht aufwendig zu berechnen, er ist ja bekannt und kann locker als Konstante addiert/subtrahiert werden. Das ist hier natürlich ein Spezialfall, keine Frage!

LDericher 1. Mär 2010 12:32

Re: Ein bisschen lineare Algebra
 
Zitat:

Zitat von jfheins
Zitat:

Zitat von LDericher
Leute, kommt mal runter, es funktioniert :D

Dein "Grün" ist aber reichlich fad :P

Oha! Du hast recht, ist mir gar nicht aufgefallen zuerst - und das ist leider wichtig für die Funktion des Ganzen...

Wie krieg ich das Grün denn hier rein? :x

Delphi-Quellcode:
function TColorRing.getColor(X, Y: integer): TColor;
var
  Angle:integer;
  R,
  G,
  B:Byte;
begin
Angle:=Self.getAngle(X, Y);
if(Angle in [0..119])then
  begin
  R:=255;
  G:=trunc(255*Angle/119);
  B:=0;
  end
else if(Angle in [120..239])then
  begin
  dec(Angle, 120);
  R:=trunc(255*(119 - Angle)/119);
  G:=trunc(255*(119 - Angle)/119);
  B:=trunc(255*Angle/119);
  end
else
  begin
  dec(Angle, 240);
  R:=trunc(255*Angle/119);
  G:=0;                          
  B:=trunc(255*(119 - Angle)/119);
  end;
Result:=RGB(R, G, B);
end;

jfheins 1. Mär 2010 12:39

Re: Ein bisschen lineare Algebra
 
http://de.wikipedia.org/wiki/HSV-Far...ung_HSV_in_RGB
Mit S = V = 1 und H = alpha
=> p=0; q=1-f; t=f

Sherlock 1. Mär 2010 12:42

Re: Ein bisschen lineare Algebra
 
Abschließend und leicht OT würde ich gerne festhalten, daß dieses Thema IMHO nicht die lineare Algebra betrifft, sondern die Trigonometrie ;)

Sherlock

LDericher 1. Mär 2010 13:12

Re: Ein bisschen lineare Algebra
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von jfheins
http://de.wikipedia.org/wiki/HSV-Farbraum#Umrechnung_HSV_in_RGB
Mit S = V = 1 und H = alpha
=> p=0; q=1-f; t=f

Grundsätzlich gerne, aber die Anordnung ist mir wichtig; also:

Delphi-Quellcode:
function TColorRing.getColor(X, Y: integer): TColor;
var
  Angle:integer;
  R,
  G,
  B:Byte;
begin
Angle:=Self.getAngle(X, Y);
if(Angle in [0..119])then
  begin
  R:=255;
  G:=trunc(255*Angle/119);
  B:=0;
  end
else if(Angle in [120..239])then
  begin
  dec(Angle, 120);    
  if(Angle in [0..59])then
    begin
    R:=trunc(255*(59 - Angle)/59);
    B:=0;
    end else
    begin  
    R:=0;
    B:=trunc(255*(Angle-60)/59);
    end;
  G:=trunc(255*(119 - Angle)/119);
  end
else
  begin
  dec(Angle, 240);
  R:=trunc(255*Angle/119);
  G:=0;                          
  B:=trunc(255*(119 - Angle)/119);
  end;
Result:=RGB(R, G, B);
end;

Zitat:

Zitat von Sherlock
Abschließend und leicht OT würde ich gerne festhalten, daß dieses Thema IMHO nicht die lineare Algebra betrifft, sondern die Trigonometrie ;)

Sherlock

Anfangs war es aber als LA formuliert ;)

Aber sonst hast du Recht!


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz