एक रेखा और क्षैतिज अक्ष के बीच के कोण की गणना कैसे करें?


248

एक प्रोग्रामिंग भाषा में (पायथन, सी #, आदि) मुझे यह निर्धारित करने की आवश्यकता है कि एक पंक्ति और क्षैतिज अक्ष के बीच के कोण की गणना कैसे करें?

मुझे लगता है कि एक छवि सबसे अच्छा वर्णन करती है कि मुझे क्या चाहिए:

कोई भी शब्द इसका वर्णन नहीं कर सकता है

दिया गया (P1 x , P1 y ) और (P2 x , P2 y ) इस कोण की गणना करने का सबसे अच्छा तरीका क्या है? मूल उत्थान में है और केवल सकारात्मक चतुर्थांश का उपयोग किया जाता है।


जवाबों:


388

पहले प्रारंभ बिंदु और अंतिम बिंदु के बीच अंतर खोजें (यहां, यह एक निर्देशित रेखा खंड का अधिक है, न कि "लाइन", क्योंकि लाइनें असीम रूप से विस्तारित होती हैं और किसी विशेष बिंदु पर शुरू नहीं होती हैं)।

deltaY = P2_y - P1_y
deltaX = P2_x - P1_x

फिर कोण की गणना करें (जो सकारात्मक X अक्ष से P1सकारात्मक Y अक्ष पर चलती है P1)।

angleInDegrees = arctan(deltaY / deltaX) * 180 / PI

लेकिन arctanआदर्श नहीं हो सकता है, क्योंकि इस तरह से मतभेदों को विभाजित करने से यह भेद करने के लिए आवश्यक भेद मिट जाएगा कि कोण किस कोण में है (नीचे देखें)। यदि आपकी भाषा में कोई atan2फ़ंक्शन शामिल है, तो इसके बजाय निम्नलिखित का उपयोग करें :

angleInDegrees = atan2(deltaY, deltaX) * 180 / PI

EDIT (22 फरवरी, 2017): सामान्य तौर पर, हालांकि, इसके atan2(deltaY,deltaX)लिए उचित कोण प्राप्त करने के लिए सिर्फ कॉल करना cosऔर sinअयोग्य हो सकता है। उन मामलों में, आप अक्सर इसके बजाय निम्नलिखित कर सकते हैं:

  1. (deltaX, deltaY)एक वेक्टर के रूप में समझो ।
  2. उस वेक्टर को एक इकाई वेक्टर से सामान्यीकृत करें। इतना विभाजित करने के लिए, deltaXऔर deltaYवेक्टर की लंबाई (से sqrt(deltaX*deltaX+deltaY*deltaY)), जब तक लंबाई 0 है।
  3. उसके बाद, deltaXअब वेक्टर और क्षैतिज अक्ष (सकारात्मक X से सकारात्मक Y अक्ष पर दिशा में P1) के बीच के कोण का कोसाइन होगा ।
  4. और deltaYअब उस कोण की साइन होगी।
  5. यदि वेक्टर की लंबाई 0 है, तो इसके और क्षैतिज अक्ष के बीच एक कोण नहीं होगा (इसलिए इसमें सार्थक साइन और कॉसियस नहीं होगा)।

EDIT (28 फरवरी, 2017): सामान्यीकरण के बिना भी (deltaX, deltaY):

  • deltaXवसीयत का संकेत आपको बताएगा कि चरण 3 में वर्णित कोसाइन सकारात्मक है या नकारात्मक।
  • यह संकेत deltaYआपको बताएगा कि चरण 4 में वर्णित साइन सकारात्मक है या नकारात्मक।
  • के संकेत deltaXऔर deltaYआप जो वृत्त का चतुर्थ भाग कोण, में है पर सकारात्मक एक्स अक्ष के संबंध में बता देंगे P1:
    • +deltaX, +deltaY: 0 से 90 डिग्री कम है।
    • -deltaX, +deltaY: 90 180 डिग्री कम है।
    • -deltaX, -deltaY: 180 270 डिग्री (-180 -90 अंश)।
    • +deltaX, -deltaY: 270 से 360 डिग्री (-90 0 डिग्री)।

रेडियन का उपयोग करते हुए पायथन में एक कार्यान्वयन (19 जुलाई, 2015 को एरिक लेसचिंस्की द्वारा प्रदान किया गया, जिन्होंने मेरे उत्तर को संपादित किया):

from math import *
def angle_trunc(a):
    while a < 0.0:
        a += pi * 2
    return a

def getAngleBetweenPoints(x_orig, y_orig, x_landmark, y_landmark):
    deltaY = y_landmark - y_orig
    deltaX = x_landmark - x_orig
    return angle_trunc(atan2(deltaY, deltaX))

angle = getAngleBetweenPoints(5, 2, 1,4)
assert angle >= 0, "angle must be >= 0"
angle = getAngleBetweenPoints(1, 1, 2, 1)
assert angle == 0, "expecting angle to be 0"
angle = getAngleBetweenPoints(2, 1, 1, 1)
assert abs(pi - angle) <= 0.01, "expecting angle to be pi, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 3)
assert abs(angle - pi/2) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 0)
assert abs(angle - (pi+pi/2)) <= 0.01, "expecting angle to be pi+pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 2, 2)
assert abs(angle - (pi/4)) <= 0.01, "expecting angle to be pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -2, -2)
assert abs(angle - (pi+pi/4)) <= 0.01, "expecting angle to be pi+pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -1, 2)
assert abs(angle - (pi/2)) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)

