Microsoft MVP성태의 닷넷 이야기
Graphics: 16. 3D 공간에서 두 점이 이루는 각도 구하기 [링크 복사], [링크+제목 복사],
조회: 30130
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

3D 공간에서 두 점이 이루는 각도 구하기

예를 들어, 다음과 같이 3D 공간에서 면과 점이 있다고 가정해 보겠습니다.

angle_between_two_0.png
(오른손 좌표계 시스템의 x-y-z 축을 사용하고 있습니다.)

이때 점 C와 점 A가 이루는 각도는 어떻게 될까요? 간단하게 점과 점의 위치를 빼서 벡터를 만들고,

점 C와 카메라의 벡터 = 점 C - 점 A
                    = (-1.4, -2.9, -5)

그 벡터가 이루는 각을 3차원에 따라 각 축 별로 3개의 각도를 구할 수 있습니다.

  • x-축을 기준으로 y-z 평면의 각
  • y-축을 기준으로 x-z 평면의 각
  • z-축을 기준으로 x-y 평면의 각

역시 시각화를 해보는 게 좋겠지요? ^^ GeoGebra 앱에서 "Home" 모양의 아이콘을 누르면,

angle_between_two_1.png

차례대로 "y축을 기준으로 x-z 평면", "z축을 기준으로 x-y 평면", "x축을 기준으로 y-z 평면" 상에서의 물체를 볼 수 있는 기능이 제공됩니다.

자... 멋진 툴이 있으니, 그럼 우선 첫 번째 아이콘인 "y축을 기준으로 x-z 평면"을 다음과 같이 볼 수 있습니다. ^^

angle_between_two_2_y.png

보는 바와 같이 x-z 평면에서 벡터가 이루는 각을 쉽게 확인할 수 있습니다. 점 A에서 x-축으로 수선의 발을 그렸을 때,

angle_between_two_3.png

직각 삼각형이 되고 이때 우리가 아는 벡터 A의 x, z 성분의 값으로 인해 아크 탄젠트 함수를 사용하면 점 A에서 이루는 각도를 구할 수 있습니다.

각 A = arc_tangent(vx, vz);

C# 코드로 구해 보면 다음과 같습니다.

Vector3 v3 = new Vector3(-1.4f, -2.9f, -5f);

{
    double yAngle = Math.Atan2(v3.X, v3.Z);
    Console.WriteLine(RadianToDegree(yAngle));
}

실행해 보면, -164.357753796137도가 나오는데, 벡터가 음의 방향이어서 그런 것일 뿐 180도를 빼면 약 15.6도가 나옵니다. 동일한 각도를 Geogebra 기하를 이용해서도 구해 볼까요? ^^

2차원 좌표계에서 x, z의 성분으로 점을 표시한 후 그와 연결한 벡터를 그리고 그 사잇각을 다음과 같이 구할 수 있습니다.

angle_between_two_4.png

잘 맞아 들어가는군요. ^^




마찬가지 방식으로 "z축을 기준으로 x-y 평면"과,

angle_between_two_2_z.png

"x축을 기준으로 y-z 평면" 상의 모습을 확인하며,

angle_between_two_2_x.png

각도를 구해 보면 이렇습니다.

Vector3 v3 = new Vector3(-1.4f, -2.9f, -5f);
Console.WriteLine("xAngle");
{
    double xAngle = Math.Atan2(v3.Y, v3.Z);
    Console.WriteLine(RadianToDegree(xAngle));
}

Console.WriteLine("yAngle");
{
    double yAngle = Math.Atan2(v3.X, v3.Z);
    Console.WriteLine(RadianToDegree(yAngle));
}

Console.WriteLine("zAngle");
{
    double zAngle = Math.Atan2(v3.Y, v3.X);
    Console.WriteLine(RadianToDegree(zAngle));
}

/*
출력 결과

xAngle
-149.886266031276
yAngle
-164.357753796137
zAngle
-115.769326504636
*/

(첨부 파일은 이 글에서 예제로 사용한 geogebra 파일입니다.)




참고로, 2개의 벡터가 이루는 각은 아크코사인을 이용해 구할 수 있습니다.

vector v1 = ...;
vector v2 = ...;

vector nv1 = normalize(v1);
vector nv2 = normalize(v2);

float angle = acos(mul(nv1, nv2));

일반적으로 acos의 정의역이 -1 ~ 1이기 때문에 정규화된 벡터의 내적 연산으로 NaN 값을 반환하는 경우는 없습니다. 문제는 0 벡터인 경우 normalize 하는 과정에서 NaN이 나온다는 것입니다.

vector v = vector(0, 0, 0, 0);
vector normal = normalize(v); // normal == NaN

