Linie mit Pfeilende zeichnen (Formel)



  • @SeppJ Vielen Dank. Ich denke, er suchte eine textuelle Beschreibung - und keinen Pseudocode ...

    Allerdings würde ich die Vektoren Stütz-/Auf- und Richtungsvektoren nennen.



  • So danke euch für die Erklärungen, im Grunde habe ich auch an Vektorrechnung gedacht, habe aber Auffrischungsbedarf ^^

    Anbei zwei Links zu den Bildern:

    3 Vektoren mit Pfeilspitze

    Herleitung Formel

    Der Vektor b (in der Herleitung) ist das Ergebnis.

    Allerdings scheint mir die Herleitung nur für den Vektor a zu funktionieren, nicht aber für die anderen beiden. Wäre super wenn ihr mich da korrigieren könntet.



  • In welchen Kontext brauchst du das denn? Schule, Lineare Algebra-Vorlesung, ...?



  • @Fragender

    Rein privates Hobby, ist Aufgabe 3 aus Kapitel 13 von dem Programmierbuch von Stroustrup (Programming Principles). Ich will das einfach hinbekommen.

    Ernüchterndes Ergebnis

    ...sehr ernüchternd, die oberen beiden Linien sind zwar nicht ganz korrekt aber sehen nicht so schlecht aus, bei den beiden unteren ist der Pfeil verkehrt herum.

    Und hier der Code:

            Arrow a1{ Point{200,200}, Point{300,200} };
    	Arrow a2{ Point{200,200}, Point{300,100} };
    	Arrow a3{ Point{200,300}, Point{100,300} };
    	Arrow a4{ Point{200,300}, Point{100,400} };
    
    void Arrow::draw_lines() const
    {
    	double angle{ 45 };		// Winkel des Pfeils zur Linie
    	double length{ 20 };	// Länge des Pfeils
    	
    	// Winkel zwischen der Linie und der X-Achse
    	double alpha{ atan(static_cast<double>(p2.y - p1.y) / static_cast<double>(p2.x - p1.x)) };
    	double phi{ 90.0 - alpha - angle };		// Hilfswinkel: zwischen Pfeil und y-Achse
    
    	// Koordinaten für Pfeillinien (obere Seite) 
    	double px1{ p2.x - length * sin(phi) };
    	double py1{ p2.y - length * cos(phi)};
    
    	// Koordinaten für Pfeillinien (untere Seite)
    	double px2{ p2.x - length * cos(-phi) };
    	double py2{ p2.y - length * sin(-phi) };
    
    	// Normale Linie zeichnen
    	fl_line(p1.x, p1.y, p2.x, p2.y);
    	
    	// Pfeile oben/unten zeichnen
    	fl_line(p2.x, p2.y, px1, py1);
    	fl_line(p2.x, p2.y, px2, py2);
    }
    

  • Mod

    Du denkst schon dran, dass trigonometrische Funktionen in C++ (und so ziemlich bei jedem Kontext außerhalb der Schule) im Bogenmaß rechnen?

    Ansonsten würde ich meine Methode empfehlen. Was soll die x-Achse und der Winkel zu dieser mit dem Problem zu tun haben? Du willst doch einzig und alleine die Linie einmal um +phi und einmal um -phi drehen. Nix mit Achsen.



  • @sirEgbert Ich hatte dir doch schon Pseudocode bzw. Java-Code gezeigt. Ich glaube nicht, dass dieser noch weiter vereinfacht werden könnte...

    package org.example;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.geom.Point2D;
    import java.util.Scanner;
    
    public class Arrows {
        public static Point2D add(Point2D a, Point2D b) {
            return new Point2D.Double(a.getX() + b.getX(), a.getY() + b.getY());
        }
    
        public static Point2D subtract(Point2D a, Point2D b) {
            return new Point2D.Double(a.getX() - b.getX(), a.getY() - b.getY());
        }
    
        public static Point2D multiply(Point2D a, double d) {
            return new Point2D.Double(a.getX() * d, a.getY() * d);
        }
    
        public static Point2D rotateDegrees(Point2D a, double deg) {
            final double rad = Math.toRadians(deg);
            return new Point2D.Double(a.getX() * Math.cos(rad) - a.getY() * Math.sin(rad),
                    a.getX() * Math.sin(rad) + a.getY() * Math.cos(rad));
        }
    
        public static void drawArrow(Point2D start, Point2D end2, Point2D a, Point2D b, Point2D c) {
            JFrame frame = new JFrame();
            JPanel panel = new JPanel() {
                private void drawLine(Graphics g, Point2D a, Point2D b) {
                    g.drawLine((int) a.getX(), (int) a.getY(), (int) b.getX(), (int) b.getY());
                }
                @Override
                public void paint(Graphics g) {
                    drawLine(g, start, end2);
                    drawLine(g, a, b);
                    drawLine(g, b, c);
                    drawLine(g, c, a);
                }
            };
            frame.add(panel);
            frame.setSize(400, 400);
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            System.out.println("Gib den Startpunkt und den Endpunkt (Pfeilspitze) ein:");
            String[] sa = new Scanner(System.in).nextLine().split(",? ");
            Point2D start = new Point2D.Double(Double.parseDouble(sa[0]), Double.parseDouble(sa[1]));
            Point2D end = new Point2D.Double(Double.parseDouble(sa[2]), Double.parseDouble(sa[3]));
            Point2D startEnd = subtract(end, start);
            Point2D end2 = add(start, multiply(startEnd, 0.9));
            System.out.println("Zeichne eine Linie von " + start + " bis " + end2);
            Point2D a = add(end2, multiply(rotateDegrees(startEnd, 90), 0.06));
            Point2D b = add(end2, multiply(rotateDegrees(startEnd, 270), 0.06));
            Point2D c = end;
            System.out.println("Zeichne eine Linie von " + a + " bis " + b);
            System.out.println("Zeichne eine Linie von " + b + " bis " + c);
            System.out.println("Zeichne eine Linie von " + c + " bis " + a);
            drawArrow(start, end2, a, b, c);
        }
    }
    

    https://i.postimg.cc/fTsGJdZ6/grafik.png



  • Ja, ok ... bei den Punkten a und b könntest du auch zuerst multiplizieren, dann drehen, und schließlich addieren. Da geht es aber schon Richtung Mikrooptimierung.



  • @sirEgbert
    Nur zur Info: du musst um die Pfeilspitze zu zeichnen den Winkel des Schafts nicht bestimmen. Du kannst einfach den Schaft-Vektor auf die gewünschte Länge bringen, und dann mit einer passenden Matrix multiplizieren um ihn um den gewünschten Winkel zu drehen: https://en.wikipedia.org/wiki/Rotation_matrix

    Der Vorteil davon ist dass du den Sonderfall p2.x == p1.x nicht mehr extra behandeln musst. (Abgesehen davon kannst du die Matritzen auch vorberechnen, was das ganze schneller macht, da du dann überhaupt keine Winkelfunktionen zur Laufzeit mehr brauchst. Wobei das vermutlich in den meisten Programmen keine Rolle spielt.)



  • @hustbaer sagte in Linie mit Pfeilende zeichnen (Formel):

    (Abgesehen davon kannst du die Matritzen auch vorberechnen, was das ganze schneller macht, da du dann überhaupt keine Winkelfunktionen zur Laufzeit mehr brauchst. Wobei das vermutlich in den meisten Programmen keine Rolle spielt.)

    Das geht aufgrund der Kommutativität der Matrizenmultiplikationen tatsächlich erstaunlich gut. Das durfte ich auch für 3d in einer Klausur berechnen/aufstellen. 🙂

    Allerdings braucht er dann hier 5 Matrizen für den kompletten Pfeil ... oder? Jap, so ist es.

    @hustbaer Auch die trigonometrischen Funktionen (sin, cos, usw.) sind inzwischen "vorberechnet"/gemappt. 🙂 Fallen also kaum noch ins Gewicht. Aber das wusstest du sicher schon... 😉



  • Oups... die sind natürlich nicht kommutativ, können aber dennoch wie ganz richtig beschrieben schön zusammengefasst werden.


Anmelden zum Antworten