두 원의 중심좌표와 반지름의 길이가 주어졌을 때, 교차범위의 면적을 구하는 문제를 풀어본다.

이 문제의 경우 삼각함수의 성질과 역삼각함수를 알아야 해결 가능하다.

 

두 원의 위치 관계로 가능한 경우는 다음과 같다.

①  두 원이 서로 접해있거나 떨어져있는 경우 (r1 + r2 <= d)

이 경우 두 원의 교차범위는 없다. 즉, 면적은 0이 된다.

 

② 한 원이 다른 원에 들어가있는 경우 (abs(r1 - r2) >= d)

이 경우 두 원의 교차범위는 작은쪽 원 전체가 되며 면적은 그 원의 면적이 된다.

 

③ 두 개의 교점을 가지는 경우

이 경우 부채꼴 O1P1P2 에서 삼각형 O1P1P2를 뺀 면적과 부채꼴 O2P1P2에서 삼각형 O2P1P2를 뺀 면적이 교차범위의 면적이 된다.

③의 경우 교차면적의 넓이는 ((r1 ** 2 * (a1 - sin(a1))) - (r2 ** 2 * (a2 - sin(a2)))) / 2 가 된다.

내각 a1 과 a2를 알아내기 위해서는 코사인 제 2 법칙과 역코사인 함수를 사용한다.

 

※ 제 2 코사인 법칙

위와 같이 삼각형의 세 변이 주어졌을 때, 내각 k에 대해

a^2 + b^2 - 2ab * cos(k) = c^2 가 성립한다.

 

제 2 코사인 법칙에 따라,

cos(a1) = (r1^2 - r2^2 + d^2) / (2 * r1 * d) 

cos(a2) = (r2^2 - r1^2 + d^2) / (2 * r2 * d) 

이 된다.

 

cos(x) = y 일 때, arccos(y) = x 이므로,

a1 = arccos((r1^2 - r2^2 + d^2) / (2 * r1 * d))

a2 = arccos((r2^2 - r1^2 + d^2) / (2 * r2 * d))

이 된다.

 

교차범위의 면적을 구하기 위해 필요한 두 내각의 값을 얻는 방법만 알면 구현은 간단하다.  이를 구현한 코드는 다음과 같다.

 

import sys
import math

input = sys.stdin.read


def sol7869():
    # 두 원의 중점의 좌표와 반지름 길이
    x1, y1, r1, x2, y2, r2 = map(float, input().split())
    
    # 두 원의 중점 사이의 거리
    d = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** .5
    
    # 두 원이 외접하거나 떨어져있는 경우
    if d >= r1 + r2:
        return 0
        
    # 두 원이 내접하거나 포함관계인 경우
    if d <= abs(r1 - r2):
        return round(math.pi * min(r1, r2) ** 2, 3)

	# 두 원이 두 개의 교점을 가지는 경우
    # 공식에 따라 두 내각을 구한 뒤 교차면적을 소수점 넷째자리에서 반올림하여 반환
    a1, a2 = 2 * math.acos((d ** 2 + (r1 ** 2 - r2 ** 2)) / (2 * r1 * d)), 2 * math.acos((d ** 2 - (r1 ** 2 - r2 ** 2)) / (2 * r2 * d))
    return round(1 / 2 * (r1 ** 2 * (a1 - math.sin(a1)) + r2 ** 2 * (a2 - math.sin(a2))), 3)


# 반올림 함수
def round(num, digit):
    # 자릿수만큼 10을 곱한 뒤 소수점자리가 5 이상이라면 1을 더해준다
    k = 10 ** digit
    res = num * k
    if res - int(res) >= 0.5:
        res += 1
    
    # 정수변환 후 자릿수만큼 10을 나누어 반환
    return int(res) / k

이러한 수학공식을 모두 기억하긴 어렵지만 원의 위치관계나 교차면적 등의 문제는 꽤 자주 응용문제로 등장할 수 있기 때문에 기억해두는게 좋을 것 같다.

+ Recent posts