Microsoft MVP성태의 닷넷 이야기
Graphics: 16. 3D 공간에서 두 점이 이루는 각도 구하기 [링크 복사], [링크+제목 복사],
조회: 30110
글쓴 사람
정성태 (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

비밀번호

댓글 작성자
 




... 151  152  153  154  155  156  157  158  159  160  161  162  163  [164]  165  ...
NoWriterDateCnt.TitleFile(s)
944정성태11/11/201031644VC++: 43. C++/CLI 컴파일 오류 - error C2872: 'IServiceProvider' : ambiguous symbol could be ...
943정성태11/8/201030763디버깅 기술: 30. windbg ".loadby sos" 명령어 [2]
942정성태11/7/201042337.NET Framework: 187. 실행 시에 메서드 가로채기 - CLR Injection: Runtime Method Replacer 개선 [7]파일 다운로드3
941정성태11/6/201025253.NET Framework: 186. windbg로 확인하는 .NET CLR LCG 메서드(DynamicMethod) [1]파일 다운로드1
940정성태11/6/201026116.NET Framework: 185. windbg로 확인하는 .NET CLR 메서드파일 다운로드1
939정성태10/24/201033070Windows: 51. RDP로 접속한 Windows Server 2008 R2 환경에서 Aero Glass 활성화 [1]
938정성태10/23/201024830디버깅 기술: 29. Windbg - Hyper-V 윈도우 7 원격 디버깅 구성 [1]
937정성태10/22/201030965DDK: 5. NT Legacy 드라이버: 프로세스(EXE) 생성/제거 모니터링 [3]파일 다운로드1
936정성태10/21/201029997DDK: 4. Device Driver 응용 프로그램의 빌드 스크립트 - 두 번째 이야기 [2]파일 다운로드1
935정성태10/17/201030608디버깅 기술: 28. Windbg - 윈도우 핸들 테이블 [3]
934정성태10/11/201033597디버깅 기술: 27. Windbg - Local Kernel Debug 모드 [2]
933정성태10/10/201025793.NET Framework: 184. 닷넷에서 호출 스택의 메서드에 대한 인자 값 확인이 가능할까? [2]파일 다운로드1
932정성태10/10/201029027DDK: 3. NT Legacy 드라이버를 이용하여 C#에서 Port 입출력파일 다운로드1
931정성태9/30/201023599오류 유형: 108. Net.Tcp Listener Adapter 서비스 시작 실패
930정성태9/30/201022909웹: 16. 윈도우 미디어 플레이어 - 일시 정지/시작을 스크립트에서 감지
929정성태9/17/201024138웹: 15. IE 9 - 작업 표시줄의 웹 사이트 바로가기 사용자 정의 - JumpLists [3]파일 다운로드1
928정성태9/16/201028308VC++: 42. 쓰기 전용 파일(예: 로그 파일)의 동기화 방법파일 다운로드1
927정성태9/14/201038166VC++: 41. UTF-8 포맷의 INI 파일에 대한 GetPrivateProfile... API 사용 불가 [2]
926정성태9/9/201027443Team Foundation Server: 41. 빌드 스크립트에 Code Coverage 추가 [1]파일 다운로드1
925정성태9/8/201031341Team Foundation Server: 40. Visual Studio 2010 - Code Coverage 결과를 외부 XML 파일로 출력하는 명령행 도구 제작 [1]파일 다운로드1
924정성태9/6/201021602개발 환경 구성: 88. SCVMM이 설치된 도메인에 참여하지 않은 Hyper-V 호스트 추가
923정성태9/5/201027587오류 유형: 107. SCVMM Agent 설치 오류 - Failed to configure the WS-Management service.
922정성태9/4/201036260오류 유형: 106. Hyper-V 가상 머신의 네트워크 끊김 현상
921정성태9/2/201030290DDK: 2. Device Driver 응용 프로그램의 빌드 스크립트 [2]파일 다운로드1
920정성태9/1/201034730오류 유형: 105. WMI - The RPC server is unavailable [2]
919정성태8/30/201040849DDK: 1. Visual Studio 2010 - Device Driver 제작- Hello World 예제 [3]파일 다운로드1
... 151  152  153  154  155  156  157  158  159  160  161  162  163  [164]  165  ...