11 Stimmen

Wie kann man die Koordinaten einer Pfeilspitze anhand des Pfeils berechnen?

Ich habe eine Linie, die auf zwei mir bekannten (x,y) Koordinaten basiert. Diese Linie hat einen Anfangs- und einen Endpunkt. Jetzt möchte ich eine Pfeilspitze am Endpunkt der Linie hinzufügen.

Ich weiß, dass der Pfeil ein gleichseitiges Dreieck ist und daher jeder Winkel 60 Grad hat. Außerdem kenne ich die Länge einer Seite, die 20 beträgt. Ich kenne auch keine Kante des Dreiecks (das ist der Endpunkt der Linie).

Wie kann ich die beiden anderen Punkte des Dreiecks berechnen? Ich weiß, dass ich etwas Trigonometrie verwenden sollte, aber wie?

P.s. Der Endpunkt der Linie sollte die Spitze der Pfeilspitze sein.

11voto

Marcelo Cantos Punkte 173498

Man braucht keine Trigonometrie, nur etwas Vektorarithmetik...

Nehmen wir an, die Linie geht von A nach B, wobei der vordere Scheitelpunkt der Pfeilspitze bei B liegt. Die Länge der Pfeilspitze ist h = 10(3) und ihre halbe Breite ist w = 10. Wir bezeichnen den Einheitsvektor von A nach B als U = (B - A)/|B - A| (d.h. die Differenz geteilt durch die Länge der Differenz), und den Einheitsvektor senkrecht dazu als V = [-U y , U x ].

Aus diesen Größen kann man die beiden hinteren Eckpunkte der Pfeilspitze als B - hU ± wV berechnen.

In C++:

struct vec { float x, y; /* … */ };

void arrowhead(vec A, vec B, vec& v1, vec& v2) {
    float h = 10*sqrtf(3), w = 10;
    vec U = (B - A)/(B - A).length();
    vec V = vec(-U.y, U.x);
    v1 = B - h*U + w*V;
    v2 = B - h*U - w*V;
}

Wenn Sie verschiedene Winkel angeben wollen, brauchen Sie etwas Trigonometrie, um die verschiedenen Werte von h y w . Angenommen, Sie wollen eine Pfeilspitze der Länge h und des Spitzenwinkels , dann ist w = h tan(/2). In der Praxis ist es jedoch am einfachsten, Folgendes anzugeben h y w direkt.

10voto

Lasse V. Karlsen Punkte 364542

Hier ist ein Beispiel LINQPad Programm, das zeigt, wie man das macht:

void Main()
{
    const int imageWidth = 512;
    Bitmap b = new Bitmap(imageWidth , imageWidth , PixelFormat.Format24bppRgb);

    Random r = new Random();
    for (int index = 0; index < 10; index++)
    {
        Point fromPoint = new Point(0, 0);
        Point toPoint = new Point(0, 0);

        // Ensure we actually have a line
        while (fromPoint == toPoint)
        {
            fromPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
            toPoint = new Point(r.Next(imageWidth ), r.Next(imageWidth ));
        }

        // dx,dy = arrow line vector
        var dx = toPoint.X - fromPoint.X;
        var dy = toPoint.Y - fromPoint.Y;

        // normalize
        var length = Math.Sqrt(dx * dx + dy * dy);
        var unitDx = dx / length;
        var unitDy = dy / length;

        // increase this to get a larger arrow head
        const int arrowHeadBoxSize = 10;

        var arrowPoint1 = new Point(
            Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize - unitDy * arrowHeadBoxSize),
            Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize + unitDx * arrowHeadBoxSize));
        var arrowPoint2 = new Point(
            Convert.ToInt32(toPoint.X - unitDx * arrowHeadBoxSize + unitDy * arrowHeadBoxSize),
            Convert.ToInt32(toPoint.Y - unitDy * arrowHeadBoxSize - unitDx * arrowHeadBoxSize));

        using (Graphics g = Graphics.FromImage(b))
        {
            if (index == 0)
                g.Clear(Color.White);

            g.DrawLine(Pens.Black, fromPoint, toPoint);
            g.DrawLine(Pens.Black, toPoint, arrowPoint1);
            g.DrawLine(Pens.Black, toPoint, arrowPoint2);
        }
    }

    using (var stream = new MemoryStream())
    {
        b.Save(stream, ImageFormat.Png);
        Util.Image(stream.ToArray()).Dump();
    }
}

Im Grunde genommen, Sie:

  1. Berechnen Sie den Vektor der Pfeillinie
  2. Normalisieren des Vektors, d.h. seine Länge auf 1 setzen
  3. Berechnen Sie die Enden der Pfeilspitzen, indem Sie gehen:
    1. Zuerst eine gewisse Entfernung vom Kopf zurück
    2. Dann senkrecht von der Linie aus eine bestimmte Entfernung

Wenn Sie möchten, dass die Pfeilspitzen einen anderen Winkel als 45 Grad haben, müssen Sie eine andere Methode anwenden.

Das obige Programm zeichnet jedes Mal 10 zufällige Pfeile, hier ist ein Beispiel:

arrow example

3voto

MBo Punkte 74571

Ihr Text lautet (x0,y0)-(x1,y1)

