Bueno el título lo resume. Esta biblioteca les permite convertir los paths de los archivos SVG en una serie de comandos que pueden ser ejecutados en un interprete de LOGO. Por ahora soporta MSWLogo y los interpretes online http://www.calormen.com/jslogo y https://turtleacademy.com.
Ejemplo de uso:
from SvgPath2Logo import SvgPath2Logo path = """M10 315L 110 215A 30 50 0 0 1 162.55 162.45 L 172.55 152.45A 30 50 -45 0 1 215.1 109.9L 315 10""" s = SvgPath2Logo() print s.toLogo(path, SvgPath2Logo.XLOGO, 0.3)
Como verán, es muy fácil. El método toLogo recibe el path SVG, el interprete para el cual generar el código y la escala. Actualmente el interprete puede ser MSWLOGO o XLOGO, siendo este último el que genera un código válido para los interpretes online antes mencionados. La escala permite redimensionar la imagen. Si vale 1(uno) se conserva el tamaño original. El código genera la siguiente salida:
;Code generated for Generic logo interpreters ;You can run it in http://www.calormen.com/jslogo or https://turtleacademy.com. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Basic Functions ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to arcsin :a if :a=-1 [ output -90 ] if :a=1 [ output 90 ] output arctan :a/(sqrt 1-:a^2) end to arccos :a if :a=0 [ output 90 ] ifelse :a<0 [ output 180+(arctan (sqrt 1-:a^2)/:a) ] [ output arctan (sqrt 1-:a^2)/:a ] end to dot_product :ux :uy :vx :vy output arccos (:ux*:vx+:uy*:vy)/((sqrt :ux^2+:uy^2)*(sqrt :vx^2+:vy^2)) end ;draws a cubic bezier curve from current point to (x, y) ;@param x1, y1 are the first control point ;@param x2, y2 are the second control point ;@param n is the number of points to cubic_bezier :x1 :y1 :x2 :y2 :x :y :n make "dt (1.0/(:n-1)) for [i 0 :n 1] [ make "t :i*:dt ;calculating coefficients make "cx 3.0*(:x1-(first pos)) make "bx 3.0*(:x2-:x1)-:cx make "ax :x-(first pos)-:cx-:bx make "cy 3.0*(:y1-(last pos)) make "by 3.0*(:y2-:y1)-:cy make "ay :y-(last pos)-:cy-:by make "rx :ax*:t^3+:bx*:t^2+:cx*:t+(first pos) make "ry :ay*:t^3+:by*:t^2+:cy*:t+(last pos) ;goto new point setxy :rx :ry ;save the second control point make "lx1 :x2 make "ly1 :y2 ] end ;draws an arc ;@param (cx, cy) is the center ;@param rx radius x ;@param ry radius y ;@param rt is the angle from the x-axis of the current coordinate system to the x-axis of the ellipse ;@param o which is the start angle of the elliptical arc prior to the stretch and rotate operations ;@param do is the difference between the initial and final angle ;see also http://www.w3.org/TR/SVG/implnote.html#ArcParameterizationAlternatives to draw_arc :cx :cy :rx :ry :rt :o :do ;make angle positive and less or equal than 360 make "o :o%360 if :o<0 [ make "o :o+360 ] ;set turning sense ifelse :do<0 [ make "i -1 ] [ make "i 1 ] ;draw arc for [a :o :o+:do :i] [ ;calculate point make "px (cos :rt)*:rx*(cos :a)-(sin :rt)*:ry*(sin :a)+:cx make "py (sin :rt)*:rx*(cos :a)+(cos :rt)*:ry*(sin :a)+:cy ;goto the point setxy :px :py ] end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;SVG Functions ; ;http://www.w3.org/TR/SVG/paths.html ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; to absolute_moveto :x :y penup setxy :x :y pendown make "x0 (first pos) make "y0 (last pos) end to relative_moveto :x :y absolute_moveto :x+(first pos) :y+(last pos) end to closepath setxy :x0 :y0 end to absolute_horizontal_lineto :x setx :x end to relative_horizontal_lineto :x absolute_horizontal_lineto :x+(first pos) end to absolute_vertical_lineto :y sety :y end to relative_vertical_lineto :y absolute_vertical_lineto :y+(last pos) end to absolute_lineto :x :y setxy :x :y end to relative_lineto :x :y absolute_lineto :x+(first pos) :y+(last pos) end to absolute_cubic_bezier :x1 :y1 :x2 :y2 :x :y ;n=1000 to ensure that the curve is smooth cubic_bezier :x1 :y1 :x2 :y2 :x :y 1000 end to relative_cubic_bezier :x1 :y1 :x2 :y2 :x :y absolute_cubic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos) end to absolute_smooth_cubic_bezier :x2 :y2 :x :y absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2 :y2 :x :y end to relative_smooth_cubic_bezier :x2 :y2 :x :y absolute_cubic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos) end to absolute_quadratic_bezier :x1 :y1 :x :y ;quadratic bezier expressed as cubic bezier ;http://fontforge.github.io/bezier.html ;see also "Converting TrueType to PostScript" absolute_cubic_bezier (first pos)+(:x1-(first pos))*2/3 (last pos)+(:y1-(last pos))*2/3 :x+(:x1-:x)*2/3 :y+(:y1-:y)*2/3 :x :y end to relative_quadratic_bezier :x1 :y1 :x2 :y2 :x :y absolute_quadratic_bezier :x1+(first pos) :y1+(last pos) :x2+(first pos) :y2+(last pos) :x+(first pos) :y+(last pos) end to absolute_smooth_quadratic_bezier :x :y absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x :y end to relative_smooth_quadratic_bezier :x :y absolute_quadratic_bezier (2*(first pos)-(:lx1)) (2*(last pos)-(:ly1)) :x+(first pos) :y+(last pos) end ;see also http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter to absolute_arc :rx :ry :rt :fa :fs :x2 :y2 ;auxiliar calcs make "rt :rt%360 make "x1 (first pos) make "y1 (last pos) make "tx1 (cos :rt)*(:x1-:x2)/2+(sin :rt)*(:y1-:y2)/2 make "ty1 -(sin :rt)*(:x1-:x2)/2+(cos :rt)*(:y1-:y2)/2 ;Correction of out-of-range rx and ry make "rx (abs :rx) make "ry (abs :ry) make "d (sqrt (:tx1^2/:rx^2+:ty1^2/:ry^2)) make "rx :d*:rx make "ry :d*:ry ;auxiliar calcs make "sq (sqrt abs (((:rx^2*:ry^2-:rx^2*:ty1^2-:ry^2*:tx1^2)/(:rx^2*:ty1^2+:ry^2*:tx1^2)))) if :fa=:fs [ make "sq -:sq ] make "tcx :sq*:rx*:ty1/:ry make "tcy :sq*-:ry*:tx1/:rx ;calculating coefficients make "cx (cos :rt)*:tcx-(sin :rt)*:tcy+(:x1+:x2)/2 make "cy (sin :rt)*:tcx+(cos :rt)*:tcy+(:y1+:y2)/2 make "o -(dot_product 1 0 (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry) make "do -(dot_product (:tx1-:tcx)/:rx (:ty1-:tcy)/:ry (-:tx1-:tcx)/:rx (-:ty1-:tcy)/:ry)%360 ;draw draw_arc :cx :cy :rx :ry :rt :o :do end to relative_arc :rx :ry :rt :fa :fs :x2 :y2 absolute_arc :rx :ry :rt :fa :fs (first pos)+:x2 (last pos)+:y2 end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Draw ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; absolute_moveto 3.0 -94.5 absolute_lineto 33.0 -64.5 absolute_arc 9.0 15.0 -0.0 0.0 1.0 48.765 -48.735 absolute_lineto 51.765 -45.735 absolute_arc 9.0 15.0 45.0 0.0 1.0 64.53 -32.97 absolute_lineto 94.5 -3.0
Como pueden ver el código generado se divide en 3 partes. La primera parte contiene funciones básicas necesarias. Estas varían de acuerdo al interprete escogido. En este caso el interprete elegido no dispone de las funciones arco seno y arco coseno, por lo que las implemente aprovechando relaciones trigonométricas con el arco tangente. Ademas se agrega el producto punto y los procedimientos que dibujan arcos(centrados en un punto) y curvas de bezier cúbicas. La función draw_arc está implementada de acuerdo a este apéndice de la W3C. La función cubic_bezier está implementada basada en este código en C que calcula n puntos basados en la ecuación paramétrica de la curva de bezier cúbica y traza las lineas correspondientes entre dichos puntos.
La segunda parte contiene las funciones SVG. Por cada comando que se puede encontrar en un path SVG hay una función análoga programada en LOGO con los mismos parámetros. Esta sección también puede variar dependiendo del interprete. Acá las únicas funciones que merecen explicación son absolute_quadratic_bezier y absolute_arc. La primera aprovecha una transformación de curvas bezier cuadráticas a cúbicas. La segunda gráfica un arco pero no centrado en un punto(como draw_arc), sino desde el punto actual al punto (x2, y2), como lo establece el comando arc. Para hacer esto simplemente hace una conversión de parámetros basados en la sección F.6.5 y F.6.6 del apéndice F de la especificación SVG.
Por último, en la tercer parte, están las llamadas a funciones que hacen el dibujo.
Pongo la imagen original y el resultado de ejecutar el código en el interprete:
¿Como funciona?
Bueno cuando se invoca al método toLogo, lo primero que hace es incluir la biblioteca LOGO correspondiente de acuerdo al interprete elegido. A continuación parsea el path y hace una traducción de cada comando a una llamada a una función de la biblioteca.
Mas ejemplos
Acá pongo algunas muestras de la ejecución del código generado sobre MSWLogo:
Quizás en el futuro agregue soporte para KTurtle, bordes de color, relleno y conversión de archivos SVG.
Dejo el enlace al repositorio. Saludos.
Hola, habra una manera de escribir todo en logo basic como para correrlo en una MSX?
Ahi veo un logo muy complejo
Hola. No entendí bien. ¿Vos querés hacer un intérprete de Logo en MSX basic? Si bien desconozco el lenguaje y la plataforma lo veo totalmente posible.