왜냐하면 정규화라는 것이 벡터 크기로 나누는 것인데,

${
\hat v = \left ( \frac{ v_x }{ \Vert v \Vert }, \frac{ v_y }{ \Vert v \Vert }, \frac{ v_z }{ \Vert v \Vert } \right )
}$

분모가 0이 되므로 normalize의 결과가 NaN이 나옵니다. 이 때문에 mul 연산도 NaN이 되고, acos까지 NaN으로 끝납니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 8/1/2018]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 121  122  123  124  125  126  [127]  128  129  130  131  132  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
2880정성태3/7/201521677개발 환경 구성: 260. C# Code Coverage 도구 - Semantic Designs 소개
2879정성태3/3/201526680개발 환경 구성: 259. Visual Studio 없이 Visual C++ 컴파일하는 방법
2878정성태2/28/201527550.NET Framework: 503. == 연산자보다는 Equals 메서드의 호출이 더 권장됩니다. [3]파일 다운로드1
2877정성태2/28/201521750.NET Framework: 502. 연산자 재정의(operator overloading)와 메서드 재정의(method overriding)의 다른 점 - 가상 함수 호출 여부 [3]파일 다운로드1
2876정성태2/27/201524216VS.NET IDE: 98. IntegraStudio - Visual Studio에서 Java 프로그램 개발
2875정성태2/26/201522824디버깅 기술: 72. Visual Studio 2013에서의 sos.dll 사용 제한
2874정성태2/26/201519574디버깅 기술: 71. windbg + 닷넷 디버깅 (2) - null 체크 패턴
2873정성태2/25/201537048.NET Framework: 501. FtpWebRequest 타입을 이용해 FTP 파일 업로드 [4]파일 다운로드1
2872정성태2/25/201521232디버깅 기술: 70. windbg + 닷넷 디버깅 (1) - 배열 인덱스 사용 패턴
2871정성태2/24/201525203개발 환경 구성: 258. 윈도우 8.1에서 방화벽과 함께 FTP 서버 여는 (하지만, 권장하지 않는) 방법 [1]
2870정성태2/24/201526340개발 환경 구성: 257. 윈도우 8.1에서 방화벽과 함께 FTP 서버 여는 방법
2869정성태2/23/201520312.NET Framework: 500. struct로 정의한 값 형식(Value Type)의 경우 Equals 재정의를 권장합니다.파일 다운로드1
2868정성태2/23/201524823VS.NET IDE: 97. Visual C++ 프로젝트 디버깅 시에 Step-Into(F11) 동작이 원치 않는 함수로 진입하는 것을 막는 방법 [2]
2867정성태2/23/201518522오류 유형: 273. File History - Failed to initiate user data backup (error 80070005)
2866정성태2/23/201520367오류 유형: 272. WAT080 : Failed to locate the Windows Azure SDK. Please make sure the Windows Azure SDK v2.1 is installed.
1868정성태2/20/201517668오류 유형: 271. The type '...' cannot be used as type parameter 'TContext' in the generic type or method 'System.ServiceModel.DomainServices.EntityFramework.LinqToEntitiesDomainService<T>
1866정성태2/20/201518570오류 유형: 270. "aspnet_regiis -i" 실행 시 0x00000006 오류 해결 방법
1865정성태2/20/201519872.NET Framework: 499. 특정 닷넷 프레임워크 버전 이후부터 제공되는 타입을 사용해야 한다면?
1864정성태2/18/201524863.NET Framework: 498. C#으로 간단하게 만들어 본 ASCII Art 프로그램 [2]파일 다운로드1
1862정성태2/18/201528699.NET Framework: 497. .NET Garbage Collection에 대한 정리 [6]
1861정성태2/18/201524050.NET Framework: 496. 마우스 커서가 놓인 지점의 문자열 얻는 방법 [1]파일 다운로드1
1860정성태2/18/201523875.NET Framework: 495. CorElementType의 요소 값 설명파일 다운로드1
1859정성태2/17/201524281Windows: 106. 컴퓨터를 재부팅하면 절전(Power Saver) 전원 모드로 돌아가는 경우
1858정성태2/16/201534266Windows: 105. 자동으로 로그아웃/잠김 화면 상태로 전환된다면? [2]
1857정성태2/16/201522277.NET Framework: 494. 값(struct) 형식의 제네릭(Generic) 타입이 박싱되는 경우의 메타데이터 토큰 값파일 다운로드1
1856정성태2/15/201521255.NET Framework: 493. TypeRef 메타테이블에 등록되는 타입의 조건파일 다운로드1
... 121  122  123  124  125  126  [127]  128  129  130  131  132  133  134  135  ...