Hi
I'm writing a program so I can draw shapes in Inkscape and import the svg file into DBPro and use the data to make a Box2d world.
So far I can draw rectangles, circles and straight paths (no bezier curves). Closed paths with 8 or less nodes will be turned into a polygon. I use two layers in Inkscape called "LayerStatic" and "LayerDynamic". The rest of the layers will be ignored.
Here's the code. It's not too well commented and I'm sure there are some bugs in there.
rem WIP version July 5. Programmed by Ranietz
rem A program that import Box2d collision data from Inkscape svg files
rem It works with rectangles, circles and paths with no curves
rem Closed paths with 8 or less nodes will be made into a polygon
rem Objects in the layer called "LayerStatic" will be static Box2d objects
rem Objects in the layer called "LayerDynamic" will be dynamic Box2d objects
rem The rest of the layers will be ignored
rem Requires Box2d and Matrix1Utility plugins
set display mode 1024, 768, 32, 1
sync on : sync rate 60
global world
global map$
rem load the collision data from a file
load_world("box2dtest.svg")
do
rem update box2d world
b2StepWorld world, 1.0/60.0
rem draw the box2d world
b2DrawWorld world, 1
sync
cls 0
loop
function load_world(fileName$)
rem check if file exist
if file exist(fileName$) = 1
open to read 1, fileName$
else
print "The file " + fileName$ + " does not exist"
print "Press any key to close the program"
sync
sync
wait key
end
endif
rem set the scale and create box2d world
b2SetScale 100, 180.0/3.1415926535, 1, 100
world = b2CreateWorld(0.0, 200.0, 1)
rem read the svg file
repeat
read string 1, map$
map$ = remove all$(map$," ")
rem load static objects
if mid$(map$, 17, 11) = "LayerStatic"
load_layer(0)
endif
rem load dynamic objects
if mid$(map$, 17, 12) = "LayerDynamic"
load_layer(1)
endif
until map$ = "</svg>"
close file 1
endfunction
function load_layer(dynamic)
repeat
read string 1, map$
map$ = remove all$(map$," ")
rem draw rectangles
if fast left$(map$,5) = "<rect"
rem read the data from the "<rect" tag
repeat
read string 1, map$
map$ = remove all$(map$," ")
if fast left$(map$,6) = "width="
tmp = fast len(map$)
tmp2 = tmp - 8
width# = val(mid$(map$,8,tmp2))
endif
if fast left$(map$,7) = "height="
tmp = fast len(map$)
tmp2 = tmp - 9
height# = val(mid$(map$,9,tmp2))
endif
if fast left$(map$,2) = "x="
tmp = fast len(map$)
tmp2 = tmp - 4
x# = val(mid$(map$,4,tmp2))
endif
if fast left$(map$,2) = "y="
tmp = fast len(map$)
tmp2 = tmp - 4
y# = val(mid$(map$,4,tmp2))
endif
until fast right$(map$, 2) = "/>"
rem make the box2d rectangles
if dynamic = 1
body = b2Createbody(world, b2BodyType_Dynamic(), x#+(width#/2), y#+(height#/2))
else
body = b2Createbody(world, b2BodyType_Static(), x#+(width#/2), y#+(height#/2))
endif
shape = b2CreatePolygonShapeAsBox(width#, height#)
fixture = b2CreateFixture(body, shape, 0.1, 0.2, 0.5)
b2DeleteShape shape
endif
rem draw path
if fast left$(map$,5) = "<path"
pathIsCircle = 0
pathIsLoop = 0
rem read data from the "<path" tag
repeat
read string 1, map$
tmp$ = remove all$(map$," ")
if fast left$(tmp$, 2) = "d="
path$ = map$
endif
if fast left$(tmp$,11) = "sodipodi:cx"
cx# = val(mid$(tmp$,14,fast len(map$)-13))
pathIsCircle = 1
endif
if fast left$(tmp$,11) = "sodipodi:cy"
cy# = val(mid$(tmp$,14,fast len(map$)-13))
pathIsCircle = 1
endif
if fast left$(tmp$,11) = "sodipodi:rx"
rx# = val(mid$(tmp$,14,fast len(map$)-13))
pathIsCircle = 1
endif
if fast left$(tmp$,12) = "sodipodi:ry="
ry# = val(mid$(tmp$,14,fast len(map$)-13))
pathIsCircle = 1
endif
until fast right$(map$, 2) = "/>"
rem make a circle if the path is a circle
if pathIsCircle = 1
if dynamic = 1
body = b2Createbody(world, b2BodyType_Dynamic(), cx#, cy#)
else
body = b2Createbody(world, b2BodyType_Static(), cx#, cy#)
endif
shape = b2CreateCircleShape(0, 0, (rx#+ry#)/2)
fixture = b2CreateFixture(body, shape, 0.1, 0.2, 0.5)
b2DeleteShape shape
else
rem if the path is not a circle it is either a regular path or it can be turned into a polygon
nodeCount = string count(path$, ",")
stringLenght = fast len(path$)
pathIsLoop = find char(path$, "z")
rem pake the path into a polygon if it has 8 or less nodes and is looped
if nodeCount <= 8 and pathIsLoop > 0
tmp1 = find char(path$, "M")+1
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x1# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y1# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x2# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y2# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x3# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y3# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
if nodeCount >=4
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x4# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y4# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
if nodeCount >=5
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x5# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y5# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
if nodeCount >=6
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x6# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y6# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
if nodeCount >=7
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x7# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y7# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
if nodeCount >=8
tmp1 = tmp3
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x8# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y8# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
endif
endif
endif
endif
endif
rem make the box2d body for the polygon
if dynamic = 1
body = b2CreateBody(world, b2BodyType_Dynamic(), 0, 0)
else
body = b2CreateBody(world, b2BodyType_Static(), 0, 0)
endif
rem make a polygon shape based on the number of nodes in the path
select nodeCount
case 3
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#)
endcase
case 4
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#, x4#, y4#)
endcase
case 5
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#, x4#, y4#, x5#, y5#)
endcase
case 6
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#, x4#, y4#, x5#, y5#, x6#, y6#)
endcase
case 7
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#, x4#, y4#, x5#, y5#, x6#, y6#, x7#, y7#)
endcase
case 8
shape = b2CreatePolygonShape(x1#, y1#, x2#, y2#, x3#, y3#, x4#, y4#, x5#, y5#, x6#, y6#, x7#, y7#, x8#, y8#)
endcase
endselect
rem make the fixture for the polygon
fixture = b2CreateFixture(body, shape, 0.1, 0.2, 0.5)
b2DeleteShape shape
else
rem make a regular path if the path can't be a polygon
rem find the first x,y node
tmp1 = find char(path$, "M")+1
tmp2 = find char(path$, ",", tmp1)
tmp3 = find char(path$, " ", tmp2)
x# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
firstx# = x#
firsty# = y#
tmp1 = tmp3
dec nodeCount
rem find the rest of the nodes and make edges of the lines
repeat
dec nodeCount
oldx# = x#
oldy# = y#
tmp2 = find char(path$, ",", tmp1)
if nodeCount = 0
tmp3 = stringLenght
else
tmp3 = find char(path$, " ", tmp2)
endif
x# = val(mid$(path$, tmp1+1, tmp2-tmp1-1))
y# = val(mid$(path$, tmp2+1, tmp3-tmp2-1))
tmp1 = tmp3
if dynamic = 1
body = b2CreateBody(world, b2BodyType_Dynamic(), 0, 0)
else
body = b2CreateBody(world, b2BodyType_Static(), 0, 0)
endif
shape = b2CreatePolygonShapeAsEdge(oldx#, oldy#, x#, y#)
fixture = b2CreateFixture(body, shape, 1)
b2DeleteShape shape
until nodeCount = 0
rem add a line from the last x,y to the first x,y if the path is a loop
if pathIsLoop > 0
if dynamic = 1
body = b2CreateBody(world, b2BodyType_Dynamic(), 0, 0)
else
body = b2CreateBody(world, b2BodyType_Static(), 0, 0)
endif
shape = b2CreatePolygonShapeAsEdge(x#, y#, firstx#, firsty#)
fixture = b2CreateFixture(body, shape, 1)
b2DeleteShape shape
endif
endif
endif
endif
until map$ = "</g>" or map$ = "</svg>" or fast right$(map$, 2) = "<g"
endfunction
I've also attached a svg file for you to try out. Hopefully someone will find this useful.
Feel free to comment, modify and expand the code.
Additional info:
-The svg file must be saved as an Inkscape svg file. I don't know how well it handles other types of svg files.
-In Inkscape preferences -> SVG Output: uncheck "Allow relative coordinates" and "Force repeat commands"
-Rectangles, circles and paths can be moved, duplicated and resized but not rotated.
-Nodes can be added and removed from a path. Just make sure you make the path straight afterwards by making the nodes into corners.
-Ungroup all objects before you save the file.
-You don't have to snap the nodes to a grid set to pixels but I find it's easier to work that way.
-Box2d and Matrix1 plugins required.