Gribouillis
Posting Maven
Moderator
2,786 posts since Jul 2008
Reputation Points: 1,044
Solved Threads: 691
Hi all, this is my first post.
A couple days ago, in preparation for a math final, I attempted to code a program which would allow me to solve triangles (law of cosines, sines, etc.). Now that the test is over, I am now interested in getting it working.
#This is TRIANGLE SOLVER!!!
#solves triangles, in SSS, ASA, SSA, AAS, SAS
#Written by Jared Miller, 2013, AAST, June 1 2010
import math
#functions
def askyesno():
if input("\nAgain?")==("y" or "Y" or "yes" or "Yes" or "YES"):
return True
else:
return False
#math constants
PI=math.pi
#math functions
sq=lambda x: math.sqrt(x)
p2=lambda x: x**2
#trig functions
sin=lambda x: math.sin(rad(x))
cos=lambda x: math.cos(rad(x))
#trig inverses
asin=lambda x: deg(math.asin(x))
acos=lambda x: deg(math.acos(x))
#trig measurements
deg=lambda x: math.degrees(x)
rad=lambda x: math.radians(x)
#laws of cosines and sines
#law of cosines, for angle and side
def lawcosside(a,b,C):
"""Law of cosines, solving side C"""
return sq(p2(a)+p2(b)-2*a*b*cos(C))
def lawcosangle(a,b,c):
"""Law of cosines, solving for angle C"""
return acos((p2(a)+p2(b)-p2(c))/(2*a*b))
#law of sines, for missing angle and side:
def lawsinside(A,a,B):
"""Law of sines, solving for side b"""
return (a*sin(B))/sin(A)
def lawsinangle(a,A,b):
"""Law of sines, solving for angle B"""
return asin((b*sin(A))/a)
#Solving triangles
#Single solution, regular cases
def SSS(a,b,c):
"""Finds angles A, B, C"""
A=lawcosangle(b,c,a)
B=lawcosangle(c,a,b)
C=180-A-B
assert not A+B+C>182
return {"sides":(a,b,c),"angles":(A,B,C)}
def ASA(A,c,B):
"""Finds sides a, b; and angle C"""
C=180-A-B
a=lawsinside(C,c,A)
b=lawsinside(C,c,B)
assert not A+B+C>182
return {"sides":(a,b,c),"angles":(A,B,C)}
def SAS(a,B,c):
"""Finds side b and angles A and C"""
b=lawcosside(a,c,B)
A=lawsinangle(b,B,a)
C=180-A-B
assert not A+B+C>182
return {"sides":(a,b,c),"angles":(A,B,C)}
def AAS(A,B,a):
"""Finds sides b, c; and angle C"""
b=lawsinside(A,a,B)
C=180-A-B
c=lawsinside(A,a,C)
assert not A+B+C>182
return {"sides":(a,b,c),"angles":(A,B,C)}
#Holy...multiple possible triangles
def SSA(c,a,A):
"""Returns 0,1,or 2 triangles, depending upon the case"""
#height declaration
A=rad(A)
h=c*sin(A)
#case 1:
#h>a
#0 triangles
if h>a:
return []
#case 2:
#h=a
#1 triangle
elif h==a:
C=90
B=180-A-C
b=lawsinside(A,a,B)
assert not A+B+C>182
return [{"sides":(a,b,c),"angles":(A,B,C)}]
#case 3:
#h<a<c
#2 triangles
elif h<a and a<c:
C1a=lawsinangle(a,A,c)
C2a=180-C1a
if C1a>C2a:
C1,C2=C1a,C2a
else:
C1,C2=C2a,C1a
B1=180-A-C1
B2=180-A-C2
assert not A1+B1+C1>182
assert not A2+B2+C2>182
b1=lawsinside(A,a,B1)
b2=lawsinside(A,a,B2)
return [{"sides triangle 1":(a,b1,c),"angles traingle 1":(A,B1,C1)}, {"sides triangle 2":(a,b2,c),"angles triangle 2":(A,B2,C2)}]
#case 4:
#a>=c
#1 triangle
else:
C=lawsinangle(a,A,c)
B=180-A-C
b=lawsinside(A,a,B)
assert not A+B+C>182
return [{"sides":(a,b,c),"angles":(A,B,C)}]
#main program
def main():
"""Start the program"""
again=True
print("""Welcome to the Triangle Solver!
Here, you will be able to solve a triangle in SSS, ASA, SSA, AAS, SAS forms.
Type in a form, and press enter to begin.
""")
while again:
type=input("Form:\t")
#SSS
if type=="SSS":
print("\nYou picked SSS. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultdict=SSS(nums[0],nums[1],nums[2])
resultdict["angles"]=[deg(ang) for ang in resultdict["angles"]]
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"])
#ASA
elif type=="ASA":
print("\nYou picked ASA. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultdict=ASA(nums[0],nums[1],nums[2])
resultdict["angles"]=[deg(ang) for ang in resultdict["angles"]]
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"])
#SSA
elif type=="SSA":
print("\nYou picked SSA. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultlist=SSA(nums[0],nums[1],nums[2])
if len(resultlist)==0:
print("\nThere are no triangles that fit these specifications")
elif len(resultlist)==1:
resultdict=resultlist[0]
resultdict["angles"]=[deg(ang) for ang in resultdict["angles"]]
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"])
else:
resultdict1=resultlist[0]
resultdict1["angles"]=[deg(ang) for ang in resultdict1["angles"]]
resultdict2=resultlist[1]
resultdict2["angles"]=[deg(ang) for ang in resultdict2["angles"]]
print("\nsides:\t ", resultdict1["sides"], " \nangles:\t ", resultdict1["angles"])
print("sides:\t ", resultdict2["sides"], " \nangles:\t ", resultdict2["angles"])
#AAS
elif type=="AAS":
print("\nYou picked AAS. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultdict=AAS(nums[0],nums[1],nums[2])
resultdict["angles"]=[deg(ang) for ang in resultdict["angles"]]
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"])
#SAS
elif type=="SAS":
print("\nYou picked SAS. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultdict=SAS(nums[0],nums[1],nums[2])
resultdict["angles"]=[deg(ang) for ang in resultdict["angles"]]
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"])
#Catch-all for bugs
else:
print("I could not recognize this request.\n")
again=askyesno()
#start of program
main()
When run, the angle measurements return outrageous values in the high 2-4 thousands, and the assert statements are failing. I'm pretty sure there is a more efficient method for parsing and synthesizing the input, but the method I have now works.
Thanks in advance,
Jared
The problem is that you convert twice the angles to degrees. For example the part if type == "SSS" should look like
if type=="SSS":
print("\nYou picked SSS. Type in each number, seperated by a space\n")
nums=input("Numbers:\t").split()
nums=[float(eval(i)) for i in nums]
resultdict=SSS(nums[0],nums[1],nums[2])
# LINE SUPPRESSED
print("\nsides:\t ", resultdict["sides"], " \nangles:\t ", resultdict["angles"]) Another problem is that you are indenting your code with tab characters instead of spaces. It's a bad habit in python, so PLEASE, configure your editor to insert 4 spaces instead of a tab when you hit the tab key.
I fixed the command line bug, and it works perfectly. I've tried upgrading the program to tkinter, and it seems to be riddled with bugs.
#triangle solver GUI
from tkinter import *
from math import *
#law of cosines, for angle and side
def lawcosside(a,b,C):
"""Law of cosines, solving side C"""
return (a**2+b**2-2*a*b*cos(C))**.5
def lawcosangle(a,b,c):
"""Law of cosines, solving for angle C"""
return acos((a**2+b**2-c**2)/(2*a*b))
#law of sines, for missing angle and side:
def lawsinside(A,a,B):
"""Law of sines, solving for side b"""
return (a*sin(B))/sin(A)
def lawsinangle(a,A,b):
"""Law of sines, solving for angle B"""
return asin((b*sin(A))/a)
#class for GUI
class Application(Frame):
"""GUI Application for solving triangles"""
def __init__(self,master):
"""Creates Frame as master, forces grid, and holds everything together"""
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Creates widgets"""
Label(self,
text="Choose type of triangle"
).grid(row=0, column=0, columnspan=6)
#Radio buttons SSS, SAS, ASA, AAS, SSA
self.tri_form=StringVar()
self.tri_form.set(None)
counter=0
tri_list=["SSS","SAS","ASA","AAS","SSA"]
for a in tri_list:
Radiobutton(self,
text=a,
variable=self.tri_form,
value=a,
command=self.change_labels
).grid(row=1, column=counter, columnspan=1)
counter+=1
#Entry Inputs
Label(self,
text="Insert inputs:"
).grid(row=2, column=0, columnspan=6)
self.input_1_lbl=Label(self,
text="Side A"
).grid(row=3, column=0, columnspan=1)
self.input_1_entry=Entry(self)
self.input_1_entry.grid(row=3, column=1, columnspan=1)
self.input_2_lbl=Label(self,
text="Side B"
).grid(row=3, column=2, columnspan=1)
self.input_2_entry=Entry(self)
self.input_2_entry.grid(row=3, column=3, columnspan=1)
self.input_3_lbl=Label(self,
text="Side C"
).grid(row=3, column=4, columnspan=1)
self.input_3_entry=Entry(self)
self.input_3_entry.grid(row=3, column=5, columnspan=1)
#Angle type radio buttons
self.ang_type=StringVar()
self.ang_type.set(None)
Radiobutton(self,
text="Radians",
variable=self.ang_type,
value="Radians",
command=self.calculate_output
).grid(row=4, column=0, columnspan=3)
Radiobutton(self,
text="Degrees",
variable=self.ang_type,
value="Degrees",
command=self.calculate_output
).grid(row=4, column=3, columnspan=3)
#Triangle 1:
self.output_1_tri_1_lbl=Label(self,
text="Angle A"
).grid(row=5, column=0, columnspan=1)
self.output1_tri_1_entry=Entry(self)
self.output1_tri_1_entry.grid(row=5, column=1, columnspan=1)
self.output2_tri_1_lbl=Label(self,
text="Angle B"
).grid(row=5, column=2, columnspan=1)
self.output2_tri_1_entry=Entry(self)
self.output2_tri_1_entry.grid(row=5, column=3, columnspan=1)
self.output3_tri_1_lbl=Label(self,
text="Angle C"
).grid(row=5, column=4, columnspan=1)
self.output3_tri_1_entry=Entry(self)
self.output3_tri_1_entry.grid(row=5, column=5, columnspan=1)
#Triangle 2:
self.output_1_tri_2_lbl=Label(self,
text="Nonexistent"
).grid(row=6, column=0, columnspan=1)
self.output1_tri_2_entry=Entry(self)
self.output1_tri_2_entry.grid(row=6, column=1, columnspan=1)
self.output2_tri_2_lbl=Label(self,
text="Nonexistent"
).grid(row=6, column=2, columnspan=1)
self.output2_tri_2_entry=Entry(self)
self.output2_tri_2_entry.grid(row=6, column=3, columnspan=1)
self.output3_tri_2_lbl=Label(self,
text="Nonexistent"
).grid(row=6, column=4, columnspan=1)
self.output3_tri_2_entry=Entry(self)
self.output3_tri_2_entry.grid(row=6, column=5, columnspan=1)
"""
Key for later
Variables
self.tri_form: form of triangle
self.ang_type: angles in radians or degrees
Input:
self.input_x_lbl x is from 1-3: label for input
self.input_x_entry x if from 1-3: entry for input
Output:
self.outputx_tri_y_lbl x is from 1-3, outputs, y is from 1-2, triangles: label
self.outputx_tri_y_entry x is from 1-3, outputs, y is from 1-2, triangles: entry
"""
def change_labels(self):
"""Changes labels of input and output boxes"""
form=self.tri_form.get()
if form=="SSS":
inputlist=["Side a", "Side b", "Side c"]
outputlist=["Angle A", "Angle B", "Angle C"]
elif form=="SAS":
inputlist=["Side a", "Angle B", "Side c"]
outputlist=["Angle A", "Side b", "Angle C"]
elif form=="AAS":
inputlist=["Angle A", "Angle B", "Side a"]
outputlist=["Side c", "Side b", "Angle C"]
elif form=="ASA":
inputlist=["Angle A", "Side c", "Angle B"]
outputlist=["Side a", "Angle C", "Side b"]
elif form=="SSA":
inputlist=["Side c", "Side a", "Angle A"]
outputlist=["Angle C", "Angle B", "Side b"]
self.input_1_lbl.config(text=inputlist[0])
self.input_2_lbl.config(text=inputlist[1])
self.input_3_lbl.config(text=inputlist[2])
self.output_1_tri_1_lbl.config(text=outputlist[0])
self.output_2_tri_1_lbl.config(text=outputlist[1])
self.output_3_tri_1_lbl.config(text=outputlist[2])
self.output_1_tri_2_lbl.config(text="Nonexistent")
self.output_2_tri_2_lbl.config(text="Nonexistent")
self.output_3_tri_2_lbl.config(text="Nonexistent")
counter=1
while counter<=3:
eval("self.input_{0}_entry".format(repr(counter))).delete(0.0, END)
eval("self.output"+repr(counter)+"_tri_1_entry" ).delete(0.0, END)
eval("self.output"+repr(counter)+"_tri_2_entry").delete(0.0, END)
counter+=1
counter=1
if form=="SSA":
while counter<=3:
eval("self.output"+repr(counter)+"_tri_2_lbl").config(text=eval("self.output"+repr(counter)+"_tri_1_lbl")['text'])
counter+=1
def calculate_output(self):
"""Calculates output, using mathematical formulae"""
form=self.tri_form.get()
ang_type=self.ang_type.get()
input_1=float(self.input_1_entry.get())
input_2=float(self.input_2_entry.get())
input_3=float(self.input_3_entry.get())
if form=="SSS":
a,b,c=input_1, input_2, input_3
A,B=lawcosangle(b,c,a),lawcosangle(c,a,b)
C=pi-A-B
if ang_type=="Degrees":
A,B,C=degrees(A),degrees(B),degrees(C)
output_1,output_2,output_3=A,B,C
output_1a,output_2a,output_3a=None,None,None
elif form=="SAS":
a,B,c=input_1,input_2,input_3
if ang_type=="Degrees":
B=radians(B)
b,A=lawcosside(a,c,B),lawsinside(b,B,a)
C=pi-A-B
if ang_type=="Degrees":
A,B,C=degrees(A),degrees(B),degrees(C)
output_1,output_2,output_3=A,b,C
output_1a,output_2a,output_3a=None,None,None
elif form=="AAS":
A,B,a=input_1,input_2,input_3
if ang_type=="Degrees":
A,B=radians(A),radians(B)
b,c=lawsinside(A,a,B),lawsinside(A,a,C)
C=pi-A-B
if ang_type=="Degrees":
A,B,C=degrees(A),degrees(B),degrees(C)
output_1,output_2,output_3=c, b, C
output_1a,output_2a,output_3a=None,None,None
elif form=="ASA":
A,c,B=input_1,input_2, input_3
if ang_type=="Degrees":
A,B=radians(A),(B)
a,b,C=lawsinside(C,c,A),lawsinside(C,c,B),(pi-A-B)
if ang_type=="Degrees":
A,B,C=degrees(A),degrees(B),degrees(C)
output_1,output_2,output_3=a,C,b
output_1a,output_2a,output_3a=None,None,None
elif form=="SSA":
c,a,A=input_1,input_2,input_3
if ang_type=="Degrees":
A=radians(A)
h=c*sin(A)
#case 1
#h>a
#0 triangles
if h<a:
output_1,output_2,output_3=None,None,None
output_1a,output_2a,output_3a=None,None,None
#case 2
#h=a
#1 triangle
elif h==a:
C=pi
B=pi-A-C
b=lawsinside(A,a,B)
if ang_type=="Degrees":
C,B=degrees(C),degrees(B)
output_1,output_2,output_3=C,B,b
output_1a,output_2a,output_3a=None,None,None
#case 3
#h<a<c
#2 triangles
elif h<a and a<c:
C1a=lawsinangle(a,A,c)
C2a=pi-C1a
if C1a>C2a:
C1,C2=C1a,C2a
else:
C1,C2=C2a,C1a
B1=pi-A-C1
B2=pi-A-C2
b1=lawsinside(A,a,B1)
b2=lawsinside(A,a,B2)
if ang_type=="Degrees":
B1,B2,C1,C2=degrees(B1),degrees(B2),degrees(C1),degrees(C2)
output_1,output_2,output_3=C1,B1,b1
output_1a,output_2a,output_3a=C2,B2,b2
#case 4
#a>=c
#1 triangle
elif a>=c:
C=lawsinangle(a,A,c)
B=pi-A-C
b=lawsinside(A,a,B)
if ang_type=="Degrees":
C,B=degrees(C),degrees(B)
output_1,output_2,output_3=C,B,b
output_1a,output_2a,output_3a=None,None,None
self.output_1,self.output_2,self.output_3,self.output_1a,self.output_2a,self.output_3a=output_1,output_2,output_3,output_1a,output_2a,output_3a
self.display_output()
def display_output(self):
"""Displays output, based on calculations from calculate_output"""
for a in [self.output_1,self.output_2,self.output_3,self.output_1a,self.output_2a,self.output_3a]:
if a==None:
a="Nonexistent"
self.output1_tri1_entry.insert(0.0,self.output_1)
self.output2_tri1_entry.insert(0.0,self.output_2)
self.output3_tri1_entry.insert(0.0,self.output_3)
self.output1_tri2_entry.insert(0.0,self.output_1a)
self.output2_tri2_entry.insert(0.0,self.output_2a)
self.output3_tri2_entry.insert(0.0,self.output_3a)
#Starts Gui
root=Tk()
root.title=("Triangle solver 2.0")
app=Application(root)
root.mainloop()At least you should store label before doing .grid:
self.input_1_lbl=Label(self,
text="Side A"
).grid(row=3, column=0, columnspan=1)
print('Created', self.input_1_lbl) Output
Created None