Code

Adding Triangle Extension - See LP#226001
authorozmikepittman <ozmikepittman@users.sourceforge.net>
Sat, 3 May 2008 22:17:07 +0000 (22:17 +0000)
committerozmikepittman <ozmikepittman@users.sourceforge.net>
Sat, 3 May 2008 22:17:07 +0000 (22:17 +0000)
po/POTFILES.in
share/extensions/Makefile.am
share/extensions/triangle.inx [new file with mode: 0644]
share/extensions/triangle.py [new file with mode: 0644]

index b470693924cc761437e3588fdd9c8f6696b2707d..5ea99dc8120be1b62b0404c88d1c38d3d8cb3ca2 100644 (file)
@@ -396,6 +396,7 @@ src/winmain.cpp
 [type: gettext/xml] share/extensions/text_titlecase.inx
 [type: gettext/xml] share/extensions/text_uppercase.inx
 [type: gettext/xml] share/extensions/txt2svg.inx
+[type: gettext/xml] share/extensions/triangle.inx
 [type: gettext/xml] share/extensions/whirl.inx
 [type: gettext/xml] share/extensions/wmf_input.inx
 [type: gettext/xml] share/extensions/xaml2svg.inx
index b41b4a41798290b63c4dcf5788b013a1a66715d8..4544b086644635b10a81a5ecaa88ecec9e35fc1d 100644 (file)
@@ -104,6 +104,7 @@ extensions = \
        text_randomcase.py \
        text_replace.py \
        text_braille.py \
+       triangle.py \
        txt2svg.pl \
        uniconv-ext.py \
        whirl.py
@@ -208,6 +209,7 @@ modules = \
        text_randomcase.inx \
        text_replace.inx \
        text_braille.inx \
+       triangle.inx \
        txt2svg.inx \
        whirl.inx \
        wmf_input.inx \
