Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Algorithmus - Zahlen auf Display zentrieren (https://www.delphipraxis.net/175883-algorithmus-zahlen-auf-display-zentrieren.html)

Crocotronic 25. Jul 2013 15:14


Algorithmus - Zahlen auf Display zentrieren
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo,
ich suche nach einem Algorythmus, der mir 1,2 und 3-Stellige Zahlen auf einem Display zentriert. Dabei soll das ganze auch harmonisch aussehen (Abstände zwischen den Zahlen). Es handelt sich um ein "EA eDIP320-8" Display, dass ich mittels XPort ansteuer.
Ich zeig euch einfach mal meinen Ansatz, das erklärt's besser als eine schriftliche Beschreibung:
Delphi-Quellcode:
function DisplayDigit(aNumbers: integer): boolean;
const DspWidth=320; // Breite des Displays
var cText: string;
    n, nLeft: integer;
    nTmp: integer;
    DWidth, DWidthSum: integer;
    Numbers: array of integer;
begin
 ClientConnect;

 DWidthSum:=0; // Breite aller Zahlen
 SetLength(Numbers,Length(inttostr(aNumbers)));
 for n:= Low(Numbers) to High(Numbers) do
 begin
  Numbers[n]:= StrToInt(inttostr(aNumbers)[n+1]);
  DWidthSum:= DWidthSum+GetDigitWidth(Numbers[n],false); // Die Funktion GetDigitWidth läd das Bitmap-File ein und list die Breite aus
 end;

 if DWidthSum < DspWidth then // Falls die Display-Breite nicht ausgenutzt wird, dann das Übrige später als Rand aufaddieren
 begin
  nTmp:= Round((DWidthSum-DspWidth)/(High(Numbers)+1));
 end;

 for n:= High(Numbers) downto Low(Numbers) do // Hier wird Zahl für Zahl das Display mit den Bitmaps beschriftet
 begin
  DWidth:= GetDigitWidth(Numbers[n],false); // Breite des aktuellen Digits

  nLeft:= Round(DWidthSum-(DWidth/(High(Numbers)+1)))-Round(DWidth/2);
  nLeft:= nLeft+nTmp;        

  SendText2Dsp(nLeft,...);
  DWidthSum:= (DWidthSum - DWidth);
 end;

 ClientDisconnect;
end;
So hab ich mir das ganze überlegt, funktioniert aber nicht immer. Natürlich könnte ich einfach auf bestimme Zahlenlängen abfragen, aber ich brauche was universelles, was auch im Falle eines größeren Display funktionieren würde.
Im Anhang könnt ihr das Ergebnis der Funktion sehen.
Hat von euch jemand eine Idee wie ich das lösen kann?

Viele Grüße
Croco

p80286 25. Jul 2013 15:30

AW: Algorithmus - Zahlen auf Display zentrieren
 
Hast Du es schon mal mit der Positionierung eines Strings statt der einzelnen Ziffern versucht?

Gruß
K-H

Crocotronic 25. Jul 2013 15:37

AW: Algorithmus - Zahlen auf Display zentrieren
 
Scherzkeks. Hat schon einen Grund warum ich eine Zahl mit Bitmaps darstelle :P Die eigenen Ziffern sind auf maximaler Größe maximal verpixelt ^^

sx2008 25. Jul 2013 15:43

AW: Algorythmus - Zahlen auf Display zentrieren
 
So wie du eine GetDigitWidth()-Funktion hast solltest du auch eine GetTextWidth()-Funktion erstellen.
Ausserdem willst du vielleicht ja auch mal Buchstaben darstellen; also nicht nur Digits.
Delphi-Quellcode:
function GetCharWidth(c:Char):Integer;
function GetTextWidth(const s:string; spacing:integer=0):Integer;
procedure DisplayText(const s:string; p:TPoint; spacing:integer=0);
Der Parameter "spacing" ist der Zeichenabstand in Pixel.
(könnte man auch weglassen, denn man kann die zusätzliche Breite auch aus so ausrechnen (AnzahlZeichen-1)*spacing = Totalspacing))

Der maximale Wert für "spacing" sollte nicht mehr als 60% der Buchstabenhöhe betragen; ansonsten entsteht ein S p e r r t e x t.

Ein einfacher Algorithmus wäre mit dem maximalen spacing zu beginnen und zu prüfen, ob der Text in die vorgesehene Breite passt und ausserdem ein Rand links+rechts von mindestens 4 * spacing übrig bleibt.
Falls zu wenig Rand übrig dann spacing verkleinern und erneut rechnen.

