Pyslvs 開發進度:

  • 三角求解器模組

Pyslvs 開發進度

三角求解器模組

寫了一個小模組求解,還未連接使用者界面。

主要功能是傳入一個 list(包含大量題目)並解題。不過 class 裡的函式可以單獨使用。

from math import *

##Directions:
##[{'p1':Point1, 'p2':Point2, 'len1':Line1, ('len2':Line2, 'angle':angle)}, ...]

class solver():
    def __init__(self, Directions=list()):
        #Cosine Theorem
        self.CosineTheoremAngle = lambda a, b, c: acos((b**2+c**2-a**2)/(2*b*c))
        self.CosineTheoremSide = lambda alpha, b, c: b**2+c**2-2*b*c*cos(alpha)
        self.Directions = Directions

    def set(self, Directions): self.Directions = Directions

    def answer(self):
        answer = self.Iterator() if self.Parser() else None
        self.Directions.clear()
        return answer

    def Parser(self):
        for e in self.Directions:
            pos = self.Directions.index(e)
            if e.get('p1', False) is False: return False
            if e.get('p2', False) is False: return False
            if e.get('len1', False) is False: return False
            if e.get('len2', False) is False and e.get('angle', False) is False: return False
            if e.get('len2', False) is False: self.Directions[pos]['Type'] = 'PLAP'
            elif e.get('angle', False) is False: self.Directions[pos]['Type'] = 'PLLP'
        return True

    def Iterator(self):
        results = list()
        for e in self.Directions:
            p1 = results[e['p1']] if type(e['p1'])==int else e['p1']
            p2 = results[e['p2']] if type(e['p2'])==int else e['p2']
            #Direction of the point
            other = e.get('other', False)
            ##True: angle1-angle2
            ##False: angle1+angle2
            if e['Type']=='PLAP': results.append(self.PLAP(p1, e['len1'], e['angle'], p2, other))
            elif e['Type']=='PLLP': results.append(self.PLLP(p1, e['len1'], e['len2'], p2, other))
        return results

    def PLAP(self, p1, line1, angle, p2, other=False):
        x1 = p1[0]
        y1 = p1[1]
        len1 = float(line1)
        angle2 = radians(float(angle))
        angle1 = self.m(p1, p2)
        if other:
            cx = x1+len1*cos(angle1-angle2)
            cy = y1+len1*sin(angle1-angle2)
        else:
            cx = x1+len1*cos(angle1+angle2)
            cy = y1+len1*sin(angle1+angle2)
        return cx, cy

    def PLLP(self, p1, line1, line2, p2, other=False):
        x1 = p1[0]
        y1 = p1[1]
        x2 = p2[0]
        y2 = p2[1]
        len1 = float(line1)
        len2 = float(line2)
        d = sqrt((x1-x2)**2+(y2-y1)**2)
        angle1 = self.m(p1, p2)
        angle2 = self.CosineTheoremAngle(len2, d, len1)
        if other:
            cx = x1+len1*cos(angle1-angle2)
            cy = y1+len1*sin(angle1-angle2)
        else:
            cx = x1+len1*cos(angle1+angle2)
            cy = y1+len1*sin(angle1+angle2)
        return cx, cy

    def m(self, p1, p2):
        x1 = p1[0]
        y1 = p1[1]
        x2 = p2[0]
        y2 = p2[1]
        x = x2-x1
        y = y2-y1
        d = sqrt(x**2+y**2)
        return self.CosineTheoremAngle(y, x, d)*(-1 if y<0 else 1)*(-1 if x<0 else 1)

if __name__=='__main__':
    #Test
    s = solver([
        {'p1':(-60, 0), 'p2':(0, 0), 'len1':30, 'angle':50}, #C
        {'p1':0, 'p2':(0, 0), 'len1':50, 'len2':60}, #D
        {'p1':0, 'p2':1, 'len1':50, 'len2':50}, #E
        ])
    print("C={}\nD={}\nE={}".format(*s.answer()))

    ##cx= -40.716371709403816 cy= 22.98133329356934
    ##dx= -6.698073034033397 dy= 59.62495968661744
    ##ex= -55.44153371488418 ey= 70.76385733649067

解題方向指定 p1、p2、len1、angle 或 len2,Parser 會檢查填入項的完整性;Iterator 會自動判斷輸入內容選擇解題。

而 p1 與 p2 的座標是使用 list 或 tuple 型態給兩個座標軸(取 [0]、[1]),或是引用上一個解(之後會增加順序檢查機制)。其他數據皆為 float 型態。

角度方面使用 degree,不過 Python 的 math 模組是用 radian,途中會進行轉換。

原理都是先求 AB 與水平夾的角度(angle1),最後將 CAB 夾角(angle2)加上 angle1 求 AC 與水平夾的角度,最後求出 C 點座標。

之中為了方便,將餘弦定理做成 lambda 使用。

程式可能還有一些漏洞,接上 Gui 之前會再檢查一遍。


Comments

comments powered by Disqus