it-swarm.com.de

Wie berechnet man einen Winkel aus drei Punkten?

Sagen wir, Sie haben folgendes:

P1 = (x=2, y=50)
P2 = (x=9, y=40)
P3 = (x=5, y=20)

Nehmen Sie an, dass P1 der Mittelpunkt eines Kreises ist. Es ist immer derselbe . Ich möchte den Winkel, der aus P2 und P3 besteht, oder mit anderen Worten den Winkel, der neben P1 liegt. Der innere Winkel um genau zu sein. Es wird immer ein spitzer Winkel sein, also weniger als -90 Grad.

Ich dachte: Mann, das ist einfache Geometriemathematik. Aber ich habe seit ungefähr 6 Stunden nach einer Formel gesucht und finde nur Leute, die über komplizierte NASA-Sachen wie Arccos und Vektorskalarprodukt sprechen. Mein Kopf fühlt sich an wie in einem Kühlschrank.

Einige mathematische Gurus glauben, dass dies ein einfaches Problem ist? Ich denke nicht, dass die Programmiersprache hier von Bedeutung ist, aber für diejenigen, die glauben, dass sie es tun: Java und Objective-c. Ich brauche es für beide, habe es aber noch nicht markiert.

120
HelloMoon

Wenn Sie den Winkel meinen, dass P1 der Scheitelpunkt ist, dann sollte das Law of Cosines funktionieren:

arccos((P122 + P132 - P232)/(2 * P12 * P13))

wo P12 ist die Länge des Segments von P1 bis P2, berechnet mit

sqrt ((P1x - P2x)2 + (P1y - P2y)2)

87
Lance Roberts

Es wird sehr einfach, wenn Sie es als zwei Vektoren betrachten, einen von Punkt P1 bis P2 und einen von P1 bis P3 

so:
a = (p1.x - p2.x, p1.y - p2.y)
b = (p1.x - p3.x, p1.y - p3.y)

Sie können dann die Punktproduktformel umkehren:
dot product
, um den Winkel zu erhalten:
angle between two vectors

Erinnere dich daran dot product bedeutet nur: a1 * b1 + a2 * b2 (hier nur 2 Dimensionen ...)

47
Andrea Ambu

Die beste Methode zur Behandlung von Winkeln ist die Verwendung von atan2(y, x), die bei Angabe eines Punktes x, y den Winkel von diesem Punkt und die X+-Achse in Bezug auf den Ursprung zurückgibt.

Angenommen, die Berechnung ist

double result = atan2(P3.y - P1.y, P3.x - P1.x) -
                atan2(P2.y - P1.y, P2.x - P1.x);

das heißt, Sie übersetzen die beiden Punkte grundsätzlich mit -P1 (dh Sie übersetzen alles so, dass P1 im Ursprung endet) und berücksichtigen dann die Differenz der absoluten Winkel von P3 und von P2.

Die Vorteile von atan2 bestehen darin, dass der vollständige Kreis dargestellt wird (Sie können eine beliebige Zahl zwischen -π und π erhalten), wobei stattdessen mit acos mehrere Fälle behandelt werden müssen, abhängig von den Vorzeichen, um das korrekte Ergebnis zu berechnen.

Der einzige singuläre Punkt für atan2 ist (0, 0)..., was bedeutet, dass sich P2 und P3 von P1 unterscheiden müssen, da es in diesem Fall nicht sinnvoll ist, über einen Winkel zu sprechen.

25
6502

Lassen Sie mich in JavaScript ein Beispiel geben, damit habe ich viel gekämpft:

/**
 * Calculates the angle (in radians) between two vectors pointing outward from one center
 *
 * @param p0 first point
 * @param p1 second point
 * @param c center point
 */
function find_angle(p0,p1,c) {
    var p0c = Math.sqrt(Math.pow(c.x-p0.x,2)+
                        Math.pow(c.y-p0.y,2)); // p0->c (b)   
    var p1c = Math.sqrt(Math.pow(c.x-p1.x,2)+
                        Math.pow(c.y-p1.y,2)); // p1->c (a)
    var p0p1 = Math.sqrt(Math.pow(p1.x-p0.x,2)+
                         Math.pow(p1.y-p0.y,2)); // p0->p1 (c)
    return Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c));
}

Bonus: Beispiel mit HTML5-Canvas

19
shaman.sir

Grundsätzlich haben Sie zwei Vektoren, einen Vektor von P1 nach P2 und einen anderen von P1 nach P3. Sie benötigen also lediglich eine Formel zur Berechnung des Winkels zwischen zwei Vektoren.

Schauen Sie sich here für eine gute Erklärung und die Formel an.

alt text

15
Andre Miller

Wenn Sie P1 als Zentrum eines Kreises betrachten, denken Sie zu kompliziert. Sie haben ein einfaches Dreieck, so dass Ihr Problem mit dem Gesetz der Cosinus lösbar ist. Keine Notwendigkeit einer Polarkoordinatentransformation oder irgendetwas. Angenommen, die Abstände sind P1-P2 = A, P2-P3 = B und P3-P1 = C:

