Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Verlauf mit "gewichteter" Farbe mittels Log? (https://www.delphipraxis.net/131988-verlauf-mit-gewichteter-farbe-mittels-log.html)

Pfoto 3. Apr 2009 20:31


Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,

ich versuche seit geraumer Zeit, einen Verlauf zwischen
zwei Farben so zu ändern, dass eine der beiden Farben
mehr Gewicht hat, also über eine gewisse Fläche hinweg
dominanter ist.

Ich habe mit Log() expermimentiert und habe festgestellt,
dass ich damit der Sache näherkomme. Leider geht der Verlauf
jedoch nicht von Anfang bis Ende, sondern wird kurz vor
Ende unterbrochen und fängt neu an.

Im Anhang ist ein Beispiel davon.


Ich verwende folgenden Code (Quelle leider unbekannt):

Delphi-Quellcode:
  function GetColorBetween(StartColor, EndColor: TColor; Pointvalue,
    aFrom, aTo : Extended): TColor;
  var
    F: Extended; r1, r2, r3, g1, g2, g3, b1, b2, b3: Byte;

    function CalcColorBytes(fb1, fb2: Byte): Byte;
    begin
      result := fb1;
      if fb1 < fb2 then Result := FB1 + Trunc(F * (fb2 - fb1));
      if fb1 > fb2 then Result := FB1 - Trunc(F * (fb1 - fb2));
    end;

  begin
    if Pointvalue <= aFrom then
    begin
      result := StartColor;
      exit;
    end;
    if Pointvalue >= aTo then
    begin
      result := EndColor;
      exit;
    end;
    F := ((Pointvalue - aFrom) / (aTo - aFrom));

    {==== Hier kommt einer meiner Versuche ===}
    F:= LogN(10, F);
    {======================================}

    asm
       mov EAX, Startcolor
       cmp EAX, EndColor
       je @@exit
       mov r1, AL
       shr EAX,8
       mov g1, AL
       shr Eax,8
       mov b1, AL
       mov Eax, Endcolor
       mov r2, AL
       shr EAX,8
       mov g2, AL
       shr EAX,8
       mov b2, AL
       push ebp
       mov al, r1
       mov dl, r2
       call CalcColorBytes
       pop ecx
       push ebp
       Mov r3, al
       mov dL, g2
       mov al, g1
       call CalcColorBytes
       pop ecx
       push ebp
       mov g3, Al
       mov dL, B2
       mov Al, B1
       call CalcColorBytes
       pop ecx
       mov b3, al
       XOR EAX,EAX
       mov AL, B3
       SHL EAX,8
       mov AL, G3
       SHL EAX,8
       mov AL, R3
    @@Exit:
       mov @result, eax
    end;
  end;



  procedure FillGradient(Canvas : TCanvas; aStart, aWidth, aHeight : Integer;
    Color1, Color2 : TColor; Direction : TDirection);

  var i : Integer;
  begin
    if (aWidth > 0) and (aHeight > 0) then
    begin
      case Direction of
        diHorizontal:
        for i := aStart to aWidth do
        begin
          Canvas.Pen.Color := GetColorBetween(Color1, Color2, i, aStart, aWidth);
          Canvas.MoveTo(i, 0);
          Canvas.LineTo(i, aHeight);
        end;
        diVertical:
        for i := aStart to aHeight do
        begin
          Canvas.Pen.Color := GetColorBetween(Color1, Color2, i, aStart, aHeight);
          Canvas.MoveTo(0, i);
          Canvas.LineTo(aWidth, i);
        end;
      end;
    end;
  end;

Leider bin ich ja mathematisch minderbegabt, d.h. ich sehe zwar
mit verschiedenen Log-Arten die Ergebnisse (z.B. viele, immer
kleiner werdende Verlaufsstrecken), kann mir aber nicht erklären,
wie ich einen soliden Wert ermittle, um einen durchgängigen
Verlauf von A nach B zu generieren :-(

Wisst ihr hier eine Formel, mit der ich das lösen könnte?

Dank und Gruß
Jürgen

**** EDIT ****

Ich habe nun mit Prozentwerten gearbeitet und erhalte
eine sehr ähnliche Ausgabe, mit der ich ja schon *fast*
zufrieden wäre:
Delphi-Quellcode:
    F := ((Pointvalue - aFrom) / (aTo - aFrom));
    Percent:= (100 * Pointvalue) / (aTo - aFrom);
    F:= (Percent * F) / 100;
Der Verlauf wird nun von der Startfarbe her gewichtet
-- das würde ich jetzt noch gerne umkehren. Leider bisher
noch ohne Erfolg.

Medium 4. Apr 2009 04:25

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Ich habe jetzt nicht alles ganz genau durchgelesen, aber ich vermute mal dass du irgendwo eine "Laufvariable" i hast, die von 0 bis 1 als Faktor der Randfarben für die Mischung zuständig ist. In diesem Fall ist das simpelste "biasing" die Potenzierung, also genau die Umkehrfunktion vom Logarithmus.
Lasse i ganz normal laufen, aber rechne die Farben mit i^k*C1 + (1-i^k)*C2.

Wenn dein i nicht 0..1 ist, skaliere es darauf. Das tolle ist dabei nämlich, dass 0^k=0 und 1^k=1 bleiben, nur die Werte da zwischen werden quasi "verbogen" - ohne je [0;1] zu verlassen. Je nach dem wie du k nun wählst ist dein Verlauf mehr nach C1 oder C2 verschoben, wobei k=1 der übliche lineare Verlauf ist.

Ein wenig gewöhnungsbedürftig: Volles Schieben nach C2 wäre bei k=0,00000...1 und nach C1 k=+inf

Pfoto 4. Apr 2009 08:17

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Medium,

ich habe das eben mal (versucht) umzusetzen.

Dieses Dach (^) kenne ich nur von Pointern, aber du
meintest damit also die Funktion Power(), oder?

Delphi-Quellcode:
var
  Pointvalue, // entspricht aktueller Position
  k: extended;

[...]
  { Pointvalue geht von 0 bis Image.Widht/Height, also
    auf 0..1 skalieren }
  Pointvalue:= (Pointvalue / aTo);
  k:= 1;
  F:= power(Pointvalue, k)*StartColor + (1-power(Pointvalue, k))*EndColor;
Beim Skalieren, wie du es nennst, war ich mir auch nicht
sicher, aber zumindest bleibt Pointvalue nun zwischen
0 und 1. Poinvalue müsste also stimmen.

Als Ergebnis erhalte ich bei k=1 leider 3 Verläufe (siehe Anhang).
Wenn K Richtung 0 geht, werden es ganz viele kleine Verläufe :-(

Wo steckt denn da der Fehler?

Dank und Gruß
Jürgen

Satty67 4. Apr 2009 10:25

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Ich glaub' ich bin ganz nah dran, wenn ich die Aufgabe richtig verstanden hatte:

Delphi-Quellcode:
function GetColorBetween(FromColor, ToColor: TColor; FromDomPercent : Byte;
                         LoRange, HiRange, Position : Integer): TColor;
type
  TRGB = packed record
    R,G,B,P : Byte;
  end;
const
  Gewichtung = 200;
var
  FromClr, ToClr, ResultClr : TRGB;
  i : Integer;
begin
  i := ColorToRGB(FromColor);
  FromClr := TRGB(i);
  i := ColorToRGB(ToColor);
  ToClr := TRGB(i);

  // Hier FromColor anteilig in ToColor einrechnen
  if FromDomPercent in [1..100] then begin
    ToClr.R := ToClr.R + ((FromDomPercent * FromClr.R) div 100);
    ToClr.G := ToClr.G + ((FromDomPercent * FromClr.G) div 100);
    ToClr.B := ToClr.B + ((FromDomPercent * FromClr.B) div 100);
  end;

  // Verlauf berechnen
  i := (Position * 255) div (HiRange - LoRange);
  ResultClr.R := ( (ToClr.R * i) + (FromClr.R * (255 - i)) ) div 255;
  ResultClr.G := ( (ToClr.G * i) + (FromClr.G * (255 - i)) ) div 255;
  ResultClr.B := ( (ToClr.B * i) + (FromClr.B * (255 - i)) ) div 255;
  ResultClr.P := 0;

  Result := TColor(ResultClr);
end;

procedure FillGradient(Canvas: TCanvas; FromClr, ToClr: TColor;
                       FromDomPercent: Byte; aRect: TRect; Vertical : Boolean);
var
  i : Integer;
begin
  if Vertical then begin
    for i := aRect.Top to aRect.Bottom do begin
      Canvas.Pen.Color := GetColorBetween(FromClr, ToClr, FromDomPercent, aRect.Top, aRect.Bottom, i);
      Canvas.MoveTo(aRect.Left, i);
      Canvas.LineTo(aRect.Right, i);
    end;
  end else begin
    for i := aRect.Left to aRect.Right do begin
      Canvas.Pen.Color := GetColorBetween(FromClr, ToClr, FromDomPercent, aRect.Left, aRect.Right, i);
      Canvas.MoveTo(i, aRect.Top);
      Canvas.LineTo(i, aRect.Bottom);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FillGradient(PaintBox1.Canvas, clRed, clBlue, SpinEdit1.Value, PaintBox1.ClientRect,False);
end;
PS: Nochmal leicht verändert, da Systemfarben nicht als Palettefarbe, sondern als Paletteneintrag behandelt werden...

PPS: Dominanz-Aufgabe noch mit eingebettet... 0-100% Domininaz der From-Farbe möglich (wobei 100% nicht die Zielfarbe völlig verschwinden lässt)

Satty67 4. Apr 2009 11:56

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Es wird übrigens nur die Farbe verändert, nicht die Helligkeit. Deshalb ist zum Testen Black -> White ganz schlecht, denn die Grausstufen ändern sich bei reiner Farb-Änderung nicht.

In der Anlage das Project, mit dem ich experimentiert hab'

Pfoto 4. Apr 2009 12:49

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Satty67,

vielen Dank erstmal für Deine Mühe!

Leider meinte ich mit "Gewichtung" etwas anderes, obwohl
man sicher auch deine Routine gut gebrauchen kann.

Die Start- und Endfarbe sollte jedoch nicht verändert werden,
sondern der Verlauf sollte eben nicht linear vorangehen,
sondern überproportional (oder wie man das nennt).
D.h. im ersten Drittel ist die Dominanz der ersten Farbe noch
deutlicher und lässt dann erst allmählich nach.

Im Anhang noch mal ein Beispiel von einem normalen und
dem von mir gemeinten Verlauf.


Gruß
Jürgen

Satty67 4. Apr 2009 13:23

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, dann hatte ich das falsch verstanden. (aber macht nicht, das experimentieren mit Farben macht mit am meisten Spass)

Hier dann mal ein anderer Ansatz (im Anhang das Projekt zum Testen)
Delphi-Quellcode:
function GetColorBetween(FromColor, ToColor: TColor; Distributor : Byte;
                         LoRange, HiRange, Position : Integer): TColor;
type
  TRGB = packed record
    R,G,B,P : Byte;
  end;
var
  FromClr, ToClr, ResultClr : TRGB;
  i,j, FirstPart, SecondPart, FullRange : Integer;
begin
  i := ColorToRGB(FromColor);
  FromClr := TRGB(i);
  i := ColorToRGB(ToColor);
  ToClr := TRGB(i);

  // Verlauf berechnen
  FullRange := (HiRange - LoRange);
  FirstPart := (Distributor * FullRange) div 100;
  SecondPart := FullRange - FirstPart;

  if Position < FirstPart then begin
    j := (Position * 50) div FirstPart;
  end else begin
    j := ((Position- FirstPart) * 50) div SecondPart;
    j := j + 50;
  end;

  i := (j * 255) div 100;

  ResultClr.R := ( (ToClr.R * i) + (FromClr.R * (255 - i)) ) div 255;
  ResultClr.G := ( (ToClr.G * i) + (FromClr.G * (255 - i)) ) div 255;
  ResultClr.B := ( (ToClr.B * i) + (FromClr.B * (255 - i)) ) div 255;
  ResultClr.P := 0;

  Result := TColor(ResultClr);
end;

procedure FillGradient(Canvas: TCanvas; FromClr, ToClr: TColor;
                       Distributor: Byte; aRect: TRect; Vertical : Boolean);
var
  i : Integer;
begin
  if Vertical then begin
    for i := aRect.Top to aRect.Bottom do begin
      Canvas.Pen.Color := GetColorBetween(FromClr, ToClr, Distributor, aRect.Top, aRect.Bottom, i);
      Canvas.MoveTo(aRect.Left, i);
      Canvas.LineTo(aRect.Right, i);
    end;
  end else begin
    for i := aRect.Left to aRect.Right do begin
      Canvas.Pen.Color := GetColorBetween(FromClr, ToClr, Distributor, aRect.Left, aRect.Right, i);
      Canvas.MoveTo(i, aRect.Top);
      Canvas.LineTo(i, aRect.Bottom);
    end;
  end;
end;

procedure TFormFarbverlauf.Button2Click(Sender: TObject);
begin
  If ColorDialog1.Execute then PanelFrom.Color := ColorDialog1.Color;
end;

procedure TFormFarbverlauf.Button3Click(Sender: TObject);
begin
  If ColorDialog1.Execute then PanelTo.Color := ColorDialog1.Color;
end;

procedure TFormFarbverlauf.TrackBar1Change(Sender: TObject);
begin
  LabelTrackbar.Caption := IntToStr(TrackBar1.Position)+' %';
  FillGradient(PaintBox1.Canvas, PanelFrom.Color, PanelTo.Color, TrackBar1.Position, PaintBox1.ClientRect,False);
end;

jfheins 4. Apr 2009 13:31

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hätte da auch was im Angebot :stupid:
Code:
namespace Test_1
{
    public partial class Form1 : Form
    {
        double potenz;
        Color col1;
        Color col2;

        public Form1()
        {
            InitializeComponent();

            col1 = Color.Red;
            col2 = Color.Blue;
            potenz = 1;
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            double pos = 0;
            double amount = 0;
            Color tempColor;
            Pen myPen = new Pen(col1);

            for (int i = 0; i < pictureBox1.Width; i++)
            {
                pos = (double)i / (pictureBox1.Width - 1);
                amount = 1 - Math.Pow(pos, potenz);
                // 1 - Weil wir den Betrag der ersten Farbe haben wollen
                tempColor = MixColors(col1, col2, amount);

                myPen.Color = tempColor;

                e.Graphics.DrawLine(myPen, new Point(i, 0), new Point(i, pictureBox1.Height - 1));
            }
        }

        private Color MixColors(Color col1, Color col2, double amount)
        {
            if (amount < 0 || amount > 1)
                throw new ArgumentOutOfRangeException("amount");

            byte R = (byte)(col1.R * amount + col2.R * (1 - amount));
            byte G = (byte)(col1.G * amount + col2.G * (1 - amount));
            byte B = (byte)(col1.B * amount + col2.B * (1 - amount));

            return Color.FromArgb(R, G, B);
        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            potenz = Math.Pow(1.1, trackBar1.Value);
            label1.Text = String.Format("Potenz: {0:F3}", potenz);
            pictureBox1.Invalidate();
        }
    }
}

Satty67 4. Apr 2009 13:37

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Kriegt ich Delphi 5 nicht beigebracht (ist das C# oder Delphi-Prism?)

***

Zu meinem zweiten Ansatz noch kurz die Idee dahinter:

Ich gehe einfach davon aus, das irgendwo der Farbverlauf die Mitte hat (Anteil beider Farben gleich) und verschiebe danach nur die Mitte und berechne Teilfarbverläufe zu neuen Mitte

jfheins 4. Apr 2009 13:52

Re: Verlauf mit "gewichteter" Farbe mittels Log?
 
Ist C# ;)

Ich habe den Ansatz von Medium gewählt.

Also mit der Laufvariable und der Potenz.

d.h. es wird eine Laufvariabele genommen die von 0 bis 1 geht (jeweils inkl.)

Der Anteil der zweiten Farbe ergibt sich dann aus laufvariable^Potenz - wenn also die Potenz gleich 1 ist isses ein linearer Farbverlauf.

Der Anteil der ersten Farbe ist dann der Rest (1 - laufvariable^Potenz)

Die Potenz muss zwischen 0 und unendlich liegen. Wenn sie null ist, ist der Anteil der zweiten Farbe immer Null, bis auf das Ende da springt er auf eins (also 100%)
Das andere Extrem ist unendlich, da ist der Anteil der zweiten Farbe erst null und springt danach sofort auf 1.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:19 Uhr.
Seite 1 von 2  1 2      

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