सभी परीक्षण पास। Https://en.wikipedia.org/wiki/Unit_circle देखें


35
यदि आपको यह पता चला है और आप JAVASCRiPT का उपयोग कर रहे हैं, तो यह ध्यान रखना बहुत महत्वपूर्ण है कि Math.sin और Math.cos रेडियन लेते हैं, इसलिए आपको परिणाम को डिग्री में बदलने की आवश्यकता नहीं है! इसलिए * 180 / PI बिट को अनदेखा करें। मुझे यह पता लगाने में 4 घंटे लगे। :)
साइडलॉन्डन

ऊर्ध्वाधर अक्ष के साथ कोण की गणना करने के लिए किसी को क्या उपयोग करना चाहिए?
ज़ीमून

3
@ आकाश 90 - angleInDegrees :?
jbaums

हमें 90 - एंगलडिजाइन करने की आवश्यकता क्यों है, क्या इसका कोई कारण है? कृपया इसे स्पष्ट करें।
प्रवीण मट्टनम

2
@sidonaldson यह केवल जावास्क्रिप्ट से अधिक है, यह C, C #, C ++, Java आदि है। वास्तव में, मैं कहता हूँ कि अधिकांश भाषाओं में अपनी गणित की लाइब्रेरी मुख्य रूप से रेडियन के साथ काम करती है। मैंने अभी तक एक ऐसी भाषा देखी है जो केवल डिफ़ॉल्ट रूप से डिग्री का समर्थन करती है।
चरण १rap

50

क्षमा करें, लेकिन मुझे पूरा यकीन है कि पीटर का उत्तर गलत है। ध्यान दें कि y अक्ष पृष्ठ के नीचे जाता है (ग्राफिक्स में सामान्य)। जैसे कि डेल्टा गणना को उलट दिया जाना चाहिए, या आपको गलत उत्तर मिल जाएगा।

विचार करें:

System.out.println (Math.toDegrees(Math.atan2(1,1)));
System.out.println (Math.toDegrees(Math.atan2(-1,1)));
System.out.println (Math.toDegrees(Math.atan2(1,-1)));
System.out.println (Math.toDegrees(Math.atan2(-1,-1)));

देता है

45.0
-45.0
135.0
-135.0

इसलिए यदि उपरोक्त उदाहरण में, P1 है (1,1) और P2 है (2,2) [क्योंकि Y पृष्ठ को बढ़ाता है], ऊपर दिए गए कोड में दिखाए गए उदाहरण के लिए 45.0 डिग्री दी जाएगी, जो कि गलत है। डेल्टा गणना के क्रम को बदलें और यह ठीक से काम करता है।


3
जैसा आपने सुझाव दिया था मैंने उसे उलट दिया और मेरा रोटेशन पीछे की ओर हो गया।
शैतान का अधिवक्ता

1
अपने कोड में मैं इसे ठीक कर रहा हूं: double arc = Math.atan2(mouse.y - obj.getPy(), mouse.x - obj.getPx()); degrees = Math.toDegrees(arc); if (degrees < 0) degrees += 360; else if (degrees > 360) degrees -= 360;
मार्कस बेकर

यह उस सर्कल के क्वॉर्टर पर निर्भर करता है, जो कि आप का कोण है: यदि आपका क्वार्टर पहले क्वार्टर में (90 डिग्री तक) डेल्टाक्स और डेल्टाई के लिए पॉजिटिव वैल्यू (Math.abs) का उपयोग करता है, तो दूसरे (90-180) में उपयोग करें एक नकारात्मक मूल्य डेल्टा का, तीसरे में (180-270) नकारात्मक दोनों डेल्टा और डेल्टा और चौथे int (270-360) ने केवल डेल्टा को नकार दिया - नीचे मेरा जवाब देखें
ममशेर 10:17

