Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Performanceproblem: Anzeige von Positionen mehrerer Clients (https://www.delphipraxis.net/156914-performanceproblem-anzeige-von-positionen-mehrerer-clients.html)

alphaflight83 20. Dez 2010 14:10

Delphi-Version: 2009

Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Tag auch,
ich habe momentan ein mittelschweres Anzeige-Performanceproblem.
Und zwar müssen mehrere Clients anhand von Positionsangaben (X, Y, Winkel) auf einer Karte angezeigt
und ihre Pfade aufgezeichnet werden.
Die Daten kommen hierbei zyklisch vom Server.
Nun die Frage(n):
Wie kann ich möglichst ressourcenschonend
1. Mehrere Clients (momentan bis zu 64) bzw. ihre Bewegungen anzeigen
2. den Pfad für diese Clients aufzeichnen (Liste für X und Y Koordinaten im Ringspeicher)
3. Den Pfad für jeweils ein Gerät anzeigen.

Momentaner Stand:
Ad 1. Dynamisch erstellte Frames, die je nach Winkel ein entsprechendes Bild anzeigen.
Bei Bewegung werden die Frames auf einem Panel verschoben.
Ad 2. Zum Aufzeichnen der Pfade wird ein Array
Delphi-Quellcode:
Positions : Array [1 .. 64] of TList;
verwendet, das dann Records der Art
Delphi-Quellcode:
TRecPos = record
  Xpos : Integer;
  Ypos : Integer;
  Angle : Integer;
end;
speichert.
TQueue habe ich nicht verwendet, weil ich auf alle Elemente zugreifen muss und TQueue,
soweit ich gesehen habe, eine Eigenschaft wie Items[Index] fehlt.
Ist die Liste voll, werden die Einträge von vorne überschrieben.
Um den momentanen Start-Index für jeden Client zu behalten, wird dieser in einem weiteren Array abgelegt.
Ad 3. Die Pfade werden auf einer über das Panel gelegten Paintbox mit
Delphi-Quellcode:
PaintBox.Canvas.MoveTo(Y1, X1);
PaintBox.Canvas.LineTo(Y2, X2);
angezeigt.
Hierbei wird durch die jeweilige Liste iteriert und von Punkt zu Punkt verbunden.
Grundsätzlich funktioniert das schon,
allerdings ist das Ganze performancetechnisch relativ bescheiden, um es positiv auszudrücken.

Ich bin für jeden sinnvolleren Ansatz bzw. Tipp bzgl. Komponenten, Vorgehensweise etc. dankbar.

Grüße, alphaflight

stho 20. Dez 2010 14:46

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Wo liegt denn genau der Flaschenhals?
Beim Zeichnen oder beim Senden/Empfangen?
Vielleicht solltest du nicht das komplette Array an jeden Client senden sondern nach dem Empfangen der Werte prüfen welche sich geändert haben und diese dann an die Clienten verteilen?
Sendest du das komplette array in einem Rutsch an die Clienten oder nur die einzelnen records in einer Schleife?
Zeichnen solltest du auf ein unsichtbares bitmap und dann mittels "BitBlt" auf deine Paintbox (oder ein TImage?) übertragen...

(Bei mir lasse ich ein Array von 1.000.000 Records durchlaufen und regelmäßig neuzeichnen...
mit dieser Methode geht das ziemlich schnell!)

alphaflight83 20. Dez 2010 15:39

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Hallo stho,

erstmal danke für die Antwort.
Der Flaschenhals ist wohl ein mehrfacher.

Schon beim Einschalten des Positions-"Loggens" sind Einbrüche zu verzeichnen,
die beim Pfadzeichnen dann noch verstärkt werden.

Das größte Problem ist anscheinend allerdings die Anzeige bzw. das Verschieben der Frames mit den winkelabhängig unterschiedlichen Bildern.
Hier ist bei einer Zunahme der Framezahl ein deutlicher Einbruch spürbar.

Ich werde morgen mal die vorgeschlagene Zeichenmethode ausprobieren.
Ich denke aber, dass zusätzlich die Änderung des Lese-Schreib Vorganges unumgänglich ist.

Bummi 20. Dez 2010 17:26

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
vielleicht hilft Dir das
http://www.delphipraxis.net/156716-g...-und-zoom.html

alphaflight83 21. Dez 2010 08:28

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Hi Bummi,
danke für den Link.

Im Thread schreibst du, dass das nicht deine präferierte Methode zur Animation ist ...
Nun, was würdest du mir denn für meine Anwendung empfehlen?
Mir geht es um eine möglichst flüssige Ausgabe bei maximaler Performance.

Dazu muss ich sagen, dass ich erste Versuche mit Andorra gemacht habe,
in meiner Anwendung neben dieser Anzeige aber gleichzeitig auch andere "Module" laufen können/müssen.
Das Positionsmodul mit Andorra lief nun einigermaßen flüssig, der Rest bekam aber kaum noch Rechenzeit ab ...

Zudem hat sich hier das Problem gestellt, wie man das einigermaßen vernünftig in Threads verpacken kann,
da in jedem Modul relativ viel wieder angezeigt werden muss.

Bummi 21. Dez 2010 13:21

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Was meinst Du mit Clients und anderen Modulen, was ist unter Positions-"Loggen" zu verstehen?
Können die Daten gethreaded gesammelt werden, könntest Du mit Canvas.Lock eine Offscreenbitmap mit allen Clientpositionen in einem Thread erstellen.

alphaflight83 21. Dez 2010 16:33

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
Das Programm beinhaltet mehrere Teilbereiche, die Positionsanzeige ist also nur eine Funktion unter vielen,
von denen mehrere gleichzeitig laufen können müssen.

Mit Positionsloggen meinte ich, dass die Positionsdaten der Clients über einen gewissen Zeitraum gesammelt werden.
Angezeigt werden kann, der Übersicht wegen, immer nur der Pfad eines Clients.

Das mit dem Offscreenbitmap ist keine schlechte Idee und sollte funktionieren.
Damit und mit GDI werde ich mich mal näher befassen.

Danke schön für den Tipp.

alphaflight83 20. Jan 2011 15:16

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
So, ich bin mal wieder bei diesem Thema gelandet ... und dank der Tipps von Bummi bin ich ein Stück weiter gekommen.
Das Offscreenbitmap funktioniert grundsätzlich und ich habe die verlinkten Sprites verwendet um die Clients anzuzeigen.
Abgesehen von ein paar Details habe ich nun ein Problem:
Ich möchte die Sprites eigentlich mit auf das Offscreenbitmap packen, nur hat sich mir bisher nicht erschlossen,
wie ich die gedrehten Sprites da rauf bekomme, bzw. ob das so überhaupt möglich ist.
Oder anders formuliert: Wie kann ich performant ein Bitmap drehen um es dann auf das Offscreenbitmap zu kopieren.
(In der Endanwendung sollen um die 60 Clienten angezeigt werden.)

Zudem hab ich bisher noch nicht gerafft, wie ich ein Bitmap/Image komplett "löschen", also auf komplette Transparenz zurücksetzen kann.
Edit: Hab einen Thread zum Leeren von Offscreenbitmaps gefunden, in dem Möglichkeiten aufgezeigt werden.

Grundsätzlich ist das Vorgehen doch richtig, die Position und Ausrichtung aller Clienten zu ermitteln und nacheinander auf ein Offscreenbitmap zu zeichnen,
das dann wiederum nach dem Hintergrund-Offscreenbitmap auf das Canvas gezeichnet wird?!?
Das Positions-Offscreenbitmap wollte ich dann zyklisch neu zeichnen um die Positionen anzupassen ...

Hab mich jetzt auch mal an GDI+ rangewagt (Mit der Version von Erik van Bilsen) Allerdings gibt es hier noch einige Unklarheiten.
(z.B. Kann man ein Objekt "Auf der Stelle" rotieren, ohne dass durch RotateTransform das Koordinatensystem für ein TranslateTransform verschoben wird?)

Grüße, alphaflight83

alphaflight83 11. Feb 2011 09:52

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
So, ich glaube ich habe nun das Ergebnis, das ich haben wollte.

Zunächst mal hab ich einen Zwischenschritt beim Zeichnen weggelassen der keinen Sinn machte
und zeichne nun alles auf EIN Offscreenbitmap.

Mit GDIPlus hab ich nun auch bei den rotierten Images ein zufriedenstellendes Ergebnis erzielt.

Anmerkungen:
Der Beispiel-Code verwendet kein Offscreenbitmap.
Die Bilsen GDIPlus Implementation verwendet Objekt-Interfaces.

Delphi-Quellcode:
uses GDIPlus;

procedure TFormDrawThis.DrawImages;
var
  Graphics: IGPGraphics;
  Image: IGPImage;
  Matrix: IGPMatrix;
  imgWidth, imgHeight : Integer;
  Angle : Single;
begin
  (* Lock the canvas *)
  Canvas.Lock;

  (* Get the dimensions of the bitmap *)
  imgWidth := Image.GetWidth;
  imgHeight := Image.GetHeight;
   
  (* Create the GDIPlus components *)
  Graphics := TGPGraphics.Create(Canvas.Handle);
  Image := TGPImage.Create(sImage_Path + 'AwesomeImage.png', TRUE);
  (* Create the transformation matrix *)
  Matrix := TGPMatrix.Create;  

  (* Set the transformation *)
  Angle := 30.0;
  Matrix.Translate(150, 100);
  Matrix.RotateAt(Angle, TGPPointF.Create(150, 100), MatrixOrderAppend);
  Graphics.SetTransform(Matrix);

  (* Draw the image according to the transformation translated to it's center *)
  Graphics.DrawImage(Image,-imgWidth*0.5,-imgHeight*0.5, imgWidth, imgHeight);

  (* Reset the transformation in the matrix and the graphics *)
  Graphics.ResetTransform;
  Matrix.Reset;

  (* Set the new transformation *)
  Angle := 120.0;
  Matrix.Translate(100, 150);
  Matrix.RotateAt(Angle, TGPPointF.Create(100, 150), MatrixOrderAppend);
  Graphics.SetTransform(Matrix);

  (* Draw the next image according to the transformation translated to it's center *)
  Graphics.DrawImage(Image,-imgWidth*0.5,-imgHeight*0.5, imgWidth, imgHeight);

  (* Reset the transformation in the matrix and the graphics *)
  Graphics.ResetTransform;
  Matrix.Reset;
   
  (* aso *)

  (* Flush all the stuff to the canvas *)
  Graphics.Flush();
end;
Falls jemand eine einfachere Möglichkeit kennt, immer her damit ;)

Gruß, alphaflight83

shmia 11. Feb 2011 16:22

AW: Performanceproblem: Anzeige von Positionen mehrerer Clients
 
@alphaflight83: dein Kommentarstil ist na ja, etwas "ineffizient".
Hier zwei Beispiele:
Delphi-Quellcode:
(* Lock the canvas *)
Canvas.Lock;

(* Flush all the stuff to the canvas *)
Graphics.Flush();
Diese Kommentare haben keine Aussagekraft und sind damit mehr schädlich als nützlich.
Soll heisen, man sollte keine Dinge kommentieren, die ganz offensichtlich aus dem Code hervorgehen.
Stattdessen würde ein mehrzeiliger Kommentar vor der Methode der in zwei Sätzen erklärt,
was hier passieren soll deutlich mehr Information an den Leser geben.

Ausserdem brauchst du für jede Kommentarzeile zu viel Schreibaufwand, weil du (* *) anstelle von // benützt.
Ich benütze Kommentare so:

Delphi-Quellcode:
// das ist ein Einzeiliger Kommentar

{
mehrzeile Kommentare
lassen sich gut mit geschweiften Klammern umsetzen.
diese Blöcke setze ich gerne vor Methoden um zu erklären
was der folgende Code tun soll
}

(* auskommentierter Code
if debug_flag then
  ShowMessageFmt('Anzahl=%d', [anz]);
*)
Styleguide > Kommentare

Und jetzt hätte ich noch eine Bitte an Alle:
bitte hier keine Diskussion über Kommentare im Sourcecode anfangen.


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