Wichtig sind auf jeden Fall die Funktionen von oben, denn erst wenn man so nützliche Hilfsfunktionen hat kann man sich auch den Algorithmus stürzen.

Crocotronic 25. Jul 2013 17:58

AW: Algorithmus - Zahlen auf Display zentrieren
 
Es sind Bitmaps die ich darstelle, keine Strings. Wenn die die Ziffer 2-Stellig ist, brauche ich 2 Bitmaps.

Furtbichler 25. Jul 2013 18:00

AW: Algorithmus - Zahlen auf Display zentrieren
 
Du könntest das Problem vereinfachen, indem Du die Ziffern-Bitmaps so gestaltest, das alle Ziffern gleich breit sind. Das ist sowieso eine anzustrebende Maßnahme, weil bei ungleicher Ziffernbreite und z.B. aufsteigendem Zähler die Zahl sonst hin und her wackelt.

Für Buchstaben gilt das natürlich nur bedingt.

Crocotronic 25. Jul 2013 18:04

AW: Algorithmus - Zahlen auf Display zentrieren
 
Das hab ich am Anfang genau so gemacht, nur hat sich dann ein optisches Problem ergeben. Wenn z.B. eine 11 angezeigt wird, dann sieht das total verkrüppelt aus, da die Einsen entweder viel zu nah aneinander oder viel zu weit weg von einander sind. Deshalb ist ein Bitmap immer nur genau so groß, wie die Zahl selbst.

Buchstaben werde ich nie anzeigen müssen

BUG 25. Jul 2013 18:32

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Zitat von Furtbichler (Beitrag 1222700)
Das ist sowieso eine anzustrebende Maßnahme, weil bei ungleicher Ziffernbreite und z.B. aufsteigendem Zähler die Zahl sonst hin und her wackelt.

Ich nehme mal an, das die Zahlen längere Zeit angezeigt werden (Wartenschlangennummer, oÄ.).

Das Stichwort heißt Kerning.

Ich würde eine 10x10 Matrix erstellen, in denen die Unterschneidungen für jedes Ziffernpaar gespeichert ist.
Wenn es nötig ist, könnte man noch eine (unsichtbare) Pseudoziffer mit betrachten, welche am Anfang und Ende jeder Zahl steht und die Zentrierung anpasst (dann also 11x11 Matrix).

Furtbichler 26. Jul 2013 07:54

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Zitat von Crocotronic (Beitrag 1222702)
Das hab ich am Anfang genau so gemacht, nur hat sich dann ein optisches Problem ergeben. Wenn z.B. eine 11 angezeigt wird, dann sieht das total verkrüppelt aus, da die Einsen entweder viel zu nah aneinander oder viel zu weit weg von einander sind. Deshalb ist ein Bitmap immer nur genau so groß, wie die Zahl selbst.

Schau dir mal Zahlen aus Fixed-Spaced Fonts (Courier z.B.) die sind so designed und es sieht gut aus.

Allerdings kann ich dein ästhetisches Naserümpfen nachvollziehen, allerdings zappelt die Anzeige dann hin und her (fände ich persönlich grauenvoll).

Furtbichler 26. Jul 2013 07:58

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Zitat von Crocotronic (Beitrag 1222702)
Das hab ich am Anfang genau so gemacht, nur hat sich dann ein optisches Problem ergeben. Wenn z.B. eine 11 angezeigt wird, dann sieht das total verkrüppelt aus, da die Einsen entweder viel zu nah aneinander oder viel zu weit weg von einander sind. Deshalb ist ein Bitmap immer nur genau so groß, wie die Zahl selbst.

Schau dir mal Zahlen aus Fixed-Spaced Fonts (Courier z.B.) die sind so designed und es sieht gut aus.

Allerdings kann ich dein ästhetisches Naserümpfen nachvollziehen, aber dann zappelt die Anzeige eben hin und her (fände ich persönlich grauenvoll). Außer...
Zitat:

Zitat von BUG (Beitrag 1222707)
Ich nehme mal an, das die Zahlen längere Zeit angezeigt werden (Wartenschlangennummer, oÄ.).

Dann natürlich nicht.

Bei der Kerning-Geschichte reicht vermutlich die Aufzählung der Ausnahmen ('01' fällt mir auf Anhieb ein, eventuell '07'. '11' vielleicht negativ, aber das wars dann im Groben).

