Zeichnen von Linien einer best. Länge zu einem Winkel



  • Wir haben in der Fortbildung das Fach Softwareentwicklung und Handhabung. Grundlage ist C/C++ und als Programm nutzen wir TCLite.

    Ich stehe momentan vor dem Problem eine Linie in Abhängigkeit von einem Winkel zeichnen zu wollen und/oder einen Kreis/Kreisbogen zu beschriften(eine Skala wäre auch nicht schlecht).
    Ich kann zwar Linien ziehen mit Angabe von Start und Endpunktpunkt, oder Tortenstücke mit Angabe von Winkel und Radius usw., aber eine Linie mit bestimmter Länge von einem Punkt in einem bestimmten Winkel bekomme ich nicht hin, geht das überhaupt??
    Der Versuch ist eine Art Manometer grafisch darzustellen, in dem eine Skala zu sehen ist und je nachdem was für Werte rein kommen sich dann auch ein Zeiger bewegt. Das "Gehäuse" und die Grobe Skala(ziemlich aufwändig) bekomme ich j anoch hin, aber bei dem Zeiger weiß ich nicht weiter.
    Über einen Tip wäre ich echt dankbar.
    Gruß
    Jens



  • müsste mathe 1. klasse sein.

    #define MF_PI_DIV_180      0.017453292519943295769236907684886   // Pi / 180 (1 Grad)
    
    //---------------------------------------------------------------------------
    // Funktion wandelt den Winkel 'a' in Bogenmass um
    //---------------------------------------------------------------------------
    template <typename T> 
    inline const double DegreeToArc(const T a)
    {
      return (((double) (a)) * MF_PI_DIV_180);
    }
    
    //---------------------------------------------------------------------------
    // Funktion berechnet die Koordinaten des Punktes, ausgehend vom
    // Punkt 'Point' mit dem Steigungswinkel 'Degree' und der geforderten
    // Entfernung 'Distance'.
    //---------------------------------------------------------------------------
    template <typename T>
    inline void Point2D<T>::GetPointByDistance(const Point2D<T> &Point, double Degree, double Distance)
    {
      x = Point.x + (Distance * cos(DegreeToArc(Degree)));
      y = Point.y - (Distance * sin(DegreeToArc(Degree)));
    }
    


  • Hallo Sunday, danke dir dafür.

    Mathe 1. klasse? Naja, ich weiß nicht so recht ... für dich mag es vielleicht einfach nachzuvollziehen sein, aber ich habe trotz deiner Kommentare noch ein paar Probleme den Code zu verstehen. Wir sind an unsere Lernunterlagen gebunden bzw. an die Möglichkeiten des Programms TCLite und unsere Lernunterlagen bzw. die Hilfe geben nicht so wirklich viel her.

    Also mal von vorn:

    Zuerst legst du den Wert fest, mit dem man den Winkel in Bogenmaß umrechnet, ist klar da die Winkelfunktionen in Bogenmaß rechnen.

    Dann wird in der Funktion a übergeben, umgerechnet und sofort wieder zurückgegeben.(Wo genau definiere ich dann vorher a oder ist das egal?)

    Mein nächstes Problem ist dann die Geschichte mit der Winkelberechnung. Es ist doch wichtig zu wissen in welchem Quadranten ich mich befinde, oder? Denn je nach dem in welchem Q ich bin, ändert sich die Berechnung von x bzw. y !?

    Template kennt TCCLite übrigens nicht. In der Hilfe steht drin, das diese Funktion für später reserviert ist!??

    Dann hätte ich noch eine Frage, kann man einen Kreisbogen oder Kreis angepaßt beschriften oder geht das nur waage oder senkrecht?

    Danke für deine Antwort und Geduld!! 👍



  • TTron schrieb:

    Zuerst legst du den Wert fest, mit dem man den Winkel in Bogenmaß umrechnet, ist klar da die Winkelfunktionen in Bogenmaß rechnen.
    Dann wird in der Funktion a übergeben, umgerechnet und sofort wieder zurückgegeben.(Wo genau definiere ich dann vorher a oder ist das egal?)

    double DegreeToArc( double a )
    {
      return a * MF_PI_DIV_180;
    }
    

    Die Variable 'a' ist als Parameter der Funktion 'DegreeToArc' definiert.

    TTron schrieb:

    Mein nächstes Problem ist dann die Geschichte mit der Winkelberechnung. Es ist doch wichtig zu wissen in welchem Quadranten ich mich befinde, oder? Denn je nach dem in welchem Q ich bin, ändert sich die Berechnung von x bzw. y !?

    Oh nein - auf keinen Fall. Die Formel, die Sunday angegeben hat, gilt in jedem Quadranten.
    Sein Kreis läuft aber mathematisch negativ; korrekt wäre etwa so was:

    void GetPointByDistance( Point2D* Point, double Degree, double Distance )
    {
      Point->x = Point->x + (Distance * cos(DegreeToArc(Degree)));
      Point->y = Point->y + (Distance * sin(DegreeToArc(Degree))); /* <== mit '+' */
    }
    

    TTron schrieb:

    Template kennt TCCLite übrigens nicht. In der Hilfe steht drin, das diese Funktion für später reserviert ist!??

    Soweit ich das gesehen habe, ist TCLite doch reines C und kein C++ - oder?

    Noch ein Tip: den Wert für PI kann man mit

    double PI = acos(-1.0);
    

    berechnen und damit bekommt man dann natürlich auch die Konstante MF_PI_DIV_180

    double MF_PI_DIV_180 = PI / 180.0;
    

    Gruß
    Werner



  • Oh .. danke für die Erläuterung Werner!!

    Das TCLite ein reiner C Compiler ist, das kann gut sein ... sorry, dann ist das hier wohl auch falsch 😕 😞

    Wie würde das denn in C aussehen?

    Mein Teilkreis(Skala) läuft übrigens von 225° - 315° , d.h. er deckt 270° ab. Null wäre bei 225° ...

    Gruß
    Jens

    gn8 😉



  • TTron schrieb:

    Wie würde das denn in C aussehen?

    Hallo Jens,

    der Code, den ich Dir gepostet habe - das soll schon C sein. Dir ist vielleicht aufgefallen, dass er etwas anders aussieht als der von Sunday.

    TTron schrieb:

    Mein Teilkreis(Skala) läuft übrigens von 225° - 315° , d.h. er deckt 270° ab. Null wäre bei 225° ...

    ich unterstelle mal, Du meinst 225° im Uhrzeigersinn drehend bis -45°. Wenn Du das später programmierst, benötigst Du einen stetigen Verlauf und keinen Sprung bei 0 auf 360° 😉

    Nehmen wir mal an, es soll ein Wert uu dargestellt werden, der sich zwischen u0u_{0} bei 225° (d.h. 54π\frac{5}{4}\pi) und -45° (d.h. 14π\frac{-1}{4}\pi) bewegt. Dann berechnet sich der Winkel aa aus einer linearen Interpolation zwischen a0a_{0} und a1a_{1}.
    τ=uu0u1u0\tau=\frac{u-u_{0}}{u_{1}-u_{0}}
    a=(1-\tau)\*a_{0}+\tau\*a_{1}
    mit
    a0=54πa_{0}=\frac{5}{4}\pi
    a1=14πa_{1}=\frac{-1}{4}\pi
    und mit u0u_{0} und u1u_{1} gibst Du Deinen Wertebereich vor - z.B. von 0 bis 100.
    So kannst Du für jedes uu den Winkel aa bestimen.

    Gruß
    Werner



  • Guten Morgen, Hallo Werner!

    Das der Code leicht verändert ist, ist mir sehr wohl aufgefallen .. allerdings hatte ich nicht verstanden wie du die Werte übergibst ... hatte das nämlich übersehen 🙄

    Das mit der Skala hast du richtig verstanden. Die Beginnt links unten im 3. Quadranten und wandert dann im Uhrzeigersinn bis zum 4. Quadranten und landet dann bei 315° bzw. -45°.
    Wenn ich allerdings einen Kreisbogen zeichne, dann gebe ich das z.B. so an:

    arc(x,y,315,225,110);
    

    wobei x/y der Bildschirmmittelpunkt ist.

    Auch wenn ich mich jetzt vielleicht lächerlich mache (was mir egal ist, so lange ich es dann doch irgendwann verstehe), noch mal zu deiner Berechnung:

    Wenn ich deine Rechnung richtig verstanden habe, dann gebe ich also mit U0 und U1 den Wertebereich vor. Also entweder von 0-100, oder von 0-270 oder was auch immer. a0 und a1 ist ja immer gleich, aber r ist dann der Radius, bzw. die Länge des Zeigers, das wäre ja auch immer gleich ?? Habe ich jetzt etwas falsch verstanden (davon gehe ich mal aus).😕
    Oder soll dann der Winkel alpha=Degree und r=Distance sein?? u hätte ich dann, weil ich weiß welcher Wert dargestellt wird, darüber kann ich r(Distance) ausrechnen und darüber dann a(Degree)? Die Werte übergebe ich dann in die Funktionen und die stellt dann den Zeiger dar!?
    Falls ich das immer noch falsch verstanden habe, dann hilft wohl nur noch eine kleine Grafik zum Verständnis ... oder ich kann dir einfach nicht folgen
    😞 😞



  • TTron schrieb:

    Auch wenn ich mich jetzt vielleicht lächerlich mache ..

    .. machst Du nicht. Jeder hat mal vorne angefangen etwas zu lernen.

    TTron schrieb:

    Wenn ich deine Rechnung richtig verstanden habe, dann gebe ich also mit U0 und U1 den Wertebereich vor. Also entweder von 0-100, oder von 0-270 oder was auch immer. a0 und a1 ist ja immer gleich, aber r ist dann der Radius, bzw. die Länge des Zeigers, das wäre ja auch immer gleich ?? Habe ich jetzt etwas falsch verstanden

    Du hast nichts falsch verstanden - genauso ist das.

    TTron schrieb:

    😕
    Oder soll dann der Winkel alpha=Degree und r=Distance sein?? u hätte ich dann, weil ich weiß welcher Wert dargestellt wird, darüber kann ich r(Distance) ausrechnen und darüber dann a(Degree)? Die Werte übergebe ich dann in die Funktionen und die stellt dann den Zeiger dar!?
    Falls ich das immer noch falsch verstanden habe, dann hilft wohl nur noch eine kleine Grafik zum Verständnis ... oder ich kann dir einfach nicht folgen
    😞 😞

    Bevor es unscharf wird, nochmal alles zusammen.
    Angenommen dort soll ein Druck dargestellt werden, der z.B. zwischen 0,8bar und 3,3bar liegt. Der Druckwert sei u in diesen Grenzen. Also u0=0,8u_{0}=0,8 und u1=3,3u_{1}=3,3.
    Dann wird zunächst mit
    τ=uu0u1u0\tau=\frac{u-u_{0}}{u_{1}-u_{0}}
    ein - sagen wir mal normierter - Input berechnet. τ\tau liegt immer zwischen 0 und 1. Angenommen u sei 1,3 dann berechnet sich τ\tau für die oben angenommen Druckgrenzwerte zu 0,2.
    Mit diesem Wert geht man jetzt in die nächste Gleichung
    a=(1-\tau)\*a_{0}+\tau\*a_{1}
    wobei a der Winkel ist, der zwischen a0=54πa_{0}=\frac{5}{4}\pi (für 225°) und a1=14πa_{1}=\frac{-1}{4}\pi (für -45°) liegt. Die Grenzwerte für a gebe ich gleich im Bogenmass an, da die sin- und cos-Funktion a auch im Bogenmass benötigen.
    Mit dem τ\tau von z.B. 0,2 (s.o.) ergibt sich dann ein Winkel von 1920π\frac{19}{20}\pi (d.h. 171°).
    Mit diesem a wird jetzt der Endpunkt des Zeigers berechnet (s. Posting von Sunday). Im Code sähe das ungefähr so aus:

    double PI = acos(-1.0);
    double GRAD2RAD = PI/180.0;
    
    void zeige_an( double u ) { /* u sei der physikalische Wert */
        double u0, u1;
        double tau;
        double a, a0, a1;
        double r, x0, y0, x1, y1;
        u0 = 0.8;  /* untere Grenze für u */
        u1 = 3.3;  /* obere Grenze für u */
        tau = (u-u0)/(u1-u0);
        a0 = 225.0 * GRAD2RAD;  /* unterer Anschlag - 225° im Bogenmass */
        a1 = -45.0 * GRAD2RAD;  /* oberer Anschlag - -45° im Bogenmass */
        a = a0*(1.0-tau) + a1*tau;
        x0 = ...;  /* X-Koordinaten für die Zeiger-Achse */
        y0 = ...;  /* Y-         "                       */
        r = ...;   /* Zeiger-Länge */
        x1 = x0 + r * cos( a );   /* siehe Funktion GetPointByDistance */
        y1 = y0 + r * sin( a );
        /* Zeiche Linie von (x0,y0) nach (x1,y1) */
        ???
    }
    

    (ohne Garantie, dass das genau stimmt. Meine C-Kenntnisse entstammen dem letzten Jahrtausend 😃 )

    Noch mal 'ne Frage - in Aussicht zukünftiger Probleme 😉 - welche x- und y-Koordinaten haben Deine obere linke und die untere rechte Ecke Deines Zeichenbereichs?
    Oder anders gefragt - wird der Y-Wert nach unten hin größer?

    Gruß
    Werner



  • Hallo und danke schon mal für deine Geduld, so langsam wirds heller 😉

    Das es ein Tau ist, konnte ich leider nicht erkennen, ich hatte das für ein kleines r gehalten. 😞
    Ich werde mich leider erst am Montag weiter mit der Aufgabe beschäftigen können, da ich das ganze WE unterwegs sein werde. Ich hoffe ich kann dann noch mal auf deine Hilfe zählen!?

    Meine Anzeigefläche hat oben links den Wert 0/0 und unten rechts 639/479.
    meinx/y habe ich folgender Maßen definiert:

    x=(getmaxx()+1)/2;
     y=(getmaxy()+1)/2;
    

    Vielleicht könntest du schon mal vorab hier zu etwas sagen:

    Point->x
    

    Was genau bewirkt der Pfeil??

    Gruß
    Jens



  • Hallo,

    TTron schrieb:

    Point->x
    

    Was genau bewirkt der Pfeil??

    es handelt sich um einen C/C++-Operator, der geschaffen wurde, um den Elementzugriff

    (*Point).x
    

    bequemer schreiben zu können.

    MfG



  • TTron schrieb:

    Hallo und danke schon mal für deine Geduld, so langsam
    wirds heller 😉

    Hallo Jens,

    das freut mich 🙂 .

    TTron schrieb:

    Meine Anzeigefläche hat oben links den Wert 0/0 und unten rechts 639/479.
    meinx/y habe ich folgender Maßen definiert:

    x=(getmaxx()+1)/2;
     y=(getmaxy()+1)/2;
    

    Ich unterstelle mal, dass Dir die Funktionen getmaxx/y die beiden Werte
    639/479 liefern und x/y der Mittelpunkt Deines Anzeigegeräts sein soll.

    Der Y-Wert wird also nach unten größer. Hmm .. dann gibt es noch ein
    weiteren Aspekt zu berücksichtigen. Deine Zeichenfläche steht also auf
    dem Kopf 🙄 . Alle bisher von mir gemachten Annahmen
    gehen von einem 'klassische' mathematischen Koordinatensystem aus.
    Die saubere Lösung wäre noch mal eine Abbildung von x/y aus z.B. der
    Funktion zeige_an in ein x/y Deines Zeichenbereichs. Aber ich will es
    Dir nicht schwerer machen als notwendig. Es reicht, die Zeile

    y1 = y0 + r * sin( a );
    

    aus meinem Posting nach

    y1 = y0 - r * sin( a );
    

    zu ändern.
    Genau wie es Sunday ursprünglich vorgeschlagen hat.
    Damit spiegelst Du die Y-Achse quasi wieder zurück. Wenn Du nichts anderes
    zeichnest als genau ein Anzeige-Gerät und Du die Skala mit den Zahlen
    ohnehin bereits hast, soll das hier reichen.

    TTron schrieb:

    Vielleicht könntest du schon mal vorab hier zu etwas sagen:

    Point->x
    

    Was genau bewirkt der Pfeil??

    Die ürsprüngliche Idee von Sunday und mir war, dass es eine Struktur
    Point2D gibt

    struct Point2D
    {
        double x;
        double y;
    };
    

    die einen Punkt auf dem Zeichenbereich beschreibt. Mit folgender
    Konstruktion

    Point2D punkt;
        GetPointByDistance( &punkt, winkel, radius );
    

    übergibt man einen Zeiger auf die Variable 'punkt' und innerhalb der
    Funktion kann man dann mit diesem Zeiger

    void GetPointByDistance( Point2D* Point, double winkel, double radius )
    {
        Point->x = ... usw.
    

    die Member der Struktur ändern oder lesen.

    Gruß
    Werner



  • Hallo Werner und Sunday,

    vielen Dank für eure Hilfe. So wie es aussieht scheint es nun zu klappen. Ich mußte noch ein paar kleine Veränderungen vor nehmen, aber nun gehts 🙂 🙂

    Merkwürdigerweise mußte ich die Winkel anpassen und unten sin und cos ändern.
    Als Wert für u habe ich erst mal ein wenig getestet und deshalb die eine Zeile da eingebaut, da die Übergabefunktion der eigentlichen Meßwerte noch nicht steht.

    void zeige_an( double u ) 		      /* u sei der physikalische Wert */
    {
    	u=5.0;                              /* Beispielwert 5 */
    	u0 = 0.0; 					/* untere Grenze fuer u */
    	u1 = 10.0; 					/* obere Grenze fuer u */
    	tau = (u-u0)/(u1-u0);
    	a0 = 315.0 * GRAD2RAD;   		/* unterer Anschlag  225ø im Bogenmass */
    	a1 = 45.0 * GRAD2RAD;   		/* oberer Anschlag  -45ø im Bogenmass */
       	a = a0*(1.0-tau) + a1*tau; 
    	x0 = x; 					/* X-Koordinaten fuer die Zeiger-Achse */
    	y0 = y; 					/* Y-         "                       */
    	r = 130;  					/* Zeiger-Laenge */
    	x1 = x0 + r * sin( a );  		/* Neuberechnung der Punkte */
    	y1 = y0 + r * cos( a );
       	line(x0,y0,x1,y1);	            /* Zeiche Linie von (x0,y0) nach (x1,y1) */
    }
    


  • Oh, man sollte doch zwischendurch mal aktualisieren .. sorry, hatte die Seite seit heute morgen offen und nach dem Frühstück nicht mehr aktualisiert.
    Werde gleich ebenalls noch mal deinen Ansatz mit deiner Änderung der Formel testen.

    Gruß
    Jens



  • So, jetzt habe ich mich mal registriert, damit ich auch mal meine Postings editieren kann. Deine Änderung funktioniert natürlich auch !! und da sie so für mich einfacher nachzuvollziehen ist, lasse ich sie so.
    Jetzt muß ich nur noch eine Funktion zum Einlesen der Daten an der Schnittstelle basteln und dann das Umsetzen der Daten in die benötigten Werte für u, aber das bekomme ich allein hin.



  • TTron schrieb:

    .. aber nun gehts 🙂 🙂

    Merkwürdigerweise mußte ich die Winkel anpassen und unten sin und cos ändern.

    Hey Wahnsinn 😃
    Das ist es ..

    ^Y
              |
            - | -
          /   |   \
    ----------+-----------> X
          \ / | \ V
           /  |  \
          /   |   \
              |
    

    .. was Du wolltest. Mit Deiner "Winkelanpassung"

    a0 = 315.0 * GRAD2RAD;   		/* unterer Anschlag  225ø im Bogenmass */
    	a1 = 45.0 * GRAD2RAD;   		/* oberer Anschlag  -45ø im */
    

    drehst Du die Skala um 90 Grad - also

    ^Y
              |   /
            - |->/
          /   | /
    ----------+-----------> X
          \   | \
            - |  \
              |   \
              |
    

    Damit

    x1 = x0 + r * sin( a );  		/* Neuberechnung der Punkte */
    	y1 = y0 + r * cos( a );
    

    vertauscht Du lokal x und y; das entspricht einer Spiegelung um die 45°-Diagonale - also

    ^Y
          \   |   /
           \  |  /
          / \ | / ^
    ----------+-----------> X
          \   |   /
            - | - 
              |
              |
    

    und weil im Zeichenbereich die Y-Achse nach unten zeigt erhält man dann am Schluß durch eine Spiegelung an der X-Achse:

    |
              |
            - | -
          /   |   \
    ----------+-----------> X
          \ / | \ V
           /  |  \
          /   |   \
              vY
    

    .. wie durch Zauberhand das gewünschte Bild.

    Auch wenn ein Programm am Ende das tut, was am Anfang gewünscht war, so muss es nicht korrekt sein. Source-Code dient nicht nur der Kommunikation mit dem Rechner sondern auch mit Menschen. D.h. Menschen - also zu aller erst Du - sollten ihn lesen und verstehen können. Wenn ein unbefangener Leser z.B. auf Zeilen wie

    a0 = 315.0 * GRAD2RAD;   		/* unterer Anschlag  225ø im Bogenmass */
    	a1 = 45.0 * GRAD2RAD;   		/* oberer Anschlag  -45ø */
    

    trifft, so wird er sich fragen, ob der Winkel jetzt 315° oder 225° sein soll. Was ist hier richtig?

    Schreibe nie Code, den Du nicht verstehst.

    Alles andere ist 'try and error'. Das schreibt Dir jemand, der täglich mit den Auswirkungen dergleichen zu tun hat. Bei 1o Zeilen mag das ja noch lustig sein, aber bei mehreren 1000 Zeilen Kot .....

    In diesem Sinne - lerne weiter und hab' Spaß daran 😉
    und viel Erfolg wünscht Dir
    Werner



  • Huhu,

    danke noch mal für die Erläuterung. Hatte ja schon geschrieben das mir die "Try and Error Variante" eh nicht so zugesagt hat, da ich es nicht so ohne weiteres hätte erklären können 😉

    Das mit der Zeichenfläche ist nun mal so wenn ich den Grafikmodus ohne irgendwelche Zusatzoptionen aktiviere. Natürlich könnte ich das anders handhaben, war aber so erst mal am einfachsten.

    Mit den Funktionen getmaxx und getmaxy liegst du richtig. Man hätte auch feste Punkte mit Werten eingeben können, aber so konnte ich ein wenig mit der Funktion rum probieren 😉

    Danke noch mal für den Hinweis mit dem "schreibe nie ..." , werde mir Mühe geben und mich daran halten. 🙂


Anmelden zum Antworten