Remrinのpython攻略日記

python3に入門しました。python3についてあれこれとサンプルコードとか。

三角形の内接円、外接円、面積、角度

外接円の中心と半径を求めるコードを作ってみました。

公式がわからなかったので、Wikipediaの外接円の項目を参照しました。

"(0,0),(0,6),(8,0)"の形の3頂点の座標から中心の座標(x, y)と半径rを求め、
(x-1)^2+(y-2)^2=3^2という円の方程式の形で結果を出力します。
小数の場合は小数点以下2桁までに四捨五入し、必要のなくなったゼロは消去。

python3
# coding: utf-8
import math

def rounding(n):
    n = int(n) if n==int(n) else round(n, 2)    #rounding
    n = int(n) if n==int(n) else n              #3.0, 3.00 >>> 3
    return n

def circumcenter(data):
    #split
    data_split = data.replace("(", "").replace(")", "").split(",")       
    x1, y1, x2, y2, x3, y3 = map(int, data_split)
    
    #length of each side to the second power and area of the triangle
    a2 = (x2 - x3) **2 + (y2 -y3) ** 2 
    b2 = (x1 - x3) **2 + (y1 -y3) ** 2
    c2 = (x2 - x1) **2 + (y2 -y1) ** 2
    area = ((x2 - x1) * (y3 -y1) - (x3 -x1) * (y2- y1)) / 2

    #not on the same line please
    if area == 0:
        return "three points exist on the same line"
    
    #circumcenter coordinate and radius      
    x = (a2*(b2+c2-a2)*x1 + b2*(c2+a2-b2)*x2 +c2*(a2+b2-c2)*x3) / (16*area*area)
    y = (a2*(b2+c2-a2)*y1 + b2*(c2+a2-b2)*y2 +c2*(a2+b2-c2)*y3) / (16*area*area) 
    r = math.sqrt((x1 - x ) ** 2 + (y1 - y) ** 2)
    
    #rounding
    x, y, r = map(rounding, [x, y, r])
    
    #join to return
    return "(x-{})^2+(y-{})^2={}^2".format(x, y, r)

if __name__ == '__main__':
    print(circumcenter("(0,0),(0,6),(8,0)"))
    print(circumcenter("(7,3),(9,6),(3,6)"))
    print(circumcenter("(3,4),(4,2),(5,0)"))

うまく丸める処理が思いつきませんでした。
たとえば、x=3.004の場合、小数点以下2位までに四捨五入すると3.00で、
その後に改めて不要な.00を消す処理にしました。

高校の数学では垂直二等分線の交点を求めた気がします。
時間ができたらそちらでも試してみようと思います。

入力から数値を抽出するのにreplaceで()、カンマを消してましたが、
eval()を使うとシンプルにできるっぽい

map()を初めて使いました。最初は

map(lambda x:int(x), data_split)

としてましたが、単純に

map(int, data_split)

でいいんですね。()を消す勇気がありませんでした

外接円の中心と半径を求めるプログラムを少し直しました。

# coding: utf-8

def circumcenter(data):
    #coordinates
    (x1, y1), (x2, y2), (x3, y3) = eval(data)
    
    #length of each side squared and area of the triangle
    a2 = (x2 - x3) **2 + (y2 -y3) ** 2 
    b2 = (x1 - x3) **2 + (y1 -y3) ** 2
    c2 = (x2 - x1) **2 + (y2 -y1) ** 2
    area = ((x2 - x1) * (y3 -y1) - (x3 -x1) * (y2- y1)) / 2

    #is_triangle
    if area == 0:
        return "three points exist on the same line"
    
    #circumcenter coordinate and radius      
    x = (a2*(b2+c2-a2)*x1 + b2*(c2+a2-b2)*x2 + c2*(a2+b2-c2)*x3) / (16*area*area)
    y = (a2*(b2+c2-a2)*y1 + b2*(c2+a2-b2)*y2 + c2*(a2+b2-c2)*y3) / (16*area*area) 
    r = ((x1-x)**2 + (y1-y)**2)**0.5
    
    #rounding
    x, y, r = map(lambda x:round(x, 2) if x!=int(x) else int(x), (x, y, r))
    
    #return the equation
    return "(x-{})^2+(y-{})^2={}^2".format(x, y, r)

if __name__ == '__main__':
    print(circumcenter("(0,0),(0,6),(8,0)"))
    print(circumcenter("(7,3),(9,6),(3,6)"))
    print(circumcenter("(3,4),(4,2),(5,0)"))

 
3辺の長さから三角形の内接円、外接円、面積、角度を求めるプログラム

# coding: utf-8
import math

def triangle(a, b, c):
    if abs(b-c) >= a or (b+c) <= a:
        print("三角形になりません")
    else:
        s = (a + b + c) / 2
        area = (s * (s - a) * (s - b) * (s - c))**0.5
        in_radius = 2 * area / (a + b + c)
        out_radius = (a *  b * c) / (4 * in_radius * s)
        angle1 = round(math.acos((b*b + c*c -a*a)/(2*b*c))/math.pi*180)
        angle2 = round(math.acos((c*c + a*a -b*b)/(2*c*a))/math.pi*180)   
        angle3 = round(math.acos((a*a + b*b -c*c)/(2*a*b))/math.pi*180)
        angles = sorted([angle1, angle2, angle3])    

        print("3辺:", a, b, c)
        print("面積:", round(area, 2))
        print("内接円の半径:", round(in_radius, 2))
        print("外接円の半径:", round(out_radius, 2))
        print("角度:", *angles)

triangle(3, 4, 5)

 
クラスで作ってみました。

import math

class Triangle2():
    def __init__(self, a, b, c):
        self.a , self.b, self.c = a, b, c
        
    def is_triangle(self):
        return abs(self.b-self.c) < self.a and (self.b+self.c) > self.a

    def area(self):
        if self.is_triangle() != True:
            return 0
        else:
            s = (self.a + self.b + self.c) / 2
            return round((s * (s - self.a) * (s - self.b) * (s - self.c))**0.5, 2)

    def in_radius(self):
        if self.is_triangle() != True:
            return None
        else:
            return round(2 * self.area() / (self.a+ self.b + self.c), 2)
    
    def out_radius(self):
        if self.is_triangle() != True:
            return None
        else:
            s = (self.a + self.b + self.c) / 2
            return round((self.a * self.b * self.c) / (4 * self.in_radius() * s), 2)
    def angles(self):
        if self.is_triangle() != True:
            return None
        else:
            a1 = (self.b**2 + self.c**2 -self.a**2)/(2 * self.b * self.c)
            a2 = (self.c**2 + self.a**2 -self.b**2)/(2 * self.c * self.a)  
            a3 = (self.a**2 + self.b**2 -self.c**2)/(2 * self.a * self.b)
            return sorted([round(math.acos(a)/math.pi*180) for a in [a1, a2, a3]])

t = Triangle2(6, 8, 10)
print(t.is_triangle()) # True
print(t.area())        # 24.0
print(t.in_radius())   # 2.0
print(t.out_radius())  # 5.0
print(t.angles())      # [37, 53, 90]