Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Eine Eigene Linen Zeichnen ? (https://www.delphipraxis.net/102709-eine-eigene-linen-zeichnen.html)

mimi 2. Nov 2007 19:58


Eine Eigene Linen Zeichnen ?
 
Hallo,
da ich schon länger Zeit für verschiedene Zwecke eine eigene Linen Zeichne möchte, habe ich diese Code heute geschrieben:
Delphi-Quellcode:
procedure DrawLinePluto(aCanvas:TCanvas; const x1,y1,x2,y2:Integer; PenColor:TColor);
var
  wx,wy:Integer;
  fx,fy,mx,my:Integer;
begin
  wx:=abs(x2-x1);
  wy:=abs(y2-y1);
 
  fx:=x1; fy:=y1;

  if wx = 0 then mx:=0 else mx:=+1;
  if wy = 0 then my:=0 else my:=+1;
 
  while True do begin
    aCanvas.Pixels[fx,fy]:=PenColor;
    fx:=fx+mx;
    fy:=fy+my;
    if (my <> 0) and (fy = y2) then break;
    if (mx <> 0) and (fx = x2) then break;
  end;
end;
Ich würde gerne von euch wisse, ob dieser Code alle Situationen Abdeckt und ob es "noch schneller" geht.
Im Internet habe ich leider nur sehr viele Beschreibungen gesehen, die mir zu Kompliziert beschrieben wahren.

Ich möchte später nach einigen Tests, verschiedene Varianten von dieser Procedere erstellen.
Z.b. Welche Die Mehrer Farben da stellen könne, im Moment kann die Line ja nur in einer Farbe da gestellt werden. Mein Ziel ist es mehrer Farben hinzubekommen, und mit Farb Muster und sowas.
das ist aber nicht weiter schwierig.

Was haltet ihr von der Procedere ?

edit:

Delphi-Quellcode:

procedure DrawLinePluto(aCanvas:TCanvas; const x1,y1,x2,y2:Integer; PenColor:TColor);
var
  wx,wy:Integer;
  fx,fy,mx,my:Integer;
begin
  wx:=x2-x1;
  wy:=y2-y1;
  fx:=x1; fy:=y1;

  if wx = 0 then mx:=0 else mx:=+1;
  if wy = 0 then my:=0 else my:=+1;

  while True do begin
    aCanvas.Pixels[fx,fy]:=PenColor;
    if wx > 0 then
      fx:=fx+mx
    else
      fx:=fx-mx;

    if wy > 0 then
      fy:=fy+my
    else
      fy:=fy-my;


    if (my <> 0) and (fy = y2) then break;
    if (mx <> 0) and (fx = x2) then break;
  end;
end;
So diese Procedere kann jetzt auch mit Negativen Werten arbeiten(scheint auf jedenfall so)

Edit2:
Leider kann diese Procedere nur Perfekte Lienen da stellen, was aber nicht immer sinvoll ist. es werden keine "Treppen" Lienen gezeichnet.

EDatabaseError 2. Nov 2007 20:03

Re: Eine Eigene Linen Zeichnen ?
 
Moin,

schau dir mal TCanvas genau an. Dies bringt sowas von Haus aus mit.

IMHO:
Delphi-Referenz durchsuchenMoveTo
Delphi-Referenz durchsuchenLineTo

mimi 2. Nov 2007 20:05

Re: Eine Eigene Linen Zeichnen ?
 
das weiß ich auch, aber dort kann man nicht ohne weiteres eine Line z.b. in mehrer Farben zeichnen ohne das mühevoll mit Polygonen oder anders zu lösen.

ich kenne die TCanvas Klasse sehr gut.

Edit01: Erste Tests haben ergeben, das diese Procedere leider nicht mit negativen Zahlen umgehen kann.
hat einer eine Idee wie ich das am einfachsten einbauen könnte ?

EDatabaseError 2. Nov 2007 20:13

Re: Eine Eigene Linen Zeichnen ?
 
Ich schätz mal das der Code hier

Delphi-Quellcode:
procedure DrawLine(aCanvas: TCanvas ; x1,y1,x2,y2: Integer ; color: TColor);
var
  crntColor: TColor;
begin
 crntColor := aCanvas.Pen.Color;
 aCanvas.Pen.Color := color;
 aCanvas.MoveTo(x1,y1);
 aCanvas.LineTo(x2,y2);
 aCanvas.Pen.Color := crntColor;
end;
das gleiche macht wie deiner... :idea:

wegen den negativen zahlen: Im Form links oben ist (0|0) weiter nach links gehts in dem fall nicht. Du müsstest da dann ein Offset einbauen das bspw. gezeichnet 50 gerechnet 0 ist.

SirThornberry 2. Nov 2007 20:15

Re: Eine Eigene Linen Zeichnen ?
 
Zitat:

Was haltet ihr von der Procedere ?
gar nichts.

folgender Aufruf klappt (verständlicher Weise) nicht:
Delphi-Quellcode:
DrawLinePluto(Self.Canvas, 0, 0, 150, 600, clBlue);
es wird eine Linie gezeichnet im 45 Grad Winkel aber nicht zu dem Punkt den ich angegeben habe. Die Funktion ist so nutzlos, die Logic stimmt einfach nicht.

Dein Quelltext bewirkt das du eintweder in jedem Schritt 1 oder gar kein Pixel nach Rechts und unten gehst. Das bewirkt logischer Weise ein 45 Grad Winkel oder 0 Grad.

mimi 2. Nov 2007 20:18

Re: Eine Eigene Linen Zeichnen ?
 
Ja ! da gebe ich dir Recht.
Aber ich möchte ja später die Möglichkeit haben eine mehrfarbige Line zu gestalten das ist mit MoveTo und LieneTo leider sehr aufwendig. und mit Poligonen möchte ich das erst recht nicht machen.

Außerdem möchte ich selber verstehen wie ein DDA Algorithmus arbeitet .
Es gibt für viele mehrer Möglichkeiten je nach dem was man gerade braucht bzw. machen möchte.
Wie mein Zweck eignet sich MoveTo und LineTo leider nicht. es sei denn man kann irgendwie mit nur einem Procedere Aufruf mehrfarbig zeichnen.

edit:
was schlägst du also vor ?

SirThornberry 2. Nov 2007 20:21

Re: Eine Eigene Linen Zeichnen ?
 
ich schlage eine Verhältnisgleichung vor.
Wenn eine Linie von x1 nach x2 gezeichnet werden soll dann muss x bei der hälfte der Stecke auch auf der y-Achse die hälfte der Stecke zurück gelegt haben.

mimi 2. Nov 2007 20:22

Re: Eine Eigene Linen Zeichnen ?
 
Ja das ist logisch..... und weiter ?

edit: Aber das mache ich doch schon im Prinzip ? beide Variablen werden um den gleichen Faktor erhört.....

SirThornberry 2. Nov 2007 20:30

Re: Eine Eigene Linen Zeichnen ?
 
du erhöhst nicht um einen Factor sondern um 1 oder 0

mimi 2. Nov 2007 20:40

Re: Eine Eigene Linen Zeichnen ?
 
wie meinst du das ?
Wenn es eine Negative Line ist verringere ich den "Faktor" und wenn es eine Positive ist erhöhe ist sie.

Aber was müsste ich jetzt genau ändern damit das klappt ?

SirThornberry 2. Nov 2007 20:53

Re: Eine Eigene Linen Zeichnen ?
 
probier mal folgende Funktion:
Delphi-Quellcode:
procedure DrawLine(ACanvas: TCanvas; x1, y1, x2, y2: Integer; AColor: TColor);
var
  lCount,
  lDistanceX,
  lDistanceY,
  lStepSize  : Integer;
begin
  lDistanceX := x2 - x1;
  lDistanceY := y2 - y1;
  if Abs(x2 - x1) < Abs(y2 - y1) then
  begin
    lCount := 0;
    if (lDistanceY > 0) then
      lStepSize := +1
    else
      lStepSize := -1;

    while (lCount <> lDistanceY) do
    begin
      ACanvas.Pixels[x1 + Trunc(lCount * lDistanceX / lDistanceY), y1 + lCount] := AColor;
      lCount := lCount + lStepSize;
    end;
  end
  else
  begin
    lCount := 0;
    if (lDistanceX > 0) then
      lStepSize := +1
    else
      lStepSize := -1;

    while (lCount <> lDistanceX) do
    begin
      ACanvas.Pixels[x1 + lCount, y1 + Trunc(lCount * lDistanceY / lDistanceX)] := AColor;
      lCount := lCount + lStepSize;
    end;
  end;
  ACanvas.Pixels[x2, y2] := AColor;
end;
Wie bereits erwähnt geht es hier um ein Verhältnis damit die Linie nicht 45 Grad wird und nicht wie du es machst entweder +1 oder 0. Sondern der X Punkt muss sich zum Y Punkt in dem Verhältnis ändern wie das Verhältnis der Länge der Linien ist.

mimi 2. Nov 2007 21:08

Re: Eine Eigene Linen Zeichnen ?
 
BESTEN DANK ! Ich werde ihn mir mal genau ansehen.

SirThornberry 2. Nov 2007 21:10

Re: Eine Eigene Linen Zeichnen ?
 
wie gesagt. Es geht darum im Verhältnis etwas zu berechnen.
Wenn du zum Beispiel eine Linie von x: 0 - y: 0 nach x: 10 - y: 40 zeichnen willst, musst du bei jedem Schritt auf der X-Achse 4 Schritte auf der Y-Achse gehen. Du musst also das Verhältnis der X-Distance zur Y-Distance gleich setzen mit dem SchrittX zu SchrittY. Nennt sich glaub ich auch Dreiecksgleichung.
Wenn du später mal eine Linie mit Farbverlauf zeichnen willst musst du die Farbanzteile zur Länge der Linie ebenso ins Verhältnis setzen.

Muetze1 2. Nov 2007 22:11

Re: Eine Eigene Linen Zeichnen ?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hier mal die alte Demo von mir mit den Marching Ants. Da ist noch eine andere Möglichkeit aufgezeigt.

/EDIT: Aber basiert auf einem WinAPI Befehl!

mimi 3. Nov 2007 12:33

Re: Eine Eigene Linen Zeichnen ?
 
Danke Muetze1 werde ich mir gleich mal ansehen.

Ich finde dieses Thema im Moment recht Intressant, weil ich mich in den letzten 10 Jahren wo ich mit Object Pascal arbeite damit mich noch nie befast habe.

Später geht es mir auch noch um andere Figuren wie z.b. Kreise, Vierecke, Abgerundete Ecken....
Aber erstmal die Line mein Ziel ist es in erster Line SirThornberry Procedure so zu erweitern, das ich Linen Style verwenden kann(eigene) und natürlich Farb Style die man mit den Linen Style Verbinden kann.

Wie das geht weiß ich schon. Kennt jemand von euch ein Tutorial was das gut beschreibt ? also mit einfachen Wörtern die jeder "normale" Mensch versteht ?

Weil auf den meisten seiten die ich zum Thema gefunden habe, wird leider alles über Formulen erklärt, aber ich habe keine Idee, wie man diese Formueln verstehen soll....

Wie gesagt, ich möchte dieses Thema verstehen.....

mimi 3. Nov 2007 13:37

Re: Eine Eigene Linen Zeichnen ?
 
ich habe in deiner Pas Datei gesehen, das du
LineDDA benutz, was mir nicht viel Weiter hilf. Ich wollte ja eine eigene Funktion, Ich meine diese Procedure gibt es auch für Lazarus.

Trotzdem Danke !

mimi 3. Nov 2007 17:32

Re: Eine Eigene Linen Zeichnen ?
 
ich habe jetzt die Procedure erweitert von:SirThornberry Vielen Dank noch mal für dein Code.

Delphi-Quellcode:
procedure DrawLine(ACanvas: TCanvas; x1, y1, x2, y2: Integer; AColor: TColor; style:array of Boolean; FarbStyle:array of TColor);
  procedure StyleFarbeLine(var zc,zw,z,lenStyle, lenColor,W:Integer);
  begin
      if (lenStyle > -1) and (lenColor > 0) then begin
        if zc +1 <= lenColor then
          inc(zc)
        else
          zc:=0;
      end; // lenColor

      if lenStyle > -1 then begin
        if z +1 <= Length(style) then
          inc(z)
        else
          z:=0;
       end; // lenStyle

      if (lenStyle = -1) and (lenColor > 0) then begin
        if zw+1 >= w then begin
          zw:=0;
          if zc+1 <=lenColor then inc(zc);
        end
        else
          inc(zw);
      end;

  end;

var
  lCount,lDistanceX,lDistanceY,lStepSize: Integer;
  z,zc,lenColor,lenStyle,w,zw:Integer;
  lc:TColor;
begin
  lDistanceX := x2 - x1;
  lDistanceY := y2 - y1;
  z:=0; zc:=0; zw:=0;
  lenColor:=Length(FarbStyle);
  lenStyle:=Length(style)-1;

  if lenColor = -1 then lc:=AColor;

  if Abs(x2 - x1) < Abs(y2 - y1) then begin
    lCount := 0;
    if (lDistanceY > 0) then
      lStepSize := +1
    else
      lStepSize := -1;

    w:=abs(lDistanceY div lenColor);
    while (lCount <> lDistanceY) do begin
      if lenColor > 0 then lc:=FarbStyle[zc];
      if (lenStyle = -1) or (lenStyle >= 0) and (style[z]) then
        ACanvas.Pixels[x1 + Trunc(lCount * lDistanceX / lDistanceY), y1 + lCount] := lc;
      StyleFarbeLine(zc,zw,z,lenStyle,lenColor,w);
      lCount := lCount + lStepSize;
    end;
  end
  else begin
    lCount := 0;
    if (lDistanceX > 0) then
      lStepSize := +1
    else
      lStepSize := -1;

    w:=abs(lDistanceX div lenColor);
    while (lCount <> lDistanceX) do begin
      if lenColor > 0 then lc:=FarbStyle[zc];

      if (lenStyle = -1) or (lenStyle >= 0) and (style[z]) then
        ACanvas.Pixels[x1 + lCount, y1 + Trunc(lCount * lDistanceY / lDistanceX)] := lc;
      StyleFarbeLine(zc,zw,z,lenStyle,lenColor,w);
      lCount := lCount + lStepSize;
    end;
  end;
  ACanvas.Pixels[x2, y2] := AColor;
end;  

// Beispiel Aufruf:
DrawLine(PaintBox1.Canvas,mx,my,x,y,clRed,[],[clred,clBlue,clYellow]);
Nun Kann sie mit Farb Stylen und Linen Stylen umgehen*freu*

Edit00: Proceure geändert.

Edit01: Neue Version von der Proceure: Jetzt dürfte alles klappen. Ich hatte im Obigen teil ein abs vergessen bei der w Zuweisung.

Muetze1 3. Nov 2007 18:11

Re: Eine Eigene Linen Zeichnen ?
 
Zitat:

Zitat von mimi
..., was mir nicht viel Weiter hilf. Ich wollte ja eine eigene Funktion, Ich meine diese Procedure gibt es auch für Lazarus.

LineDDA ist eine GDI Funktion und könnte höchstens nachgebildet werden unter Lazarus. Aber unter Linux? Naja, kA.

Und warum sollte dir die Funktion (neben dem eben erwähnten) denn nicht helfen? Die Funktion implementiert den Linien-zeichnen Algorithmus und berechnet jeden einzelnen Punkt, welcher zu Zeichnen ist und ruft zum zeichnen jeweils die angegebene Funktion auf. Somit kannst du doch deinen Style/Farbe etc frei anpassen. Du wirst für jeden einzelnen Punkt aufgerufen. Von daher kapier ich deinen Einwand nicht oder du hast die Funktion nicht im Detail verstanden.

mimi 3. Nov 2007 18:35

Re: Eine Eigene Linen Zeichnen ?
 
ehrlich gesagt, habe ich mir die Funktion lineDDA gar nicht angesehen....
ich habe nur die Parameter gesehen und das reichte mir schon.

Du meinst damit ist sowas schon möglich ? von Windows aus ? Bunte Linen ?

SirThornberry 3. Nov 2007 18:37

Re: Eine Eigene Linen Zeichnen ?
 
so wie ich muetze verstanden habe gibt man eine callbackmethode an welche dann für das zeichnen jedes pixels aufgerufen wird

Muetze1 3. Nov 2007 18:38

Re: Eine Eigene Linen Zeichnen ?
 
Zitat:

Zitat von mimi
Du meinst damit ist sowas schon möglich ? von Windows aus ? Bunte Linen ?

Wie gesprochen: Du musst eine Callback Funktion angeben und diese wird für jeden einzelnen Punkt mit dessen Koordinaten aufgerufen. Wie du diesen Punkt mals liegt in deiner Hand und somit kannst du diese doch malen wie du es willst. Das Beispiel zeigt doch schon auf, was möglich ist. Ich lasse mit der LineDDA() Funktion die 4 Linien ständig zeichnen und beim Zeichnen bestimmte ich nur, ob ich den jeweiligen Pixel nun zeichne oder nicht. Dabei wird immer wieder eine Verschiebung reingebracht, wass dann zu dem gezeigten Effekt der "marschierenden Ameisen" führt. Siehe EXE/Code.

/EDIT: roter Kasten?

SirThomberry trifft es genau.

mimi 3. Nov 2007 18:43

Re: Eine Eigene Linen Zeichnen ?
 
ich habe mir dein Beispiel noch einmal angesehen und mir ist ein Licht aufgegangen...

Aber leider nützt er mir wenig da ich unter Lazarus keine LineDDA Procedure habe.

Ich könnte allerdings den Code entsprechend umbauen... Wenn ich wollte.

Naja, dann nochmal VIELEN DANK.
ich glaube jetzt weiß ich wie LineDDA Arbeitet, hatte es beim ersten hinsehen nicht ganz verstanden aber jetzt schon. Unter Delphi währe das eine Erleichterung gewesen.

Muetze1 3. Nov 2007 18:49

Re: Eine Eigene Linen Zeichnen ?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von mimi
Aber leider nützt er mir wenig da ich unter Lazarus keine LineDDA Procedure habe.

Hatte ich ja schon vermutet. Hätte mich gewundert, wenn es so wäre.

Aber nun habe ich in der Zwischenzeit mal ein Beispiel von dem Marching Ants Beispiel abgeleitet mit einer bunten Linie. Vielleicht hilft es dir ja, um die Farbwerte zu bilden.

mimi 3. Nov 2007 18:54

Re: Eine Eigene Linen Zeichnen ?
 
nicht schlecht... das habe ich so hinbekommen:
Delphi-Quellcode:
procedure DrawRect(const aCanvas:TCanvas; const x1,y1,x2,y2:Integer; const AColor: TColor; const LinenStyle:array of Boolean; const FarbSyle:array of TColor);
begin

  // Oben
  DrawLine(aCanvas,x1,y1,x2,y1,AColor,LinenStyle,FarbSyle);

  // Unten
  DrawLine(aCanvas,x1,y2,x2,y2,AColor,LinenStyle,FarbSyle);

  // Links
  DrawLine(aCanvas,x1,y1,x1,y2,AColor,LinenStyle,FarbSyle);

  // Rechts
  DrawLine(aCanvas,x2,y1,x2,y2,AColor,LinenStyle,FarbSyle);
end;
Auf diese art und weise kann ich ebenfalls ein Viereck zeichnen....
Was mit Bunten Linen und Stylen klar kommt. Das einzigte Problem was ich noch haben sind Füllmuster.

alzaimar 4. Nov 2007 08:02

Re: Eine Eigene Linen Zeichnen ?
 
Schau Dir einfach den Bresenham-Algorithmus an, das ist eigentlich der Algorithmus, der in so ziemlich heder Graphics-Engine implementiert ist. Er benötigt keine Floatingpoint-Mathematik und ist imho der schnellste Algorithmus.
Hier in der DP
Wiki

mimi 4. Nov 2007 15:02

Re: Eine Eigene Linen Zeichnen ?
 
Floatingpoint-Mathematik
die kenne ich gar nicht....

Danke ! Den Wiki Aktikel kannte ich schon, der hat mir nicht weiter geholfen, wegen den Formeln die ich verstehe, weil ich nicht weiß wie ich sie lesen muss

Der Andere link könnte Hilfreich sein. Vielen Dank dafür.....
Weil ich möchte wie schon gesagt noch weitere Figuren selbst zeichnen wie z.b. ein Kreis.Ich habe gelesen das kann der Bresenham-Algorithmus ebenfalls.

edit00:
Delphi-Quellcode:
if dy >= 0 then    // positive Steigung
    if dx >= dy then   // leichte positive Steigung
      for x := P1.X to P2.X do
      begin
        Plot(x,y);
        if 2*(e + dy) < dx then
          Inc(e,dy)
        else
        begin
          Inc(y);
          Inc(e, dy-dx);
        end;
      end
    else
Diesen Teil verstehe icn noch nicht ganz: was passiert genau bei 2*(e+dy) ?
ich weiß das es sich hierbei um eine Berechnung handelt. aber zu welchem Zweck ?

Khabarakh 4. Nov 2007 15:27

Re: Eine Eigene Linen Zeichnen ?
 
Zitat:

Zitat von mimi
Floatingpoint-Mathematik
die kenne ich gar nicht....

Floatingpoint = Gleitkommazahl ;) . Soll heißen, der Algo benötigt die FPU überhaupt nicht. Genauer gesagt benötigt er nicht einmal mehr als Addition und Bit-Shifting.

Zitat:

Danke ! Den Wiki Aktikel kannte ich schon, der hat mir nicht weiter geholfen, wegen den Formeln die ich verstehe, weil ich nicht weiß wie ich sie lesen muss
:gruebel: Unter "Ansatz" lässt sich nur eine einzige Formel finden und die ist zur mathematischen Ergänzung.

Zitat:

Diesen Teil verstehe icn noch nicht ganz: was passiert genau bei 2*(e+dy) ?
Dazu müsstest du schon das verlinkte Tutorial durchlesen. Die Erklärung bei Wikipedia ist aber wirklich einfacher und kommt ganz ohne Formeln aus.

mimi 4. Nov 2007 15:40

Re: Eine Eigene Linen Zeichnen ?
 
naja, dann muss ich die Funktion mal bei Gelegenheit auseinander nehmen, Zeile für Zeile.
Aber die Beispiel Soruce Sagen mir im Moment recht wenig.


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:15 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