Winkel = Arkos ((B ^ 2-A ^ 2-C ^ 2)/2AC)

Alles, was Sie tun müssen, ist die Länge der Entfernungen A, B und C .. zu berechnen .. Diese sind leicht aus den x- und y-Koordinaten Ihrer Punkte und dem Satz von Pythagoras

Länge = Quadrat ((X2-X1) ^ 2 + (Y2-Y1) ^ 2)

12
Treb

Ich hatte kürzlich ein ähnliches Problem, nur ich musste zwischen einem positiven und einem negativen Winkel unterscheiden. Falls dies für alle von Nutzen ist, empfehle ich das Code-Snippet, das ich von dieser Mailing-Liste über das Erkennen der Rotation über ein Berührungsereignis für Android ergriffen habe:

 @Override
 public boolean onTouchEvent(MotionEvent e) {
    float x = e.getX();
    float y = e.getY();
    switch (e.getAction()) {
    case MotionEvent.ACTION_MOVE:
       //find an approximate angle between them.

       float dx = x-cx;
       float dy = y-cy;
       double a=Math.atan2(dy,dx);

       float dpx= mPreviousX-cx;
       float dpy= mPreviousY-cy;
       double b=Math.atan2(dpy, dpx);

       double diff  = a-b;
       this.bearing -= Math.toDegrees(diff);
       this.invalidate();
    }
    mPreviousX = x;
    mPreviousY = y;
    return true;
 }
8
Marc

Sehr einfache geometrische Lösung mit Erläuterung

Vor ein paar Tagen fiel a auf dasselbe Problem und musste mit dem Mathematikbuch sitzen. Ich löste das Problem, indem ich einige grundlegende Formeln kombinierte und vereinfachte.


Betrachten wir diese Zahl

 angle

Wir wollen ϴ wissen, also müssen wir zuerst α und β herausfinden. Nun, für jede gerade Linie 

y = m * x + c

Sei - A = (ax, ay), B = (bx, by) und O = (ox, oy). Also für die Zeile OA -

oy = m1 * ox + c   ⇒ c = oy - m1 * ox   ...(eqn-1)

ay = m1 * ax + c   ⇒ ay = m1 * ax + oy - m1 * ox   [from eqn-1]
                   ⇒ ay = m1 * ax + oy - m1 * ox
                   ⇒ m1 = (ay - oy) / (ax - ox)
                   ⇒ tan α = (ay - oy) / (ax - ox)   [m = slope = tan ϴ]   ...(eqn-2)

Ebenso für Zeile OB -

tan β = (by - oy) / (bx - ox)   ...(eqn-3)

Nun brauchen wir ϴ = β - α. In der Trigonometrie haben wir eine Formel

tan (β-α) = (tan β + tan α) / (1 - tan β * tan α)   ...(eqn-4)

Nachdem wir den Wert von tan α (aus Gleichung 2) und tan b (aus Gleichung 3) in Gleichung 4 ersetzt und die Vereinfachung angewendet haben, erhalten wir

tan (β-α) = ( (ax-ox)*(by-oy)+(ay-oy)*(bx-ox) ) / ( (ax-ox)*(bx-ox)-(ay-oy)*(by-oy) )

So,

ϴ = β-α = tan^(-1) ( ((ax-ox)*(by-oy)+(ay-oy)*(bx-ox)) / ((ax-ox)*(bx-ox)-(ay-oy)*(by-oy)) )

Das ist es! 


Nehmen Sie nun folgende Abbildung

 angle

Diese C # - oder Java-Methode berechnet den Winkel (ϴ) -

    private double calculateAngle(double P1X, double P1Y, double P2X, double P2Y,
            double P3X, double P3Y){

        double numerator = P2Y*(P1X-P3X) + P1Y*(P3X-P2X) + P3Y*(P2X-P1X);
        double denominator = (P2X-P1X)*(P1X-P3X) + (P2Y-P1Y)*(P1Y-P3Y);
        double ratio = numerator/denominator;

        double angleRad = Math.Atan(ratio);
        double angleDeg = (angleRad*180)/Math.PI;

        if(angleDeg<0){
            angleDeg = 180+angleDeg;
        }

        return angleDeg;
    }
7
Minhas Kamal

In Objective-C können Sie dies mit tun

float xpoint = (((atan2((newPoint.x - oldPoint.x) , (newPoint.y - oldPoint.y)))*180)/M_PI);

Oder lesen Sie mehr hier