Crocotronic 26. Jul 2013 12:47

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Zitat von BUG (Beitrag 1222707)
Ich nehme mal an, das die Zahlen längere Zeit angezeigt werden (Wartenschlangennummer, oÄ.).

Richtig!

Zitat:

Zitat von Furtbichler (Beitrag 1222735)
Schau dir mal Zahlen aus Fixed-Spaced Fonts (Courier z.B.) die sind so designed und es sieht gut aus.
Allerdings kann ich dein ästhetisches Naserümpfen nachvollziehen, allerdings zappelt die Anzeige dann hin und her (fände ich persönlich grauenvoll).

Ich habe nur 12 Fonts zur Verfügung, die schon auf dem Display gespeichert sind. Und wie schon gesagt, sind diese bei maximaler Größe viel zu verpixelt. Deshalb musste ich aus jeder Zahl ein eigenes Bitmap machen.

Das mit dem Kerning schau ich mir mal genauer an...

Klaus01 26. Jul 2013 12:57

AW: Algorithmus - Zahlen auf Display zentrieren
 
nunja - verpixelt, da kommt es auch immer auf die Entfernung die Betrachter zum Display hat an.

Grüße
Klaus

Perlsau 26. Jul 2013 14:33

AW: Algorithmus - Zahlen auf Display zentrieren
 
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:

Zitat von Crocotronic (Beitrag 1222685)
ich suche nach einem Algorythmus, der mir 1,2 und 3-Stellige Zahlen auf einem Display zentriert.

Ist im Grunde nicht schwer. Als Beispiel hab ich eine kleine Testanwendung angehängt (Delphi 2009).

Furtbichler 26. Jul 2013 16:26

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Deshalb musste ich aus jeder Zahl ein eigenes Bitmap machen. Das mit dem Kerning schau ich mir mal genauer an...
Na dann hast Du doch die maximale Freiheit. Stichwort Kerning: Fixed Space Fonts (Courier z.B.) benötigen kein Kerning :-) Du kannst Dir ja die Bitmaps so wie eine Consolas, Letter Gothic oder Lucida Sans Typewriter erstellen bzw. von Windows sogar rendern lassen: Einfach in 150pt (oder was weiss ich) in Word, Screenshot => Bitmap => Fertig.

Hier mal mein bescheidener Beitrag (Zahl wird von rechts nach links gezeichnet). Die Kerninginfo steht im Array 'KerningCorrection'.
Die '1' hinter einer '0' wird um 10 Pixel, die '7' hinter einer '0' um 6 pixel nach links verschoben,