Rückwärtsgerichteter Vektor (dx, dy) = (x0-x1, y0-y1)

Das ist die Norm Norm = Sqrt(dx*dx+dy*dy)

Normalisieren Sie es: (udx, udy) = (dx/Norm, dy/Norm)

Drehen nach Winkeln Pi/6 y -Pi/6

ax = udx * Sqrt(3)/2 - udy * 1/2

ay = udx * 1/2 + udy * Sqrt(3)/2

bx = udx * Sqrt(3)/2 + udy * 1/2

by =  - udx * 1/2 + udy * Sqrt(3)/2

Ihre Punkte: (x1 + 20 * ax, y1 + 20 * ay) y (x1 + 20 * bx, y1 + 20 * by)

2voto

Patratacus Punkte 1549

Ich möchte meine Antwort in C# auf der Grundlage der Antwort von Marcelo Cantos beitragen, da der Algorithmus wirklich gut funktioniert. Ich habe ein Programm geschrieben, um den Schwerpunkt eines Laserstrahls zu berechnen, der auf ein CCD-Array projiziert wird. Nachdem der Schwerpunkt gefunden wurde, wird die Richtungs-Winkel-Linie gezeichnet und ich brauche die Pfeilspitze, die in diese Richtung zeigt. Da der Winkel berechnet wird, müsste die Pfeilspitze dem Winkel in jeder beliebigen Richtung folgen.

Length = 10, Half-Width = 10

Length = 20, Half-Width = 10

enter image description here

Mit diesem Code können Sie die Größe der Pfeilspitze flexibel ändern, wie in den Abbildungen gezeigt.

Zunächst benötigen Sie die Vektorstruktur mit allen erforderlichen Überladungen der Operatoren.

private struct vec
{
    public float x;
    public float y;

    public vec(float x, float y)
    {
        this.x = x;
        this.y = y;
    }

    public static vec operator -(vec v1, vec v2)
    {
        return new vec(v1.x - v2.x, v1.y - v2.y);
    }

    public static vec operator +(vec v1, vec v2)
    {
        return new vec(v1.x + v2.x, v1.y + v2.y);
    }

    public static vec operator /(vec v1, float number)
    {
        return new vec(v1.x / number, v1.y / number);
    }

    public static vec operator *(vec v1, float number)
    {
        return new vec(v1.x * number, v1.y * number);
    }

    public static vec operator *(float number, vec v1)
    {
        return new vec(v1.x * number, v1.y * number);
    }

    public float length()
    {
        double distance;
        distance = (this.x * this.x) + (this.y * this.y);
        return (float)Math.Sqrt(distance);
    }
}

Dann kannst du den gleichen Code wie Marcelo Cantos verwenden, aber ich habe die Länge und die halbe Breite der Pfeilspitze zu Variablen gemacht, damit du sie beim Aufruf der Funktion definieren kannst.

private void arrowhead(float length, float half_width, 
                       vec A, vec B, ref vec v1, ref vec v2)
{
    float h = length * (float)Math.Sqrt(3);
    float w = half_width;
    vec U = (B - A) / (B - A).length();
    vec V = new vec(-U.y, U.x);
    v1 = B - h * U + w * V;
    v2 = B - h * U - w * V;

}

Jetzt können Sie die Funktion wie folgt aufrufen:

vec leftArrowHead = new vec();
vec rightArrowHead = new vec();
arrowhead(20, 10, new vec(circle_center_x, circle_center_y), 
    new vec(x_centroid_pixel, y_centroid_pixel),
    ref leftArrowHead, ref rightArrowHead);

In meinem Code ist der Kreismittelpunkt die erste Vektorposition (Pfeilspitze), und der centroid_pixel ist die zweite Vektorposition (Pfeilspitze).

Ich zeichne die Pfeilspitze, indem ich die Vektorwerte in den Punkten für die Funktion graphics.DrawPolygon() in der Datei System.Drawings. Der Code wird unten gezeigt:

Point[] ppts = new Point[3];
ppts[0] = new Point((int)leftArrowHead.x, (int)leftArrowHead.y);
ppts[1] = new Point(x_cm_pixel,y_cm_pixel);
ppts[2] = new Point((int)rightArrowHead.x, (int)rightArrowHead.y);

g2.DrawPolygon(p, ppts);

1voto

Denis Ermolin Punkte 5448

Sie können den Winkel der Linie ermitteln.

Vector ox = Vector(1,0);
Vector line_direction = Vector(line_begin.x - line_end.x, line_begin.y - line_end.y);
line_direction.normalize();
float angle = acos(ox.x * line_direction.x + line_direction.y * ox.y);

Verwenden Sie diese Funktion dann für alle 3 Punkte mit dem gefundenen Winkel.

Point rotate(Point point, float angle)
{
    Point rotated_point;
    rotated_point.x = point.x * cos(angle) - point.y * sin(angle);
    rotated_point.y = point.x * sin(angle) + point.y * cos(angle);
    return rotated_point;
}

Unter der Annahme, dass der obere Punkt der Pfeilspitze das Ende der Linie ist, wird er perfekt gedreht und an die Linie angepasst. Ich habe es nicht getestet =(

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X