diff --git a/share/extensions/triangle.inx b/share/extensions/triangle.inx
new file mode 100644 (file)
index 0000000..3e5748e
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">\r
+    <_name>Triangle</_name>\r
+    <id>math.triangle</id>\r
+    <dependency type="executable" location="extensions">triangle.py</dependency>\r
+    <dependency type="executable" location="extensions">inkex.py</dependency>\r
+    <param name="s_a"       type="float"   min="0.01" max="10000" _gui-text="Side Length a / px">100.0</param>\r
+    <param name="s_b"       type="float"   min="0.01" max="10000" _gui-text="Side Length b / px">100.0</param>\r
+    <param name="s_c"       type="float"   min="0.01" max="10000" _gui-text="Side Length c / px">100.0</param>\r
+    <param name="a_a"       type="float"   min="0"    max="180"   _gui-text="Angle a / deg">60</param>\r
+    <param name="a_b"       type="float"   min="0"    max="180"   _gui-text="Angle b / deg">30</param>\r
+    <param name="a_c"       type="float"   min="0"    max="180"   _gui-text="Angle c / deg">90</param>\r
+    <param name="mode"      type="optiongroup"                    _gui-text="Mode">\r
+        <_option value="3_sides">From Three Sides</_option>\r
+        <_option value="s_ab_a_c">From Sides a, b and Angle c</_option>\r
+        <_option value="s_ab_a_a">From Sides a, b and Angle a</_option>\r
+        <_option value="s_a_a_ab">From Side a and Angles a, b</_option>\r
+        <_option value="s_c_a_ab">From Side c and Angles a, b</_option></param>\r
+    <effect>\r
+        <object-type>all</object-type>\r
+                <effects-menu>\r
+                    <submenu _name="Render"/>\r
+                </effects-menu>\r
+    </effect>\r
+    <script>\r
+        <command reldir="extensions" interpreter="python">triangle.py</command>\r
+    </script>\r
+</inkscape-extension>
\ No newline at end of file
diff --git a/share/extensions/triangle.py b/share/extensions/triangle.py
new file mode 100644 (file)
index 0000000..22c8633
--- /dev/null
@@ -0,0 +1,194 @@
+#!/usr/bin/env python 
+'''
+Copyright (C) 2007 John Beard john.j.beard@gmail.com
+
+##This extension allows you to draw a triangle given certain information
+## about side length or angles.
+
+##Measurements of the triangle
+
+         C(x_c,y_c)                              
+        /`__                                     
+       / a_c``--__                               
+      /           ``--__ s_a                     
+ s_b /                  ``--__                   
+    /a_a                    a_b`--__             
+   /--------------------------------``B(x_b, y_b)
+  A(x_a,y_a)         s_b                         
+
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+'''\r
+
+import inkex
+import simplestyle, sys
+from math import *
+
+def draw_SVG_tri( (x1, y1), (x2, y2), (x3, y3), (ox,oy), width, name, parent):
+    style = { 'stroke': '#000000', 'stroke-width':str(width), 'fill': 'none' }
+    tri_attribs = {'style':simplestyle.formatStyle(style),
+                    'inkscape:label':name,
+                    'd':'M '+str(x1+ox)+','+str(y1+oy)+
+                       ' L '+str(x2+ox)+','+str(y2+oy)+
+                       ' L '+str(x3+ox)+','+str(y3+oy)+
+                       ' L '+str(x1+ox)+','+str(y1+oy)+' z'}
+    inkex.etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs )
+    
+def angle_from_3_sides(a, b, c): #return the angle opposite side c
+    cosx = (a*a + b*b - c*c)/(2*a*b)  #use the cosine rule
+    return acos(cosx)
+
+def third_side_from_enclosed_angle(s_a,s_b,a_c): #return the side opposite a_c
+    c_squared = s_a*s_a + s_b*s_b -2*s_a*s_b*cos(a_c)
+    if c_squared > 0:
+        return sqrt(c_squared)
+    else:
+        return 0 #means we have an invalid or degenerate triangle (zero is caught at the drawing stage)
+
+def pt_on_circ(radius, angle): #return the x,y coordinate of the polar coordinate
+    x = radius * cos(angle)
+    y = radius * sin(angle)
+    return [x, y]
+
+def v_add( (x1,y1),(x2,y2) ):#add an offset to coordinates
+    return [x1+x2, y1+y2]
+
+def is_valid_tri_from_sides(a,b,c):#check whether triangle with sides a,b,c is valid
+    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
+                #no zero-length sides, no degenerate case
+
+def draw_tri_from_3_sides(s_a, s_b, s_c, offset, parent): #draw a triangle from three sides (with a given offset
+    if is_valid_tri_from_sides(s_a,s_b,s_c):
+        a_b = angle_from_3_sides(s_a, s_c, s_b)
+                
+        a = (0,0)    #a is the origin
+        b = v_add(a, (s_c, 0)) #point B is horizontal from the origin
+        c = v_add(b, pt_on_circ(s_a, pi-a_b) ) #get point c
+        c[1] = -c[1]
+        
+        offx = max(b[0],c[0])/2 #b or c could be the furthest right
+        offy = c[1]/2 #c is the highest point
+        offset = ( offset[0]-offx , offset[1]-offy ) #add the centre of the triangle to the offset
+               
+        draw_SVG_tri(a, b, c , offset, 2, 'Triangle', parent)
+    else:
+        sys.stderr.write('Error:Invalid Triangle Specifications.\n')
+
+class Grid_Polar(inkex.Effect):
+    def __init__(self):
+        inkex.Effect.__init__(self)
+        self.OptionParser.add_option("--s_a",
+                        action="store", type="float", 
+                        dest="s_a", default=100.0,
+                        help="Side Length a")
+        self.OptionParser.add_option("--s_b",
+                        action="store", type="float", 
+                        dest="s_b", default=100.0,
+                        help="Side Length b")
+        self.OptionParser.add_option("--s_c",
+                        action="store", type="float", 
+                        dest="s_c", default=100.0,
+                        help="Side Length c")
+        self.OptionParser.add_option("--a_a",
+                        action="store", type="float", 
+                        dest="a_a", default=60.0,
+                        help="Angle a")
+        self.OptionParser.add_option("--a_b",
+                        action="store", type="float", 
+                        dest="a_b", default=30.0,
+                        help="Angle b")
+        self.OptionParser.add_option("--a_c",
+                        action="store", type="float", 
+                        dest="a_c", default=90.0,
+                        help="Angle c")
+        self.OptionParser.add_option("--mode",
+                        action="store", type="string", 
+                        dest="mode", default='3_sides',
+                        help="Side Length c")
+    
+    def effect(self):
+        
+        tri = self.current_layer
+        offset = (self.view_center[0],self.view_center[1]) #the offset require to centre the triangle
+        
+        if self.options.mode == '3_sides':
+            s_a = self.options.s_a
+            s_b = self.options.s_b
+            s_c = self.options.s_c
+            draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+        
+        elif self.options.mode == 's_ab_a_c':
+            s_a = self.options.s_a
+            s_b = self.options.s_b
+            a_c = self.options.a_c*pi/180 #in rad
+            
+            s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
+            draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+        
+        elif self.options.mode == 's_ab_a_a':
+            s_a = self.options.s_a
+            s_b = self.options.s_b
+            a_a = self.options.a_a*pi/180 #in rad
+            
+            if (a_a < pi/2.0) and (s_a < s_b) and (s_a > s_b*sin(a_a) ): #this is an ambigous case
+                ambiguous=True#we will give both answers
+            else:
+                ambiguous=False
+            
+            sin_a_b =  s_b*sin(a_a)/s_a
+            
+            if (sin_a_b <= 1) and (sin_a_b >= -1):#check the solution is possible
+                a_b = asin(sin_a_b) #acute solution
+                a_c = pi - a_a - a_b
+                error=False
+            else:
+                sys.stderr.write('Error:Invalid Triangle Specifications.\n')#signal an error
+                error=True
+            
+            if not(error) and (a_b < pi) and (a_c < pi): #check that the solution is valid, if so draw acute solution
+                s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
+                draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+            
+            if not(error) and ((a_b > pi) or (a_c > pi) or ambiguous):#we want the obtuse solution
+                a_b = pi - a_b
+                a_c = pi - a_a - a_b
+                s_c = third_side_from_enclosed_angle(s_a,s_b,a_c)
+                draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+        
+        elif self.options.mode == 's_a_a_ab':
+            s_a = self.options.s_a
+            a_a = self.options.a_a*pi/180 #in rad
+            a_b = self.options.a_b*pi/180 #in rad
+            
+            a_c = pi - a_a - a_b
+            s_b = s_a*sin(a_b)/sin(a_a)
+            s_c = s_a*sin(a_c)/sin(a_a)
+            
+            draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+        
+        elif self.options.mode == 's_c_a_ab':
+            s_c = self.options.s_c
+            a_a = self.options.a_a*pi/180 #in rad
+            a_b = self.options.a_b*pi/180 #in rad
+            
+            a_c = pi - a_a - a_b
+            s_a = s_c*sin(a_a)/sin(a_c)
+            s_b = s_c*sin(a_b)/sin(a_c)
+            
+            draw_tri_from_3_sides(s_a, s_b, s_c, offset, tri)
+
+e = Grid_Polar()
+e.affect()
+