Sie haben einen vorzeichenbehafteten Winkel (-90) erwähnt. In vielen Anwendungen können Winkel Zeichen haben (positiv und negativ, siehe http://en.wikipedia.org/wiki/Angle ). Wenn die Punkte beispielsweise P2 (1,0), P1 (0,0), P3 (0,1) sind, ist der Winkel P3-P1-P2 herkömmlich positiv (PI/2), während der Winkel P2-P1- P3 ist negativ. Bei Verwendung der Längen der Seiten wird nicht zwischen + und - unterschieden. Wenn dies wichtig ist, müssen Sie Vektoren oder eine Funktion wie Math.atan2 (a, b) verwenden.

Winkel können auch über 2 * PI hinausgehen, und obwohl dies für die aktuelle Frage nicht relevant ist, war es ausreichend wichtig, dass ich meine eigene Winkelklasse schrieb (auch um sicherzustellen, dass Grad und Radiant nicht gemischt werden). Die Frage, ob Winkel1 kleiner als Winkel2 ist, hängt entscheidend davon ab, wie Winkel definiert werden. Es kann auch wichtig sein zu entscheiden, ob eine Linie (-1,0) (0,0) (1,0) als Math.PI oder -Math.PI dargestellt wird

4

my angle demo program

In letzter Zeit habe auch ich das gleiche Problem ... In Delphi Es ist dem Objective-C sehr ähnlich.

procedure TForm1.FormPaint(Sender: TObject);
var ARect: TRect;
    AWidth, AHeight: Integer;
    ABasePoint: TPoint;
    AAngle: Extended;
begin
  FCenter := Point(Width div 2, Height div 2);
  AWidth := Width div 4;
  AHeight := Height div 4;
  ABasePoint := Point(FCenter.X+AWidth, FCenter.Y);
  ARect := Rect(Point(FCenter.X - AWidth, FCenter.Y - AHeight),
    Point(FCenter.X + AWidth, FCenter.Y + AHeight));
  AAngle := ArcTan2(ClickPoint.Y-Center.Y, ClickPoint.X-Center.X) * 180 / pi;
  AngleLabel.Caption := Format('Angle is %5.2f', [AAngle]);
  Canvas.Ellipse(ARect);
  Canvas.MoveTo(FCenter.X, FCenter.Y);
  Canvas.LineTo(FClickPoint.X, FClickPoint.Y);
  Canvas.MoveTo(FCenter.X, FCenter.Y);
  Canvas.LineTo(ABasePoint.X, ABasePoint.Y);
end;
4
antonio

Hier ist eine C # -Methode, um den Winkel (0-360) von der Horizontalen für einen Punkt auf einem Kreis entgegen dem Uhrzeigersinn zurückzugeben.

    public static double GetAngle(Point centre, Point point1)
    {
        // Thanks to Dave Hill
        // Turn into a vector (from the Origin)
        double x = point1.X - centre.X;
        double y = point1.Y - centre.Y;
        // Dot product u dot v = mag u * mag v * cos theta
        // Therefore theta = cos -1 ((u dot v) / (mag u * mag v))
        // Horizontal v = (1, 0)
        // therefore theta = cos -1 (u.x / mag u)
        // nb, there are 2 possible angles and if u.y is positive then angle is in first quadrant, negative then second quadrant
        double magnitude = Math.Sqrt(x * x + y * y);
        double angle = 0;
        if(magnitude > 0)
            angle = Math.Acos(x / magnitude);

        angle = angle * 180 / Math.PI;
        if (y < 0)
            angle = 360 - angle;

        return angle;
    }

Prost, Paul

2
Paul

function p(x, y) {return {x,y}}

function normaliseToInteriorAngle(angle) {
	if (angle < 0) {
		angle += (2*Math.PI)
	}
	if (angle > Math.PI) {
		angle = 2*Math.PI - angle
	}
	return angle
}

function angle(p1, center, p2) {
	const transformedP1 = p(p1.x - center.x, p1.y - center.y)
	const transformedP2 = p(p2.x - center.x, p2.y - center.y)

	const angleToP1 = Math.atan2(transformedP1.y, transformedP1.x)
	const angleToP2 = Math.atan2(transformedP2.y, transformedP2.x)

	return normaliseToInteriorAngle(angleToP2 - angleToP1)
}

function toDegrees(radians) {
	return 360 * radians / (2 * Math.PI)
}

console.log(toDegrees(angle(p(-10, 0), p(0, 0), p(0, -10))))

2
Dominic

es gibt IS eine einfache Antwort auf diese Frage mit Hilfe der Mathematik der High School.

Angenommen, Sie haben 3 Punkte

Winkel von Punkt A nach B zu bekommen

angle = atan2(A.x - B.x, B.y - A.y)

Winkel von Punkt B zu C erhalten

angle2 = atan2(B.x - C.x, C.y - B.y)

Answer = 180 + angle2 - angle
If (answer < 0){
    return answer + 360
}else{
    return answer
}

Ich habe diesen Code gerade in dem kürzlich erstellten Projekt verwendet. Ändern Sie das B in P1. Sie können auch das "180 +" entfernen, wenn Sie möchten

0
James Penner