QB64 Phoenix Edition
SVG lines to micro(A) string array initialization - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: QBJS, BAM, and Other BASICs (https://qb64phoenix.com/forum/forumdisplay.php?fid=50)
+--- Thread: SVG lines to micro(A) string array initialization (/showthread.php?tid=1874)



SVG lines to micro(A) string array initialization - mnrvovrfc - 08-03-2023

This is a program that processes an SVG file and creates code for micro(A). This attempts to "steal" coordinates in millimeters of a "plain" SVG file and present them into strings of run-on 4-digit numbers, which are X and Y absolute coordinate pairs. The values will have to be scaled for a graphics screen according to the maximum dimensions out of the SVG. It looks like the graphics screen of micro(A) is 780x570.

This could probably be done with "sodipodi" format, which is that of Inkscape, but it's not recommended. That program could insert a lot of transformation commands which would make for an uneven picture, and this effort by a hobbyist doesn't provision for that.

N.B. The SVG is expected to have relative coordinates, except the first point of each path. But this is translated into code which employs absolute coordinates. Directly copying from the original document to a QB64 graphics program requires PSET or something else to anchor, then "LINE" with "STEP" option to draw things relatively.

The run-on strings will have sequences of "99999999". This is a reset which means a new shape will begin with the next point listed, and should not connect with the previous coordinate that was obtained. I had to do it this way because micro(A) doesn't process strings very well. Originally it was going to be a string check for "######" for three-digit coordinates. This program shouldn't be used for very large vector pictures anyway.

I had to make more edits to the program to account for "z" at the end of path command. However this could come up with missing lines. I will need more time to look into this.

As it stands, this does not produce useable running micro(A) code, it only creates a couple of array variables and initializes them. I should also offer some simple code in micro(A) to put the lines together for the drawing. But my cohort protested. :/ But why since it's only "line" statements to use? In fact this could be translated into a QB64 or any BASIC program that supports graphics and has a line-drawing statement supporting absolute coordinates.

I got a bit lazy with this program. I was supposed to add Dav's routine to get filenames on Linux or Windows and display them in a nice box in SCREEN 0, and allow this for any version of QB64. Instead if you don't have Phoenix Edition v3.4 or later, you will have to type in a filename for a file that exists inside "(home)/Pictures". Including the directories. This is hard-coded. Yes I know it should be better.

Despite this caveat, this code should run on QB64 v2.0 and up. It does nothing fancy except parse a few values in text format.

There are more explanations as comments in the source code.

Neat trick of the QB64 IDE! It makes "pale" the code that the "conditional" decides doesn't apply for "$IF... THEN... $ELSE... $END IF".

User "roquedrivel" from "BASIC4US" forum helped with this program. Smile

Code: (Select All)
'by mnrvovrfc 3-Aug-2023
'this needs extensive testing because Inkscape keeps mixing absolute and relative coordinates.
'it doesn't matter between "sodipodi" or "plain" SVG.
'GIMP exports paths in absolute coordinates only, but is clunkier to work with.
'this would be easier with relative coordinates only, with the first
' "m" command of a path having the only absolute coordinate.
'it helps sometimes setting, before creating any document:
' Preferences/Input and Output/SVG Output/Paths: choose "relative" from menu.
'this works with lines only! Not bezier paths! Any bezier paths need to have the
' two control points reset: press [N] to choose node tool,
' select the node then the first choice
' on the toolbar for path nodes on the top of the screen.
'one more thing: from a plain SVG the measurement
' is in millimeters *NOT* in pixels!
'This program is meant to be run from the terminal!
'It's up to you to select the terminal text, copy and then paste into a text editor
' or into micro(A)'s editor. Then keep developing the script from there.
'If this is not satisfactory then the user is free to add code
' to create an output file.
$CONSOLE:ONLY
OPTION _EXPLICIT
DIM SHARED sf(1 TO 20) AS STRING, sl(1 TO 20) AS STRING
DIM AS DOUBLE xx, yy, x0, y0, x1, y1
DIM AS LONG fe, x, y, u, v, gh, coma
DIM AS INTEGER g, h
DIM apath$, afile$, dee$, a$, c$, qu$, entry$
DIM f AS _BYTE, lut AS _BYTE

qu$ = CHR$(34)

h = 1
g = 0
gh = 0
sf(h) = "st[" + _TRIM$(STR$(h)) + "] = " + qu$
dee$ = " d=" + qu$
$IF WIN THEN
apath$ = environ$("USERPROFILE") + "\Pictures\"
$ELSE
apath$ = ENVIRON$("HOME") + "/Pictures/"
'/" let's see if this fixes the "qb" code block bug on forum
$END IF
$IF VERSION < 3.4 THEN
'sorry Dav's file list routine was supposed to be here...
' but that would require "direntry.h"
PRINT "The current path now is "; apath$
PRINT "Please type in the name of an SVG file to load."
LINE INPUT afile$
IF afile$ = "" THEN SYSTEM
afile$ = apath$ + afile$
IF NOT _FILEEXISTS(afile$) THEN
PRINT "Unable to proceed!"
PRINT "File not found: "; afile$
END IF
$ELSE
afile$ = _OPENFILEDIALOG$("Please choose an SVG file.", apath$, "*.svg", "Plain SVG")
IF afile$ = "" THEN SYSTEM
$END IF
fe = FREEFILE
OPEN afile$ FOR INPUT AS fe
DO UNTIL EOF(fe)
LINE INPUT #fe, entry$
u = INSTR(entry$, dee$)
IF u THEN
lut = 0
x = -1E+6
y = -1E+6
xx = 0
yy = 0
c$ = ""
a$ = ""
entry$ = MID$(entry$, LEN(dee$) + u)
entry$ = LEFT$(entry$, LEN(entry$) - 1)
PRINT entry$
'trying to squash a bug where it refuses to read the final pair
entry$ = entry$ + " "
sf(h) = sf(h) + "99999999"
gh = gh + 8
g = g + 1
v = 1
u = INSTR(entry$, " ")
DO WHILE u
a$ = MID$(entry$, v, u - v)
'must make sure there are lines only here.
'might also have to check "M" and "m", this only assumes "m" at beginning
' is absolute coordinate.
'this cannot handle "h" nor "v", requires manual editing of SVG file or a
' search-and-replace conversion in this program.
'at last moment I had to make a provision for "z" which means draw a line,
' going back to the first (absolute) point of the path.
IF a$ = "L" THEN lut = 1
IF a$ = "l" THEN lut = 0
IF a$ = "z" THEN EXIT DO
IF LEN(a$) <> 1 THEN
coma = INSTR(a$, ",")
x1 = VAL(LEFT$(a$, coma - 1))
y1 = VAL(MID$(a$, coma + 1))
IF x = -1E+6 AND y = -1E+6 THEN
x0 = x1
y0 = y1
xx = x1
yy = y1
x = INT(xx)
y = INT(yy)
ELSEIF lut THEN
xx = x1
yy = y1
ELSE
xx = xx + x1
yy = yy + y1
END IF
outtheline
END IF
v = u + 1
u = INSTR(v, entry$, " ")
LOOP
IF RIGHT$(entry$, 3) = " z " THEN
xx = x0
yy = y0
outtheline
END IF
PRINT "---"
END IF
LOOP
CLOSE fe

sf(h) = sf(h) + qu$
a$ = _TRIM$(STR$(h))
sl(h) = "sl[" + a$ + "] =" + STR$(gh)

PRINT "var i, j, x1, y1, x2, y2, xscale, yscale, xmove, first, stnumele"
PRINT "str a, b"
PRINT "str st["; a$; "]"
PRINT "var sl["; a$; "]"
FOR g = 1 TO h
PRINT sf(g)
PRINT sl(g)
NEXT
PRINT "stnumele ="; h + 1
PRINT "xscale = 1"
PRINT "yscale = 1"
PRINT "xmove = 0"
PRINT "wcolor 0, 0, 0"
PRINT "fcolor 255, 255, 255"
PRINT "i = 1"
PRINT "label lb02"
PRINT " j = 1"
PRINT " label lb03"
PRINT " x1 = x2"
PRINT " y1 = y2"
PRINT " b = st[i]"
PRINT " a = mstr(b, j, 4)"
PRINT " x2 = val(a)"
PRINT " if x2 = 9999"
PRINT " first = 1"
PRINT " j = j + 8"
PRINT " goto cb03"
PRINT " endif"
PRINT " x2 = x2 * xscale"
PRINT " x2 = x2 + xmove"
PRINT " j = j + 4"
PRINT " b = st[i]"
PRINT " a = mstr(b, j, 4)"
PRINT " y2 = val(a)"
PRINT " y2 = y2 * yscale"
PRINT " if first = 0"
PRINT " line x1, y1, x2, y2"
PRINT " endif"
PRINT " if first = 1 : first = 0 : endif"
PRINT " j = j + 4"
PRINT "label cb03"
PRINT " if j < sl[i] : goto lb03 : endif"
PRINT "i = i + 1"
PRINT "if i < stnumele : goto lb02 : endif"
PRINT "swap"
SYSTEM


SUB outtheline ()
SHARED AS LONG x, y, gh
SHARED AS DOUBLE xx, yy
SHARED AS INTEGER g, h
SHARED qu$
DIM hs$
x = INT(xx)
y = INT(yy)
PRINT x; ","; y
sf(h) = sf(h) + Zeroes$(x, 4) + Zeroes$(y, 4)
gh = gh + 8
g = g + 1
IF g >= 80 THEN
hs$ = _TRIM$(STR$(h))
sf(h) = sf(h) + qu$
sl(h) = "sl[" + hs$ + "] =" + STR$(gh)
gh = 0
g = 0
h = h + 1
hs$ = _TRIM$(STR$(h))
sf(h) = "st[" + hs$ + "] = " + qu$
END IF
END SUB


FUNCTION Zeroes$ (num AS LONG, numdig AS INTEGER)
DIM b$, v AS LONG
DIM AS INTEGER sg, hx
IF num < 0 THEN sg = -1: num = num * -1
IF numdig < 0 THEN hx = 1: numdig = numdig * -1 ELSE hx = 0
IF hx THEN
b$ = HEX$(num)
ELSE
b$ = LTRIM$(STR$(num))
END IF
v = numdig - LEN(b$)
IF v > 0 THEN b$ = STRING$(v, 48) + b$
IF sg = -1 THEN b$ = "-" + b$
Zeroes$ = b$
END FUNCTION



RE: SVG lines to micro(A) string array initialization - mnrvovrfc - 08-03-2023

Please see the first post. Fixed it so the program generates output which is a complete micro(A) script.


RE: SVG lines to micro(A) string array initialization - aurel - 08-03-2023

Thanks @mnrvovrfc Smile