home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Inkscape / Inkscape-0.48.2-1-win32.exe / share / extensions / draw_from_triangle.py < prev    next >
Encoding:
Python Source  |  2011-07-08  |  22.0 KB  |  475 lines

  1. #!/usr/bin/env python 
  2. '''
  3. Copyright (C) 2007 John Beard john.j.beard@gmail.com
  4.  
  5. ##This extension allows you to draw various triangle constructions
  6. ##It requires a path to be selected
  7. ##It will use the first three nodes of this path
  8.  
  9. ## Dimensions of a triangle__
  10. #
  11. #        /`__
  12. #       / a_c``--__
  13. #      /           ``--__ s_a
  14. # s_b /                  ``--__
  15. #    /a_a                    a_b`--__  
  16. #   /--------------------------------``B
  17. #  A              s_b
  18.  
  19. This program is free software; you can redistribute it and/or modify
  20. it under the terms of the GNU General Public License as published by
  21. the Free Software Foundation; either version 2 of the License, or
  22. (at your option) any later version.
  23.  
  24. This program is distributed in the hope that it will be useful,
  25. but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27. GNU General Public License for more details.
  28.  
  29. You should have received a copy of the GNU General Public License
  30. along with this program; if not, write to the Free Software
  31. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  32. '''
  33.  
  34. import inkex
  35. import simplestyle, sys, simplepath
  36. from math import *
  37. import gettext
  38. _ = gettext.gettext
  39.  
  40. #DRAWING ROUTINES
  41.  
  42. #draw an SVG triangle given in trilinar coords
  43. def draw_SVG_circle(rad, centre, params, style, name, parent):#draw an SVG circle with a given radius as trilinear coordinates
  44.     if rad == 0: #we want a dot
  45.         r = style.d_rad #get the dot width from the style
  46.         circ_style = { 'stroke':style.d_col, 'stroke-width':str(style.d_th), 'fill':style.d_fill }
  47.     else:
  48.         r = rad #use given value
  49.         circ_style = { 'stroke':style.c_col, 'stroke-width':str(style.c_th), 'fill':style.c_fill }
  50.  
  51.     cx,cy = get_cartesian_pt(centre, params)
  52.     circ_attribs = {'style':simplestyle.formatStyle(circ_style),
  53.                     inkex.addNS('label','inkscape'):name,
  54.                     'cx':str(cx), 'cy':str(cy), 
  55.                     'r':str(r)}
  56.     inkex.etree.SubElement(parent, inkex.addNS('circle','svg'), circ_attribs )
  57.  
  58. #draw an SVG triangle given in trilinar coords
  59. def draw_SVG_tri(vert_mat, params, style, name, parent):
  60.     p1,p2,p3 = get_cartesian_tri(vert_mat, params) #get the vertex matrix in cartesian points
  61.     tri_style   = { 'stroke': style.l_col, 'stroke-width':str(style.l_th), 'fill': style.l_fill }
  62.     tri_attribs = {'style':simplestyle.formatStyle(tri_style),
  63.                     inkex.addNS('label','inkscape'):name,
  64.                     'd':'M '+str(p1[0])+','+str(p1[1])+
  65.                        ' L '+str(p2[0])+','+str(p2[1])+
  66.                        ' L '+str(p3[0])+','+str(p3[1])+
  67.                        ' L '+str(p1[0])+','+str(p1[1])+' z'}
  68.     inkex.etree.SubElement(parent, inkex.addNS('path','svg'), tri_attribs )
  69.  
  70. #draw an SVG line segment between the given (raw) points
  71. def draw_SVG_line( (x1, y1), (x2, y2), style, name, parent):
  72.     line_style   = { 'stroke': style.l_col, 'stroke-width':str(style.l_th), 'fill': style.l_fill }
  73.     line_attribs = {'style':simplestyle.formatStyle(line_style),
  74.                     inkex.addNS('label','inkscape'):name,
  75.                     'd':'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
  76.     inkex.etree.SubElement(parent, inkex.addNS('path','svg'), line_attribs )
  77.  
  78. #lines from each vertex to a corresponding point in trilinears
  79. def draw_vertex_lines( vert_mat, params, width, name, parent):
  80.     for i in range(3):
  81.         oppositepoint = get_cartesian_pt( vert_mat[i], params)
  82.         draw_SVG_line(params[3][-i%3], oppositepoint, width, name+':'+str(i), parent)
  83.         
  84. #MATHEMATICAL ROUTINES
  85.  
  86. def distance( (x0,y0),(x1,y1)):#find the pythagorean distance
  87.     return sqrt( (x0-x1)*(x0-x1) + (y0-y1)*(y0-y1) )
  88.  
  89. def vector_from_to( (x0,y0),(x1,y1) ):#get the vector from (x0,y0) to (x1,y1)
  90.     return (x1-x0, y1-y0)
  91.  
  92. def get_cartesian_pt( t, p):#get the cartesian coordinates from a trilinear set
  93.     denom = p[0][0]*t[0] + p[0][1]*t[1] + p[0][2]*t[2]
  94.     c1 = p[0][1]*t[1]/denom
  95.     c2 = p[0][2]*t[2]/denom
  96.     return ( c1*p[2][1][0]+c2*p[2][0][0], c1*p[2][1][1]+c2*p[2][0][1] )
  97.  
  98. def get_cartesian_tri( ((t11,t12,t13),(t21,t22,t23),(t31,t32,t33)), params):#get the cartesian points from a trilinear vertex matrix
  99.     p1=get_cartesian_pt( (t11,t12,t13), params )
  100.     p2=get_cartesian_pt( (t21,t22,t23), params )
  101.     p3=get_cartesian_pt( (t31,t32,t33), params )
  102.     return (p1,p2,p3)
  103.  
  104. def angle_from_3_sides(a, b, c): #return the angle opposite side c
  105.     cosx = (a*a + b*b - c*c)/(2*a*b)  #use the cosine rule
  106.     return acos(cosx)
  107.     
  108. def translate_string(string, os): #translates s_a, a_a, etc to params[x][y], with cyclic offset
  109.     string = string.replace('s_a', 'params[0]['+str((os+0)%3)+']') #replace with ref. to the relvant values,
  110.     string = string.replace('s_b', 'params[0]['+str((os+1)%3)+']') #cycled by i
  111.     string = string.replace('s_c', 'params[0]['+str((os+2)%3)+']')
  112.     string = string.replace('a_a', 'params[1]['+str((os+0)%3)+']')
  113.     string = string.replace('a_b', 'params[1]['+str((os+1)%3)+']')
  114.     string = string.replace('a_c', 'params[1]['+str((os+2)%3)+']')
  115.     string = string.replace('area','params[4][0]')
  116.     string = string.replace('semiperim','params[4][1]')
  117.     return string
  118.  
  119. def pt_from_tcf( tcf , params):#returns a trilinear triplet from a triangle centre function
  120.     trilin_pts=[]#will hold the final points
  121.     for i in range(3):
  122.         temp = tcf #read in the tcf
  123.         temp = translate_string(temp, i)
  124.         func = eval('lambda params: ' + temp.strip('"')) #the function leading to the trilinar element
  125.         trilin_pts.append(func(params))#evaluate the function for the first trilinear element
  126.     return trilin_pts
  127.     
  128. #SVG DATA PROCESSING
  129.     
  130. def get_n_points_from_path( node, n):#returns a list of first n points (x,y) in an SVG path-representing node
  131.  
  132.     p = simplepath.parsePath(node.get('d')) #parse the path
  133.     
  134.     xi = [] #temporary storage for x and y (will combine at end)
  135.     yi = []
  136.     
  137.     for cmd,params in p:                    #a parsed path is made up of (cmd, params) pairs
  138.         defs = simplepath.pathdefs[cmd]
  139.         for i in range(defs[1]):
  140.             if   defs[3][i] == 'x' and len(xi) < n:#only collect the first three
  141.                 xi.append(params[i])
  142.             elif defs[3][i] == 'y' and len(yi) < n:#only collect the first three
  143.                 yi.append(params[i])
  144.  
  145.     if len(xi) == n and len(yi) == n:
  146.         points = [] # returned pairs of points
  147.         for i in range(n):
  148.             points.append( [ xi[i], yi[i] ] )
  149.     else:
  150.         #inkex.errormsg(_('Error: Not enough nodes to gather coordinates.')) #fail silently and exit, rather than invoke an error console
  151.         return [] #return a blank
  152.         
  153.     return points
  154.     
  155. #EXTRA MATHS FUNCTIONS
  156. def sec(x):#secant(x)
  157.     if x == pi/2 or x==-pi/2 or x == 3*pi/2 or x == -3*pi/2: #sec(x) is undefined
  158.         return 100000000000
  159.     else:
  160.         return 1/cos(x)
  161.  
  162. def csc(x):#cosecant(x)
  163.     if x == 0 or x==pi or x==2*pi or x==-2*pi: #csc(x) is undefined
  164.         return 100000000000
  165.     else:
  166.         return 1/sin(x)
  167.  
  168. def cot(x):#cotangent(x)
  169.     if x == 0 or x==pi or x==2*pi or x==-2*pi: #cot(x) is undefined
  170.         return 100000000000
  171.     else:
  172.         return 1/tan(x)
  173.         
  174. def report_properties( params ):#report to the Inkscape console using errormsg
  175.     inkex.errormsg(_("Side Length 'a'/px: " + str( params[0][0] ) ))
  176.     inkex.errormsg(_("Side Length 'b'/px: " + str( params[0][1] ) ))
  177.     inkex.errormsg(_("Side Length 'c'/px: " + str( params[0][2] ) ))
  178.     inkex.errormsg(_("Angle 'A'/radians: " + str( params[1][0] ) ))
  179.     inkex.errormsg(_("Angle 'B'/radians: " + str( params[1][1] ) ))
  180.     inkex.errormsg(_("Angle 'C'/radians: " + str( params[1][2] ) ))
  181.     inkex.errormsg(_("Semiperimeter/px: " + str( params[4][1] ) ))
  182.     inkex.errormsg(_("Area /px^2: " + str( params[4][0] ) ))
  183.     return
  184.     
  185.  
  186. class Style(object): #container for style information
  187.     def __init__(self, options):
  188.         #dot markers
  189.         self.d_rad = 4 #dot marker radius
  190.         self.d_th  = 2 #stroke width
  191.         self.d_fill= '#aaaaaa' #fill colour
  192.         self.d_col = '#000000' #stroke colour
  193.  
  194.         #lines
  195.         self.l_th  = 2
  196.         self.l_fill= 'none'
  197.         self.l_col = '#000000'
  198.         
  199.         #circles
  200.         self.c_th  = 2
  201.         self.c_fill= 'none'
  202.         self.c_col = '#000000'
  203.  
  204. class Draw_From_Triangle(inkex.Effect):
  205.     def __init__(self):
  206.         inkex.Effect.__init__(self)
  207.         self.OptionParser.add_option("--tab",
  208.                         action="store", type="string", 
  209.                         dest="tab", default="sampling",
  210.                         help="The selected UI-tab when OK was pressed") 
  211. #PRESET POINT OPTIONS
  212.         self.OptionParser.add_option("--circumcircle",
  213.                         action="store", type="inkbool", 
  214.                         dest="do_circumcircle", default=False)
  215.         self.OptionParser.add_option("--circumcentre",
  216.                         action="store", type="inkbool", 
  217.                         dest="do_circumcentre", default=False)
  218.         self.OptionParser.add_option("--incircle",
  219.                         action="store", type="inkbool", 
  220.                         dest="do_incircle", default=False)
  221.         self.OptionParser.add_option("--incentre",
  222.                         action="store", type="inkbool", 
  223.                         dest="do_incentre", default=False)
  224.         self.OptionParser.add_option("--contact_tri",
  225.                         action="store", type="inkbool", 
  226.                         dest="do_contact_tri", default=False)
  227.         self.OptionParser.add_option("--excircles",
  228.                         action="store", type="inkbool", 
  229.                         dest="do_excircles", default=False)
  230.         self.OptionParser.add_option("--excentres",
  231.                         action="store", type="inkbool", 
  232.                         dest="do_excentres", default=False)
  233.         self.OptionParser.add_option("--extouch_tri",
  234.                         action="store", type="inkbool", 
  235.                         dest="do_extouch_tri", default=False)
  236.         self.OptionParser.add_option("--excentral_tri",
  237.                         action="store", type="inkbool", 
  238.                         dest="do_excentral_tri", default=False)
  239.         self.OptionParser.add_option("--orthocentre",
  240.                         action="store", type="inkbool", 
  241.                         dest="do_orthocentre", default=False)
  242.         self.OptionParser.add_option("--orthic_tri",
  243.                         action="store", type="inkbool", 
  244.                         dest="do_orthic_tri", default=False)
  245.         self.OptionParser.add_option("--altitudes",
  246.                         action="store", type="inkbool", 
  247.                         dest="do_altitudes", default=False)
  248.         self.OptionParser.add_option("--anglebisectors",
  249.                         action="store", type="inkbool", 
  250.                         dest="do_anglebisectors", default=False)
  251.         self.OptionParser.add_option("--centroid",
  252.                         action="store", type="inkbool", 
  253.                         dest="do_centroid", default=False)
  254.         self.OptionParser.add_option("--ninepointcentre",
  255.                         action="store", type="inkbool", 
  256.                         dest="do_ninepointcentre", default=False)
  257.         self.OptionParser.add_option("--ninepointcircle",
  258.                         action="store", type="inkbool", 
  259.                         dest="do_ninepointcircle", default=False)
  260.         self.OptionParser.add_option("--symmedians",
  261.                         action="store", type="inkbool", 
  262.                         dest="do_symmedians", default=False)
  263.         self.OptionParser.add_option("--sym_point",
  264.                         action="store", type="inkbool", 
  265.                         dest="do_sym_pt", default=False)
  266.         self.OptionParser.add_option("--sym_tri",
  267.                         action="store", type="inkbool", 
  268.                         dest="do_sym_tri", default=False)
  269.         self.OptionParser.add_option("--gergonne_pt",
  270.                         action="store", type="inkbool", 
  271.                         dest="do_gergonne_pt", default=False)
  272.         self.OptionParser.add_option("--nagel_pt",
  273.                         action="store", type="inkbool", 
  274.                         dest="do_nagel_pt", default=False)
  275. #CUSTOM POINT OPTIONS
  276.         self.OptionParser.add_option("--mode",
  277.                         action="store", type="string", 
  278.                         dest="mode", default='trilin')
  279.         self.OptionParser.add_option("--cust_str",
  280.                         action="store", type="string", 
  281.                         dest="cust_str", default='s_a')
  282.         self.OptionParser.add_option("--cust_pt",
  283.                         action="store", type="inkbool", 
  284.                         dest="do_cust_pt", default=False)
  285.         self.OptionParser.add_option("--cust_radius",
  286.                         action="store", type="inkbool", 
  287.                         dest="do_cust_radius", default=False)
  288.         self.OptionParser.add_option("--radius",
  289.                         action="store", type="string", 
  290.                         dest="radius", default='s_a')
  291.         self.OptionParser.add_option("--isogonal_conj",
  292.                         action="store", type="inkbool", 
  293.                         dest="do_isogonal_conj", default=False)
  294.         self.OptionParser.add_option("--isotomic_conj",
  295.                         action="store", type="inkbool", 
  296.                         dest="do_isotomic_conj", default=False)
  297.         self.OptionParser.add_option("--report",
  298.                         action="store", type="inkbool", 
  299.                         dest="report", default=False)
  300.  
  301.  
  302.     def effect(self):
  303.         
  304.         so = self.options #shorthand
  305.         
  306.         pts = [] #initialise in case nothing is selected and following loop is not executed
  307.         for id, node in self.selected.iteritems():
  308.             if node.tag == inkex.addNS('path','svg'):
  309.                 pts = get_n_points_from_path( node, 3 ) #find the (x,y) coordinates of the first 3 points of the path
  310.  
  311.  
  312.         if len(pts) == 3: #if we have right number of nodes, else skip and end program
  313.             st = Style(so)#style for dots, lines and circles
  314.             
  315.             #CREATE A GROUP TO HOLD ALL GENERATED ELEMENTS IN
  316.             #Hold relative to point A (pt[0])
  317.             group_translation = 'translate(' + str( pts[0][0] ) + ','+ str( pts[0][1] ) + ')'
  318.             group_attribs = {inkex.addNS('label','inkscape'):'TriangleElements',
  319.                   'transform':group_translation }
  320.             layer = inkex.etree.SubElement(self.current_layer, 'g', group_attribs)
  321.             
  322.             #GET METRICS OF THE TRIANGLE
  323.             #vertices in the local coordinates (set pt[0] to be the origin)
  324.             vtx = [[0,0],
  325.                    [pts[1][0]-pts[0][0],pts[1][1]-pts[0][1]],
  326.                    [pts[2][0]-pts[0][0],pts[2][1]-pts[0][1]]]
  327.             
  328.             s_a = distance(vtx[1],vtx[2])#get the scalar side lengths
  329.             s_b = distance(vtx[0],vtx[1])
  330.             s_c = distance(vtx[0],vtx[2])
  331.             sides=(s_a,s_b,s_c)#side list for passing to functions easily and for indexing
  332.             
  333.             a_a = angle_from_3_sides(s_b, s_c, s_a)#angles in radians
  334.             a_b = angle_from_3_sides(s_a, s_c, s_b)
  335.             a_c = angle_from_3_sides(s_a, s_b, s_c)
  336.             angles=(a_a,a_b,a_c)
  337.             
  338.             ab  = vector_from_to(vtx[0], vtx[1]) #vector from a to b
  339.             ac  = vector_from_to(vtx[0], vtx[2]) #vector from a to c
  340.             bc  = vector_from_to(vtx[1], vtx[2]) #vector from b to c
  341.             vecs= (ab,ac) # vectors for finding cartesian point from trilinears
  342.  
  343.             semiperim = (s_a+s_b+s_c)/2.0 #semiperimeter
  344.             area      = sqrt( semiperim*(semiperim-s_a)*(semiperim-s_b)*(semiperim-s_c) ) #area of the triangle by heron's formula
  345.             uvals = (area, semiperim) #useful values
  346.                     
  347.             params = (sides, angles, vecs, vtx, uvals) #all useful triangle parameters in one object
  348.             
  349.             if so.report:
  350.                 report_properties( params )
  351.  
  352.             #BEGIN DRAWING
  353.             if so.do_circumcentre or so.do_circumcircle:
  354.                 r  = s_a*s_b*s_c/(4*area)
  355.                 pt = (cos(a_a),cos(a_b),cos(a_c))
  356.                 if so.do_circumcentre:
  357.                     draw_SVG_circle(0, pt, params, st, 'Circumcentre', layer)
  358.                 if so.do_circumcircle:
  359.                     draw_SVG_circle(r, pt, params, st, 'Circumcircle', layer)
  360.             
  361.             if so.do_incentre or so.do_incircle:
  362.                 pt = [1,1,1]
  363.                 if so.do_incentre:
  364.                     draw_SVG_circle(0, pt, params, st, 'Incentre', layer)
  365.                 if so.do_incircle:
  366.                     r  = area/semiperim
  367.                     draw_SVG_circle(r, pt, params, st, 'Incircle', layer)
  368.             
  369.             if so.do_contact_tri:
  370.                 t1 = s_b*s_c/(-s_a+s_b+s_c)
  371.                 t2 = s_a*s_c/( s_a-s_b+s_c)
  372.                 t3 = s_a*s_b/( s_a+s_b-s_c)
  373.                 v_mat = ( (0,t2,t3),(t1,0,t3),(t1,t2,0))
  374.                 draw_SVG_tri(v_mat, params, st,'ContactTriangle',layer)
  375.                 
  376.             if so.do_extouch_tri:
  377.                 t1 = (-s_a+s_b+s_c)/s_a
  378.                 t2 = ( s_a-s_b+s_c)/s_b
  379.                 t3 = ( s_a+s_b-s_c)/s_c
  380.                 v_mat = ( (0,t2,t3),(t1,0,t3),(t1,t2,0))
  381.                 draw_SVG_tri(v_mat, params, st,'ExtouchTriangle',layer)
  382.                           
  383.             if so.do_orthocentre:
  384.                 pt = pt_from_tcf('cos(a_b)*cos(a_c)', params)
  385.                 draw_SVG_circle(0, pt, params, st, 'Orthocentre', layer)
  386.             
  387.             if so.do_orthic_tri:
  388.                 v_mat = [[0,sec(a_b),sec(a_c)],[sec(a_a),0,sec(a_c)],[sec(a_a),sec(a_b),0]]
  389.                 draw_SVG_tri(v_mat, params, st,'OrthicTriangle',layer)
  390.             
  391.             if so.do_centroid:
  392.                 pt = [1/s_a,1/s_b,1/s_c]
  393.                 draw_SVG_circle(0, pt, params, st, 'Centroid', layer)
  394.             
  395.             if so.do_ninepointcentre or so.do_ninepointcircle:
  396.                 pt = [cos(a_b-a_c),cos(a_c-a_a),cos(a_a-a_b)]
  397.                 if so.do_ninepointcentre:
  398.                     draw_SVG_circle(0, pt, params, st, 'NinePointCentre', layer)
  399.                 if so.do_ninepointcircle:
  400.                     r    = s_a*s_b*s_c/(8*area)
  401.                     draw_SVG_circle(r, pt, params, st, 'NinePointCircle', layer)
  402.             
  403.             if so.do_altitudes:
  404.                 v_mat  = [[0,sec(a_b),sec(a_c)],[sec(a_a),0,sec(a_c)],[sec(a_a),sec(a_b),0]]
  405.                 draw_vertex_lines( v_mat, params, st, 'Altitude', layer)
  406.             
  407.             if so.do_anglebisectors:
  408.                 v_mat  = ((0,1,1),(1,0,1),(1,1,0))
  409.                 draw_vertex_lines(v_mat,params, st, 'AngleBisectors', layer)
  410.             
  411.             if so.do_excircles or so.do_excentres or so.do_excentral_tri:
  412.                 v_mat = ((-1,1,1),(1,-1,1),(1,1,-1))
  413.                 if so.do_excentral_tri:
  414.                     draw_SVG_tri(v_mat, params, st,'ExcentralTriangle',layer)
  415.                 for i in range(3):
  416.                     if so.do_excircles:
  417.                         r = area/(semiperim-sides[i])
  418.                         draw_SVG_circle(r, v_mat[i], params, st, 'Excircle:'+str(i), layer)
  419.                     if so.do_excentres:
  420.                         draw_SVG_circle(0, v_mat[i], params, st, 'Excentre:'+str(i), layer)
  421.             
  422.             if so.do_sym_tri or so.do_symmedians:
  423.                 v_mat = ((0,s_b,s_c), (s_a, 0, s_c), (s_a, s_b, 0))
  424.                 if so.do_sym_tri:
  425.                     draw_SVG_tri(v_mat, params, st,'SymmedialTriangle',layer)
  426.                 if so.do_symmedians:
  427.                     draw_vertex_lines(v_mat,params, st, 'Symmedian', layer)
  428.             
  429.             if so.do_sym_pt:
  430.                 pt = (s_a,s_b,s_c)
  431.                 draw_SVG_circle(0, pt, params, st, 'SymmmedianPoint', layer)
  432.             
  433.             if so.do_gergonne_pt:
  434.                 pt = pt_from_tcf('1/(s_a*(s_b+s_c-s_a))', params)
  435.                 draw_SVG_circle(0, pt, params, st, 'GergonnePoint', layer)
  436.             
  437.             if so.do_nagel_pt:
  438.                 pt = pt_from_tcf('(s_b+s_c-s_a)/s_a', params)
  439.                 draw_SVG_circle(0, pt, params, st, 'NagelPoint', layer)
  440.             
  441.             if so.do_cust_pt or so.do_cust_radius or so.do_isogonal_conj or so.do_isotomic_conj:
  442.                 pt = []#where we will store the point in trilinears
  443.                 if so.mode == 'trilin':#if we are receiving from trilinears
  444.                     for i in range(3):
  445.                         strings = so.cust_str.split(':')#get split string
  446.                         strings[i] = translate_string(strings[i],0)
  447.                         func = eval('lambda params: ' + strings[i].strip('"')) #the function leading to the trilinar element
  448.                         pt.append(func(params)) #evaluate the function for the trilinear element
  449.                 else:#we need a triangle function
  450.                     string = so.cust_str #don't need to translate, as the pt_from_tcf function does that for us
  451.                     pt = pt_from_tcf(string, params)#get the point from the tcf directly
  452.                     
  453.                 if so.do_cust_pt:#draw the point
  454.                     draw_SVG_circle(0, pt, params, st, 'CustomTrilinearPoint', layer)
  455.                 if so.do_cust_radius:#draw the circle with given radius
  456.                     strings = translate_string(so.radius,0)
  457.                     func = eval('lambda params: ' + strings.strip('"')) #the function leading to the radius
  458.                     r = func(params)
  459.                     draw_SVG_circle(r, pt, params, st, 'CustomTrilinearCircle', layer)
  460.                 if so.do_isogonal_conj:
  461.                     isogonal=[0,0,0]
  462.                     for i in range (3):
  463.                         isogonal[i] = 1/pt[i]
  464.                     draw_SVG_circle(0, isogonal, params, st, 'CustomIsogonalConjugate', layer)
  465.                 if so.do_isotomic_conj:
  466.                     isotomic=[0,0,0]
  467.                     for i in range (3):
  468.                         isotomic[i] = 1/( params[0][i]*params[0][i]*pt[i] )
  469.                     draw_SVG_circle(0, isotomic, params, st, 'CustomIsotomicConjugate', layer)
  470.  
  471.  
  472. if __name__ == '__main__':   #pragma: no cover
  473.     e = Draw_From_Triangle()
  474.     e.affect()
  475.