Autor Beitrag
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 13:33 
Moin :)!

Folgendes Problem: ich habe eine Zeichenfälche, auf die ich Zeiger zeichne. Dabei wird automatisch eine derartige Skalierung gewählt, sodass kein Zeiger aus dem Bild verschwindet. Dieser Skalierungsfaktor (pro Achse verschieden) berechnet sich wie folgt (stark gekürzt):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
      //Skalierungsfaktor (x) bestimmen
      SetLength(tempvars, Length(vars) + 1);
      oldv := 0;
      for i := Low(vars) to High(vars) do begin
        if ListBox2.Checked[i] then
          tempvars[i] := Abs(vars[i].Real);
        tempvars[i] := Abs(tempvars[i]);
        end;
      if Zeichnen1.Checked then
        tempvars[Length(vars)] := Abs(loesung.Real);
      scalex := MaxValue(tempvars); //Größten Realteil bestimmen (Betrag!)
      SetLength(tempvars, 0);
      if scalex = 0 then //Zu kleine Skalierung unterbinden (EDivideByZero)
        scalex := 0.9;
      scalex := (w div 2 - 10) / scalex; //10px Abstand


Das in der letzten Zeile ist der endgültige Wert der Skalierung; Beispiel: ist scalex 50, entspricht eine Einheit auf der x-Achse exakt 50 Pixel, 2 100, 3, 150 etc.
Nun kann der Benutzer aber die Achsen beschriften lassen - und hier liegt das eigentliche Problem. Der Benutzer kann wählen, in wieviele Teile er die Achse unterteilt haben möchte; diese werden dann beschriftet. Nun kann es allerdings passieren, dass der Benutzer folgendes sieht:

0,6  1,1  1,7  2,2 (Achtung: Werte sind auf eine Kommastelle gerundet!)

Und genau das will ich wenn irgendmöglich vermeiden. Meine Frage also: wie schaffe ich es, dass scalex so gewählt wird, dass die Beschriftungen linear und ohne Kommafehler angezeigt werden; also z.B. so:

0,6  1,2  1,8  2,4?

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 13:35 
Den Faktor vor der Verwendung auf gewünschte Werte runden!
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 13:36 
user profile iconwdbee hat folgendes geschrieben:
Den Faktor vor der Verwendung auf gewünschte Werte runden!


Die Idee hatte ich auch schon, nur wie finde ich heraus, ob ein Wert gewünscht ist ;)

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 13:39 
Gewünschte Werte können doch sein: Ganze Zahlen, Ganze Zahlen div 2, Ganze Zahlen div 10 usw.
Was tatsächlich sinnvoll ist, hängt von der Anwendung ab! Bei Zeitskalen kommen statt 10er Teilungen auch 12er oder 7er in Frage.
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 13:44 
user profile iconwdbee hat folgendes geschrieben:
Gewünschte Werte können doch sein: Ganze Zahlen, Ganze Zahlen div 2, Ganze Zahlen div 10 usw.


Eben nicht. Ich hab mal debuggt und für die oben genannten Achsenbeschriftung habe ich xscale = 78,000 (exakt)

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 13:47 
Und das sind dann 7,8 pro Pixel, richtig? Sei großzügig und nimm 8, dann hast du dass was du willst! :wink:
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 13:50 
user profile iconwdbee hat folgendes geschrieben:
Und das sind dann 7,8 pro Pixel, richtig? Sei großzügig und nimm 8, dann hast du dass was du willst! :wink:


Nein... 78 bedeutet, dass 78 Pixel dem Wert 1 auf der x-Achse entsprechen, 156 dem Wert 2 etc.:

ausblenden Quelltext
1:
2:
---------------------------------------
     0,6   * 1,1     1,7     2,2 ...


*... hier irgendwo ist 1; genau bei 78 Pixel

Runden bringt nichts... irgendwie muss da noch die Anzahl der Beschriftungen mit rein...

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 13:53 
Ich war von 10 Pixeln pro Teilstrich ausgegangen. Wenn du 39 hast, musst du statt durch 10 durch 39 Teilen und dann runden bzw. aufrunden, richtig?
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 13:58 
user profile iconwdbee hat folgendes geschrieben:
Ich war von 10 Pixeln pro Teilstrich ausgegangen. Wenn du 39 hast, musst du statt durch 10 durch 39 Teilen und dann runden bzw. aufrunden, richtig?


Wenn's so einfach wäre; ich hab nicht unbedingt eine ganzzahlige Anzahl Pixel pro Teilstrich. Beispiel: Benutzer stellt ein, er möchte 10 Unterteilungen haben, macht bei einer Fenstergröße von z.B. 456 Pixel exakt 45,6 Pixel pro Teilstrich ;)

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 14:05 
Ich habe das immer so gemacht, dass dann die Pixelabstände abgerundet werden, damit sie bei der Ausgabe tatsächlich gleiche Abstände haben.
Aber wenn du das anders lieber hast, dann musst du doch deinen Skalierungsfaktor nur noch aus deiner Achse zurückrechnen (Dreisatz). Maximalwert der dargestellt werden soll ist gegeben, Länge der Achse ist gegeben, Anzahl der Unterteilungen ist gegeben. Also Aufrunden des Maximalwertes ggf. unter Berücksichtigung der Anzahl der zu beschriftenden Teilstriche und dann sollten nur noch glatte Werte auftreten, auch wenn sie nicht an der exakten Stelle gezeichnet werden können.
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 14:22 
Was is ein Dreisatz :gruebel: Ich kenn zwar Pythagoras und Thales, aber einen Dreisatz kenn ich nicht...

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 14:37 
Wenn 10 Teilstricheabstände 456 Pixel lang sind, wie lang sind dann 5 Teilstrichabstände?