1

मैंने पायथन में एक समाधान पाया है जो अच्छी तरह से काम कर रहा है!

from math import atan2,degrees

def GetAngleOfLineBetweenTwoPoints(p1, p2):
    return degrees(atan2(p2 - p1, 1))

print GetAngleOfLineBetweenTwoPoints(1,3)

1

सटीक प्रश्न को ध्यान में रखते हुए, हमें एक "विशेष" निर्देशांक प्रणाली में रखा गया है, जहां सकारात्मक अक्ष का अर्थ है DOWN (जैसे कि स्क्रीन या इंटरफ़ेस दृश्य), आपको इस फ़ंक्शन को इस तरह से अनुकूलित करने की आवश्यकता है, और Y निर्देशांक को नकारात्मक:

उदाहरण 2.0 स्विफ्ट में

func angle_between_two_points(pa:CGPoint,pb:CGPoint)->Double{
    let deltaY:Double = (Double(-pb.y) - Double(-pa.y))
    let deltaX:Double = (Double(pb.x) - Double(pa.x))
    var a = atan2(deltaY,deltaX)
    while a < 0.0 {
        a = a + M_PI*2
    }
    return a
}

यह फ़ंक्शन प्रश्न का सही उत्तर देता है। उत्तर रेडियन में है, इसलिए उपयोग, डिग्री में कोणों को देखने के लिए है:

let p1 = CGPoint(x: 1.5, y: 2) //estimated coords of p1 in question
let p2 = CGPoint(x: 2, y : 3) //estimated coords of p2 in question

print(angle_between_two_points(p1, pb: p2) / (M_PI/180))
//returns 296.56

0

"पीटर ओ" संदर्भ के आधार पर .. यहाँ जावा संस्करण है

private static final float angleBetweenPoints(PointF a, PointF b) {
float deltaY = b.y - a.y;
float deltaX = b.x - a.x;
return (float) (Math.atan2(deltaY, deltaX)); }

0

matlab फ़ंक्शन:

function [lineAngle] = getLineAngle(x1, y1, x2, y2) 
    deltaY = y2 - y1;
    deltaX = x2 - x1;

    lineAngle = rad2deg(atan2(deltaY, deltaX));

    if deltaY < 0
        lineAngle = lineAngle + 360;
    end
end

0

0 से 2pi तक के कोण के लिए एक सूत्र।

X = x2-X1 और y = y2-y1 है। सूत्र के लिए काम कर रहा है

x और y का कोई भी मान। X = y = 0 के लिए परिणाम अपरिभाषित है।

च (एक्स, वाई) = अनुकरणीय () - अनुकरणीय () / 2 * (1 + चिह्न (x)) * (1-चिह्न (y ^ 2))

     -pi()/4*(2+sign(x))*sign(y)

     -sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

0
deltaY = Math.Abs(P2.y - P1.y);
deltaX = Math.Abs(P2.x - P1.x);

angleInDegrees = Math.atan2(deltaY, deltaX) * 180 / PI

if(p2.y > p1.y) // Second point is lower than first, angle goes down (180-360)
{
  if(p2.x < p1.x)//Second point is to the left of first (180-270)
    angleInDegrees += 180;
  else //(270-360)
    angleInDegrees += 270;
}
else if (p2.x < p1.x) //Second point is top left of first (90-180)
  angleInDegrees += 90;

आपके कोड का कोई मतलब नहीं है: और (270-360) .. क्या?
WDUK

0
import math
from collections import namedtuple


Point = namedtuple("Point", ["x", "y"])


def get_angle(p1: Point, p2: Point) -> float:
    """Get the angle of this line with the horizontal axis."""
    dx = p2.x - p1.x
    dy = p2.y - p1.y
    theta = math.atan2(dy, dx)
    angle = math.degrees(theta)  # angle is in (-180, 180]
    if angle < 0:
        angle = 360 + angle
    return angle

परिक्षण

परीक्षण के लिए मैंने परिकल्पना को परीक्षण मामलों को उत्पन्न करने दिया।

यहां छवि विवरण दर्ज करें

import hypothesis.strategies as s
from hypothesis import given


@given(s.floats(min_value=0.0, max_value=360.0))
def test_angle(angle: float):
    epsilon = 0.0001
    x = math.cos(math.radians(angle))
    y = math.sin(math.radians(angle))
    p1 = Point(0, 0)
    p2 = Point(x, y)
    assert abs(get_angle(p1, p2) - angle) < epsilon
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.