Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / share / extensions / triangle.py
1 #!/usr/bin/env python 
2 '''
3 Copyright (C) 2007 John Beard john.j.beard@gmail.com
5 ##This extension allows you to draw a triangle given certain information
6 ## about side length or angles.
8 ##Measurements of the triangle
10          C(x_c,y_c)                              
11         /`__                                     
12        / a_c``--__                               
13       /           ``--__ s_a                     
14  s_b /                  ``--__                   
15     /a_a                    a_b`--__             
16    /--------------------------------``B(x_b, y_b)
17   A(x_a,y_a)         s_b                         
20 This program is free software; you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 2 of the License, or
23 (at your option) any later version.
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28 GNU General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33 '''
35 import inkex
36 import simplestyle, sys
37 from math import *
39 def draw_SVG_tri( (x1, y1), (x2, y2), (x3, y3), (ox,oy), width, name, parent):
40     style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' }
41     tri_attribs = {'style':simplestyle.formatStyle(style),
42                     inkex.addNS('label','inkscape'):name,
43                     'd':'M '+str(x1+ox)+','+str(y1+oy)+
44                        ' L '+str(x2+ox)+','+str(y2+oy)+
45                        ' L '+str(x3+ox)+','+str(y3+oy)+
46                        ' L '+str(x1+ox)+','+str(y1+oy)+' z'}
47     inkex.etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs )
48     
49 def angle_from_3_sides(a, b, c): #return the angle opposite side c
50     cosx = (a*a + b*b - c*c)/(2*a*b)  #use the cosine rule
51     return acos(cosx)
53 def third_side_from_enclosed_angle(s_a,s_b,a_c): #return the side opposite a_c
54     c_squared = s_a*s_a + s_b*s_b -2*s_a*s_b*cos(a_c)
55     if c_squared > 0:
56         return sqrt(c_squared)
57     else:
58         return 0 #means we have an invalid or degenerate triangle (zero is caught at the drawing stage)
60 def pt_on_circ(radius, angle): #return the x,y coordinate of the polar coordinate
61     x = radius * cos(angle)
62     y = radius * sin(angle)
63     return [x, y]
65 def v_add( (x1,y1),(x2,y2) ):#add an offset to coordinates
66     return [x1+x2, y1+y2]
68 def is_valid_tri_from_sides(a,b,c):#check whether triangle with sides a,b,c is valid
69     return (a+b)>c and (a+c)>b and (b+c)>a and a > 0 and b> 0 and c>0#two sides must always be greater than the third
70                 #no zero-length sides, no degenerate case
72 def draw_tri_from_3_sides(s_a, s_b, s_c, offset, parent): #draw a triangle from three sides (with a given offset
73     if is_valid_tri_from_sides(s_a,s_b,s_c):
74         a_b = angle_from_3_sides(s_a, s_c, s_b)
75                 
76         a = (0,0)    #a is the origin
77         b = v_add(a, (s_c, 0)) #point B is horizontal from the origin
78         c = v_add(b, pt_on_circ(s_a, pi-a_b) ) #get point c
79         c[1] = -c[1]
80         
81         offx = max(b[0],c[0])/2 #b or c could be the furthest right
82         offy = c[1]/2 #c is the highest point
83         offset = ( offset[0]-offx , offset[1]-offy ) #add the centre of the triangle to the offset
84                
85         draw_SVG_tri(a, b, c , offset, 2, 'Triangle', parent)
86     else:
87         sys.stderr.write('Error:Invalid Triangle Specifications.\n')
89 class Grid_Polar(inkex.Effect):
90     def __init__(self):
91         inkex.Effect.__init__(self)
92         self.OptionParser.add_option("--s_a",
93                         action="store", type="float", 
94                         dest="s_a", default=100.0,
95                         help="Side Length a")
96         self.OptionParser.add_option("--s_b",
97                         action="store", type="float", 
98                         dest="s_b", default=100.0,
99                         help="Side Length b")
100         self.OptionParser.add_option("--s_c",
101                         action="store", type="float", 
102                         dest="s_c", default=100.0,
103                         help="Side Length c")
104         self.OptionParser.add_option("--a_a",
105                         action="store", type="float", 
106                         dest="a_a", default=60.0,
107                         help="Angle a")
108         self.OptionParser.add_option("--a_b",
109                         action="store", type="float", 
110                         dest="a_b", default=30.0,
111                         help="Angle b")
112         self.OptionParser.add_option("--a_c",
113                         action="store", type="float", 
114                         dest="a_c", default=90.0,
115                         help="Angle c")
116         self.OptionParser.add_option("--mode",
117                         action="store", type="string", 
118                         dest="mode", default='3_sides',
119                         help="Side Length c")
120     
121     def effect(self):
122         
123         tri = self.current_layer
124         offset = (self.view_center[0],self.view_center[1]) #the offset require to centre the triangle
125         
126         if self.options.mode == '3_sides':
127             s_a = self.options.s_a
128             s_b = self.options.s_b
129             s_c = self.options.s_c
130             draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
131         
132         elif self.options.mode == 's_ab_a_c':
133             s_a = self.options.s_a
134             s_b = self.options.s_b
135             a_c = self.options.a_c*pi/180 #in rad
136             
137             s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
138             draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
139         
140         elif self.options.mode == 's_ab_a_a':
141             s_a = self.options.s_a
142             s_b = self.options.s_b
143             a_a = self.options.a_a*pi/180 #in rad
144             
145             if (a_a < pi/2.0) and (s_a < s_b) and (s_a > s_b*sin(a_a) ): #this is an ambigous case
146                 ambiguous=True#we will give both answers
147             else:
148                 ambiguous=False
149             
150             sin_a_b =  s_b*sin(a_a)/s_a
151             
152             if (sin_a_b <= 1) and (sin_a_b >= -1):#check the solution is possible
153                 a_b = asin(sin_a_b) #acute solution
154                 a_c = pi - a_a - a_b
155                 error=False
156             else:
157                 sys.stderr.write('Error:Invalid Triangle Specifications.\n')#signal an error
158                 error=True
159             
160             if not(error) and (a_b < pi) and (a_c < pi): #check that the solution is valid, if so draw acute solution
161                 s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
162                 draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
163             
164             if not(error) and ((a_b > pi) or (a_c > pi) or ambiguous):#we want the obtuse solution
165                 a_b = pi - a_b
166                 a_c = pi - a_a - a_b
167                 s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
168                 draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
169         
170         elif self.options.mode == 's_a_a_ab':
171             s_a = self.options.s_a
172             a_a = self.options.a_a*pi/180 #in rad
173             a_b = self.options.a_b*pi/180 #in rad
174             
175             a_c = pi - a_a - a_b
176             s_b = s_a*sin(a_b)/sin(a_a)
177             s_c = s_a*sin(a_c)/sin(a_a)
178             
179             draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
180         
181         elif self.options.mode == 's_c_a_ab':
182             s_c = self.options.s_c
183             a_a = self.options.a_a*pi/180 #in rad
184             a_b = self.options.a_b*pi/180 #in rad
185             
186             a_c = pi - a_a - a_b
187             s_a = s_c*sin(a_a)/sin(a_c)
188             s_b = s_c*sin(a_b)/sin(a_c)
189             
190             draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
192 if __name__ == '__main__':
193     e = Grid_Polar()
194     e.affect()
197 # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99