10 <-> 456
5 <-> x

x := (5 * 456) / 10

Das heißt bei uns Dreisatz (Grundschule).

Aber nochmal zum Thema: Du hast mehrere Freiheitsgrade: Länge der Achse, Anzahl der Teilstriche, Abbildungsmaßstab. Wenn du nun die Länge der Achse der Fensterbreite gleichsetzen willst und die Anzahl der Teilstriche vorgeben willst, dann musst du den Abbildungsmaßstab ausrechnen, der dazu führt, dass alle Teilstriche vernünftig beschriftet werden können.
Du kannst aber auch umgekehrt vorgehen, und die Anzahl der Teilstriche berechnen, die zu einem vernünftigen Ergebnis führen. Maximalwert aufgerundet gibt den Wert an der maximalen Länge der Achse.
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 14:45 
user profile iconwdbee hat folgendes geschrieben:
Aber nochmal zum Thema: Du hast mehrere Freiheitsgrade: Länge der Achse, Anzahl der Teilstriche, Abbildungsmaßstab. Wenn du nun die Länge der Achse der Fensterbreite gleichsetzen willst und die Anzahl der Teilstriche vorgeben willst, dann musst du den Abbildungsmaßstab ausrechnen, der dazu führt, dass alle Teilstriche vernünftig beschriftet werden können.


Genau das will ich, nur irgendwie steh ich @themoment voll auf dem Schlauch und hab keine Ahnung, wie der Code dazu aussehen muss :autsch:

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 14:58 
Wenn die Länge der Achse 456 ist und der Maximalwert 5,85 (456/78=5,85):

Aufrunden auf 6

Anzahl der Teilstriche soll 10 sein: Abstand der Teilstriche 456/6 = 76
Beschriftung 0,6 1,2 1,8 usw,
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 15:04 
Funktioniert nicht...

ausblenden Quelltext
1:
0,5  1,1  1,6					


AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 15:07 
An welchen Stellen berechnest du denn die Werte?

0,76,152,228...
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 15:19 
Beispiel: Zeichenfläche ist 1100 Pixel groß (der Einfachheit halber) und der User stellt 10 Unterteilungen ein; dann hab ich eine bei 100, eine bei 200, ... etc. - eben genau 10 Striche ;)

AXMD

PS.: Im Anhang eine Debugversion, die die Werte von scalex und scaley auf der Zeichenfläche links oben ausgibt; Unter Ansichtseinstellungen mal mit der Anzahl der Beschriftungen spielen... das funzt nicht...
Einloggen, um Attachments anzusehen!
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 15:46 
Skalierung reele Achse:
Wenn die Einstellung auf 6 steht, ist die Achse 7 Teilstriche lang? Ist das im Programm auch so berücksichtigt?

Ach und die Abbildungsfaktoren bleiben immer gleich? Das kann so nicht stimmen. Denn dann gibt es nur bei Teilung durch 10 sinnvolle Werte (sprich Zehntel).

Muss für eine Weile weg. Ich melde mich später mal mit etwas Code.


Zuletzt bearbeitet von wdbee am Mi 23.03.05 15:55, insgesamt 3-mal bearbeitet
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mi 23.03.05 15:47 
user profile iconwdbee hat folgendes geschrieben:
Skalierung reele Achse:
Wenn die Einstellung auf 6 steht, ist die Achse 7 Teilstriche lang? Ist das im Programm auch so berücksichtigt?


Klar, der User kann ja einstellen, wieviele Teilstriche er haben will; die Achse wird dann in Teilstriche + 1 Teile zerlegt

AXMD
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 23.03.05 17:19 
Kleines Demo:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
type
  TForm1 = class(TForm)
    EditTS: TEdit;
    Label1: TLabel;
    EditVal: TEdit;
    Label2: TLabel;
    Button1: TButton;
    EditScale: TEdit;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function CalcScale(Achse,Teilstriche: Integer; Value: Double): Double;
var
  UnitValue: Double;
  MaxValue: Double;
begin
  UnitValue := Value / (Teilstriche + 1);
  UnitValue := (Trunc(10 * UnitValue) + 1) / 10.0;
  Result := UnitValue;
  MaxValue := UnitValue * (Teilstriche + 1);
  Result := Achse / MaxValue;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Scale, AScale, Value: Double;
  Achse, Teilstriche: Integer;
  X0,Y0,X: Integer;
  I: Integer;
begin
  DecimalSeparator := '.';
  Teilstriche := StrToInt(EditTS.Text);
  Value := StrToFloat(EditVal.Text);
  Achse := Image1.Width div 2;

  Scale := CalcScale(Achse,Teilstriche,Value);
  AScale := Achse / (Teilstriche + 1);

  EditScale.Text := Format('%f',[Scale]);

  X0 := Image1.Width div 2;
  Y0 := Image1.Height div 2;
  with Image1.Canvas do
  begin
    FillRect(Rect(0,0,Image1.Width,Image1.Height));
    MoveTo(X0, 0);
    LineTo(X0, Image1.Height);
    MoveTo(X0, Y0);
    LineTo(Image1.Width, Y0);
    MoveTo(X0, Y0 - 20);
    LineTo(Round(X0 + Value * Scale), Y0 - 20);
    for I := 1 to Teilstriche do
    begin
      x := Round(X0 + I * AScale);
      MoveTo(x, Y0 + 10);
      LineTo(x, Y0 - 10);
      Textout(x, Y0 + 15, Format('%.1f',[(x-X0)/Scale]));
    end;
  end;
end;
Einloggen, um Attachments anzusehen!