Delphi-Quellcode:
Const
  KerningCorrection : Array [0..9, 0..9] Of Integer = (
       {  0   1   2   3   4   5   6   7   8   9}
   {0} (  0,-10, 0, 0, 0, 0, 0, -6, 0, 0),
   {1} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {2} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {3} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {4} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {5} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {6} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {7} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {8} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
   {9} (  0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
);
Function CalcNumberWidth (Number : Integer) : Integer;
Var
  Digit, DigitToTheRight : Integer;

Begin
  Result := 0;
  DigitToTheRight := -1;
  Repeat
    Digit := Number mod 10;
    Number := Number div 10;
    Result := Result + GetDigitWidth(Digit,false) + GetKerningCorrection (Digit, DigitToTheRight);
    DigitToTheRight := Digit;
  Until Number=0;
End;

Procedure DrawNumberAt (LeftPos, Number : Integer);
Var
  Digit, DigitToTheRight : Integer;

Begin
  Repeat
    Digit := Number mod 10;
    Number := Number div 10;
    LeftPos := LeftPos -  GetDigitWidth(Digit,false) + GetKerningCorrection (Digit, DigitToTheRight);
    DigitToTheRight := Digit;
    DrawDigitAt(LeftPos, Digit);
  Until Number=0;
End;

Function GetKerningCorrection (Digit, DigitToTheRight : Integer) : Integer;
// > 0 add spacing, < 0 reduce spacing
Begin
  If DigitToTheRight = -1 then
    result := 0
  else
    result := AdditionalSpacing[Digit, DigitToTheRight];
End;

Procedure DisplayNumber (Number : Integer; Alignment : TAlignment);
Const
  DisplayWidth = 320;
Var
  NumberWidth, LeftPos, i : Integer;

Begin
  ClientConnect;
  Try
    NumberWidth := CalcNumberWidth(Number);
    case Alignment of
      taLeftAlignment:
        LeftPos := DisplayWidth - NumberWidth;
      taCenter:
        LeftPos := (DisplayWidth + NumberWidth) div 2;
      taRightAligment
        LeftPos := DisplayWidth;
    end;

    DrawNumberAt(LeftPos, Number);
  Finally
    ClientDisconnect
  End
End;
Ungetestet.

Crocotronic 28. Jul 2013 14:18

AW: Algorithmus - Zahlen auf Display zentrieren
 
Liste der Anhänge anzeigen (Anzahl: 1)
:shock::shock::shock: Wow, funktioniert auf anhieb! Dafür schon mal vielen vielen Dank!
Was noch nicht ganz funktioniert ist, dass die Kerning Correction beim zentrieren mit einberechnet wird (siehe Bild).

Viele Grüße
Croco

Furtbichler 28. Jul 2013 15:30

AW: Algorithmus - Zahlen auf Display zentrieren
 
Hast Du denn eine Kerning-Korrektur für '01' oder nur für '10'. Bei der '1' ist links ein leerer Raum, und denn füllt man mit einem kleinen Teil des rechten Rands der '0'.

Ich würde eher sagen, das der Parameter für 'Alignment' auf taLeftAlignment steht bzw. der Wert von 'LeftPos' falsch ist.

Vor dem Aufruf von DrawNumberAt muss er den rechten Rand des rechten Bitmaps (bei dir die '0') beschreiben. Die Breite sollte korrekt errechnet sein...

Haaalt! Da ist ein kleiner Fehler.

Delphi-Quellcode:
Procedure DrawNumberAt (LeftPos, Number : Integer);
Var
   Digit, DigitToTheRight : Integer;

Begin
   DigitToTheRight := -1; // <<<<<< FEHLT!
   Repeat
...

Crocotronic 28. Jul 2013 16:18

AW: Algorithmus - Zahlen auf Display zentrieren
 
Zitat:

Zitat von Furtbichler (Beitrag 1222862)
Hast Du denn eine Kerning-Korrektur für '01' oder nur für '10'. Bei der '1' ist links ein leerer Raum, und denn füllt man mit einem kleinen Teil des rechten Rands der '0'.
Ich würde eher sagen, das der Parameter für 'Alignment' auf taLeftAlignment steht bzw. der Wert von 'LeftPos' falsch ist.

Also ich hab die Kerning-Korrektur bei 1 für 1 auf -20 stehen
Delphi-Quellcode:
{1} ( 0, -20, 0, 0, 0, 0, 0, 0, 0, 0),
Das Alignment steht auf taCenter. Es wird auch zentriert, wenn ich die -20 durch eine 0 ersetze.

Zitat:

Zitat von Furtbichler (Beitrag 1222862)
Haaalt! Da ist ein kleiner Fehler.

Delphi-Quellcode:
Procedure DrawNumberAt (LeftPos, Number : Integer);
Var
   Digit, DigitToTheRight : Integer;

Begin
   DigitToTheRight := -1; // <<<<<< FEHLT!
   Repeat
...

Tatsächlich! Ist aber nicht der Fehler für das falsch Zentrierte.

Crocotronic 28. Jul 2013 16:28

AW: Algorithmus - Zahlen auf Display zentrieren
 
Habs! Abs ist das Stichwort ;)

Delphi-Quellcode:
function TWartezeit.CalcNumberWidth(aNumber: integer): integer;
var Digit, DigitToTheRight : Integer;
begin
 Result:= 0;
 DigitToTheRight:= -1;
 repeat
  Digit:= aNumber mod 10;
  aNumber:= aNumber div 10;
  Result:= Result + GetDigitWidth(Digit,false) + Abs(GetKerningCorrection(Digit, DigitToTheRight)); // <- hier würde sonst die Breite verringert werden
  DigitToTheRight:= Digit;
 until aNumber=0;
end;

Furtbichler 29. Jul 2013 07:14

AW: Algorithmus - Zahlen auf Display zentrieren
 
Nein nein. Steht eine '1' rechts von einer '0', soll die '0' etwas nach links rutschen. Das geschieht, indem die '0' dann etwas schmaler wird. Vielleicht habe ich die Vorzeichen in der KerningCorrection-Matrix vertauscht. Ich hatte es ja nicht getestet.


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