GDI - DrawLines

  • VB.NET

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von rotherford.

    GDI - DrawLines

    Hallo,

    Ich bin gerade dabei eine Art Gauge-Control zu erstellen (Anhang) und komme bei der Berechnung der Nadel-Position nicht (mehr) wirklich weiter.
    Mein Control besitzt die Eigenschaft Value (0-100).

    Die Nadel besteht aus 3 Punkten, die mittels DrawLines() verbunden werden:

    VB.NET-Quellcode

    1. 'M (PointF) ist der Mittelpunkt des Controls
    2. 'KnobRadius ist der Radius (Single) des "Mittelpunktkreises"
    3. 'GetPointAt ist eine Funktion um den Punkt eines Winkels an einem Kreis zu bekommen.
    4. Dim Vertices(3) As PointF
    5. Vertices(0) = New PointF(M.X - KnobRadius, M.Y)
    6. Vertices(1) = New PointF(M.X + KnobRadius, M.Y)
    7. Vertices(2) = GetPointAt(Angle, B)
    8. Vertices(3) = Vertices(0)
    9. Dim Pth As New GraphicsPath
    10. Pth.StartFigure()
    11. Pth.AddLines(Vertices)
    12. G.DrawPath(Pens.Silver, Pth)

    Nun Zum Problem:
    Wenn die Value = 50% ist, dann funktioniert alles perfekt, wenn aber die Value z.B 90% ist, dann wird die Nadel immer Dünner.
    Ich habe es schon mit Matrix-Transformation usw. versucht, aber irgendwie lässt sich das Problem nicht beheben.
    Kennt jmd. einen einen Lösungsansatz/Lösung?

    Ich nehme es euch nicht übel, wenn ihr das Problem nicht versteht, ich habe absolut keine Ahnung wie ich den ganzen Gedankensalat in Worte packen soll ;)
    Ich denke aber die Bilder helfen etwas.

    Liebe Grüße
    Bilder
    • 5090.jpg

      23,36 kB, 672×432, 285 mal angesehen
    /nicht getestet
    Kannst du vielleicht die Funktion GetPointAt posten? Denn dann wäre es einfach dir zu helfen. Achja, wird der Winkel in Grad oder im Bogenmaß angegeben?
    Hier die Funktion:

    VB.NET-Quellcode

    1. Private Function GetPointAt(ByVal Angle As Single, ByVal ContainerRect As Rectangle) As PointF
    2. Dim GetRadians As New Func(Of Single, Single)(Function(Angle_)
    3. Return CSng(Angle_ * Math.PI / 180)
    4. End Function)
    5. Dim Middle As New PointF(CSng(ContainerRect.Width / 2) + ContainerRect.X, CSng(ContainerRect.Height / 2) + ContainerRect.Y)
    6. Dim R As Single = CSng(ContainerRect.Width / 2)
    7. Return (New PointF( _
    8. CSng(Middle.X + R * Math.Cos(GetRadians.Invoke(Angle))), _
    9. CSng(Middle.Y + R * Math.Sin(GetRadians.Invoke(Angle)))))
    10. End Function


    Wird in Bogenmaß umgerechnet.
    Liebe Grüße
    /nicht getestet
    Die Funktion Liefert ja richtige Werte zurück.
    Ich denke ich weiß woran es liegt:
    Vertices(0) & Vertices(1) sind fest definiert (Siehe Anhang)

    Da müsste ich mit Rotation bzw. Transformation arbeiten - Was meint ihr?
    Liebe Grüße
    Bilder
    • 5090.jpg

      25,35 kB, 672×432, 232 mal angesehen
    /nicht getestet

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „rotherford“ ()

    Oh, stimmt, das macht Sinn. Dann musst du die beiden Punkte also auf dem Umkreis des Innersten Kreises drehen.
    Perfekt, Es klappt!
    Vielen Dank.

    Lösung:

    VB.NET-Quellcode

    1. 'Knob ist ein Rectangle, in dem der Mittelkreis enthalten ist.
    2. Vertices(0) = GetPointAt(Angle - 90.0F, Knob)
    3. Vertices(1) = GetPointAt(Angle + 90.0F, Knob)

    Liebe Grüße
    /nicht getestet
    Das so zu berechnen ist übrigens unfug xD
    GDI+ verfügt über eine Transform-Eigenschaft vom typ Matrix. Diese kann alles, was mit manipulation zutun hat: verschieben, strecken, zerren, skalieren UND drehen. Ist viel einfacher und schneller.

    lg
    Ja, aber ich glaube danach sind alle Mouse-Koordinaten Pfutsch?

    Hat zwar gerade nichts mit dem Thema zu tun, aber ich frage mich gerade warum für MeasureString eine Graphics Klasse instanziert sein muss? ;)

    Liebe Grüße
    /nicht getestet

    rotherford schrieb:

    warum muss für MeasureString eine Graphics Klasse instanziert sein?
    Die Graphics-Instanz allein weiß, wie der String darzustellen ist, also weiß sie auch, wie groß er ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    {...MatrixTransformationen...}

    rotherford schrieb:

    Ja, aber ich glaube danach sind alle Mouse-Koordinaten Pfutsch?
    Ja, wenn man die Matrix auf das Gesamte Control anwendet, wird die Zeichnung ziemlich bald undurchführbar.
    Aber du kannst die Matrix auf einen Klon des Zeiger-GraphicsPath anwenden, dann kannste den schön drehen und Zeugs.

    Also imo kommt man bei so Controls mit mehreren ZeichenObjekten nicht mehr drumrum, auch wirklich im Code intelligente Zeichenobjekte anzulegen, die "wissen, wie und wo sie sich selbst zeichnen".
    gugge Control mit beweglicher Figur
    und such auf activevb.de/cgi-bin/upload/search.pl nach "clocksample" suchen - das ist sehr ähnlich deinem Prob.
    @RodFromGermany
    Aber Wieso dann nicht als Shared?

    @ErfinderDesRades
    Klon?
    ICloneable bzw. MemberWiseClone()?
    Das heißt, wenn ich eine Transformation nur auf einen GraphicsPath anwende, bleiben Koordinaten etc. erhalten?
    Ja, vielleicht hätte ich das Ganze mit Transformation ggf. Rotation erledigen können,
    Aber ich glaube ich werde das Ganze jetzt nicht mehr umschreiben.. ;)

    Liebe Grüße
    /nicht getestet

    rotherford schrieb:

    Aber Wieso dann nicht als Shared?
    Weil Graphics-Objekte für den Bildschirm, das Papier usw. recht unterschiedlich aussehen, aber äquivalente Ergebnisse liefern müssen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    rotherford schrieb:

    Klon?
    Ja, was - weißt du nicht, was ein Klon ist? Ein anderes Objekt, in allen Eigenschaften gleich der Vorlage. Wie du das heranschaffst, ob MemberwiseClone, ICloneable, ein Copy-Konstruktor oder sonstwas daran beteiligt ist, ist mir ja schnurz.
    Aber GraphicsPath implementiert ja tatsächlich die ICloneable-Schnittstelle.

    Das heißt, wenn ich eine Transformation nur auf einen GraphicsPath anwende, bleiben Koordinaten etc. erhalten?
    wessen Koordinaten?
    Bei sone Transformation wird der GraphicsPath total verändert - eben die Darstellung rückt an die richtige Position mit der richtigen Drehung und Scalierung

    Aber ich glaube ich werde das Ganze jetzt nicht mehr umschreiben.. ;)
    (Abwarten ;))
    naja, in meinem Konzept von DrawFigure.
    Da beinhaltet eine Figur einen Standard-GraphicsPath, und wenn die Figur bewegt und sonstwie verändert wird, so darf man natürlich nicht den Standard-GraphicsPath bewegen, sonst hat man ja bei der nächsten Bewegung eine ziemlich unkalkulierbare Ausgangslage.
    Also vom Standard-GP (dem "Template") eine Kopie ziehen, und die herumschubsen.

    Aber ich habe doch Beispiele gegeben.

    rotherford schrieb:

    Warum muss man erst eine Kopie vom GraphicsPath erstellen?
    Es gibt 2 Möglichkeiten:
    1. Du hast 1 GP-Objekt, auf das Du alle Änderungfen anwendest, dass Du also 17000 Mal transformierst.
    2. Du machst Dir einen Clone und addierst die Änderungen in einer Rotations-, einer Vergrößerungs- und einer Translationsvariablen.
    Also 17000 Additionen und genau eine Transformation. Wenn ich da eine Fehlerbetrachtung anstelle, ist die 2. Lösung, die vom @ErfinderDesRades: die deutlich bessere.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!