Hello 
I'm Siobhan Curran/Kisa Naumova, and this is my weblog. I tend to write about stuff like crossdressing, Macs, code, cats, wine and Second Life, but in general it's just an ongoing conversation about all sorts of stuff. If you'd like to know a little bit more about what this all is, I recommend starting on this page which has a little bit of info on who I am, and what I'm trying to do — or you could dive into my five years worth of archives if you like.
Otherwise, feel free to close this box and explore...
More On Building With SVG
secondlife howto illustrator building SVG
...because where's the fun in code if you can't share it, eh?
I'm rather chuffed with my little Illustrator->SVG->Prim scripting adventure
The main reason I wanted something that did that was because the Illustrator files of our building at work turned up unexpectedly in my .INBOX the other day, and I wanted to be able to use them in my ongoing project, rather than having to construct it all by hand.
Here's our floor...

And here's the script in action...
"But Kisa," comes the inevitable query of (oooh) no-one, "how does it work?"
OK, first step is the SVG file. Have you ever opened one of those in a text editor? ![]()
The gubbins that Illustrator generates is rather verbose, but buried deep in the XML structure is some fun stuff like this...
<rect x="1101.013"
y="88.387"
i:knockout="Off"
fill="#FF900B"
width="20.203"
height="800.506"/>
...perfect fodder for some mathematical jiggery pokery ![]()
So, first off, I use PHP's built-in XML parsing to find out where the info I need is...
<?php
$scale = 1000 ; // How many pixels per metre
$xml_src = "/path/to/SVG" // Change as needed, natch
$simple = file_get_contents($xml_src);
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
So far, so good. I now have the structure of the SVG defined in $index, and the contents in $vals
$rect = $index['RECT'] ;
That loads all the rectangle keys into an array called $rect, so I can get at what I need.
$root = $rect[0];
$bounds['x'] = $vals[$root]['attributes']['WIDTH'] ;
$bounds['y'] = $vals[$root]['attributes']['HEIGHT'] ;
And that uses the first rectangle (the one at the bottom) to work out the overall dimensions of the build, and act as a centre-reference for all the others.
OK, this next bit is a bit dodgy, in that I don't need to create an array with all the rectangles in it — it just seemed like it would be useful, that's all...
$count = 0 ;
foreach ($rect as $box) {
Here's where the maths starts. The x and y dimensions of the prim are just the width and height from the XML...
$boxes[$count]['dx'] = $vals[$box]['attributes']['WIDTH'] ;
$boxes[$count]['dy'] = $vals[$box]['attributes']['HEIGHT'] ;
Easy
The x and y positions though, are relative to the bottom-left¹ corner of the 'root' rectangle — so we need to do some number-crunching...
$boxes[$count]['x'] = $vals[$box]['attributes']['X']
— ($bounds['x'] / 2) + ($boxes[$count]['dx'] / 2) ;
$boxes[$count]['y'] = 0 — ($vals[$box]['attributes']['Y']
— ($bounds['y'] / 2) + ($boxes[$count]['dy'] / 2)) ;
(I've had to wrap those lines BTW)
Essentially, they're "this position minus half the overall size, plus half this size" — and the "0 -" bit in the y part, is because otherwise it would be upside down.
Then we take the colour...
$boxes[$count]['colour'] = $vals[$box]['attributes']['FILL'] ;
...and we split the hexidecimal into three (RGB), convert it to decimal, and divide by 255 to get happy Second Life numbers...
$boxes[$count]['r'] =
round((hexdec(substr($boxes[$count]['colour'], 1, 2)) / 255),3) ;
$boxes[$count]['g'] =
round((hexdec(substr($boxes[$count]['colour'], 3, 2)) / 255),3) ;
$boxes[$count]['b'] =
round((hexdec(substr($boxes[$count]['colour'], 5, 2)) / 255),3) ;
('scuse the wrapping, again)
All I'm doing there is taking a sub-string of the colour (eg. #FFFFFF -> "FF"), converting it to a decimal (so "FF" would give me "255"), dividing by 255, and rounding it to three decimal places.
With all that in place, I just output everything to the browser, seperated by the pipe symbol (so I can parse the text to a list in SL), taking the $scale into account...
if($count>0) { // I don't need the root prim
echo round($boxes[$count]['x']/$scale, 3)
."|"
.round($boxes[$count]['y']/$scale, 3)
."|"
.round($boxes[$count]['dx']/$scale, 3)
."|"
.round($boxes[$count]['dy']/$scale, 3)
."|<"
.$boxes[$count]['r'].","
.$boxes[$count]['g'].","
.$boxes[$count]['b'].">n" ;
}
The 'RGB' bit BTW, I make into a vector — that's what the < and > are for.
And finally, I up the counter...
$count++ ;
}
?>
With me? ![]()
When I run that, I get stuff like this:
-0.143|0.09|0.17|0.033|<1,1,1>
...which is a prim 0.17 x 0.033 metres in size, at a position of -0.143 x 0.09 metres away from the centre of the build, and coloured white.
The fun stuff, though, happens in Second Life. To make this work, you need two objects — one is the main 'rezzer' (and corresponds to the root rectangle in all that stuff above), the other is a cube called "box" (which needs full permissions) that the main one makes copies of.
First, rez a cube and set the texture to "blank" (otherwise you'll end up with plywood boxes all over the place — unless you want that, of course). Call it "box", and drop this script in it...
/////////////////////////////////////////////////////////
list params;
vector colour; // There's a bloody U in it. Dammit
default
{
on_rez(integer param)
{
llListen( param, "", NULL_KEY, "" );
}
listen( integer channel, string data, key id, string message )
{
params = llParseString2List(message, ["|"],[]);
colour = (vector)llList2String(params,4);
llSetPrimitiveParams([PRIM_POSITION,
llGetPos() +
<llList2Float(params,0), llList2Float(params,1), 0>,
PRIM_SIZE,
<llList2Float(params,2), llList2Float(params,3), 1>,
PRIM_COLOR, ALL_SIDES, colour , 1.0 ]);
}
}
/////////////////////////////////////////////////////////
All that does, is listen out for instructions on a special channel (set by the initial param), and when it hears "-0.143|0.09|0.17|0.033|<1,1,1>" from the root prim (I'll come to that in a second), it parses that, and uses the info to reposition, resize, and recolour itself.
The root prim needs this script in it (which I copy-pasted from the LSLWiki, and tweaked a little)...
/////////////////////////////////////////////////////////
// Read out a complete notecard from the object's inventory.
string gName; // name of notecard in the inventory
integer gLine = 0; // current line number
key gQueryID; // id used to identify dataserver queries
default {
state_entry() {
}
touch_start(integer foo) {
gName = llGetInventoryName(INVENTORY_NOTECARD, 0);
// select the first notecard in the object's inventory
gQueryID = llGetNotecardLine(gName, gLine);
// request first line
}
dataserver(key query_id, string data) {
if (query_id == gQueryID) {
if (data != EOF) { // not at the end
llRezObject("box", llGetPos() + <0, 0, 0.75>,
ZERO_VECTOR, ZERO_ROTATION, gLine+1);
llSleep(1);
llSay(gLine+1, data); // output the line
++gLine; // increase line count
gQueryID = llGetNotecardLine(gName, gLine);
// request next line
}
}
}
}
/////////////////////////////////////////////////////////
Messy huh? ![]()
What that does is read through the first notecard in the object's inventory (I forgot to mention — you need to put all the text that the PHP code generates into a notecard and drop it into the object) line by line. With each line, it rezzes a copy of "box" (which I also forgot to mention needs to be in its inventory) with the initial parameter of gLine+1 — basically the line number we're on (starting at zero) plus one...
llRezObject("box", llGetPos() + <0, 0, 0.75>,
ZERO_VECTOR, ZERO_ROTATION, gLine+1);
This tells "box" which channel to listen out for instructions on. See? ![]()
Then it says the line contents on that channel...
llSay(gLine+1, data);
..ups the counter and moves onto the next line untli it gets to the end.
Like I said though, it's messy. There are some big rough edges that need to be ironed out:
The z-height and z-size of "box" are hard-coded into the script. There needs to be a way of setting them more elegantly.
You end up with a load of prims all still listening on their channels. I need some way of killing the scripts inside them — or, even better, deleting the scripts once they're in the right place.
Because I round things to three decimal places, sometimes I get seams between the prims. I'm thinking that I can avoid that by using a sensible scale in my Illustrator files and by double-checking the numbers before I save it.
No idea what will happen if you try to make a prim larger than 10 metres — most likely it'll just silently fail. I need to write something that'll catch those in the PHP, and split them into smaller chunks.
...
Anyway. Sorry for the Big Code Post™ ![]()
You know, I do posts like these for two reasons. Partly to pat myself on the back (I am a vain cow), but also in the hope that someone will take these and improve on them. Intolerable and Junie Ginsburg, for example, have been doing some really impressive stuff with the SMIL/TeXML stuff I posted the other day ![]()
¹ I think. I should check that.
I’m always impressed with the SL stuff, no really I am, and it’s way beyond me but fascinating because of that. One day I’ll actually sit down and learn how to do the basic stuff.
Ciara
You know, it's pretty beyond me too ![]()
I mean, I wonder sometimes just what professional coders would say about my lazy, half-arsed attempts to script and stuff. I feel (for one reason or another) that's it's probably worth re-stressing that I'm just a 'hobbyist' when it comes to all this.
Granted, sometimes I do get paid for stuff, but mostly I'm just having fun seeing what I can make things do within the very limited bounds of my "knowledge".
I guess what I'm saying is that I don't have some gradiose impression of myself as being a "coder" — I'm just someone who likes tinkering and sharing...
...in a dress.
Posture
Hmm, I just noticed that when I wear a bra, my back arches itself like a reflex. I'm now wondering if anyone has done any research into the long-term effects on posture for men who wear bras and falsies ![]()
Well as far as I’m concerned having fun is what life is about, just from ad hoc observations I think people who take themselves too seriously and more over there subject to seriously are joyless “shit-faced cock-masters” (oh I’ve so promised myself I’d start using that phrase).
As for being a hobbyist, as long as you don’t start having a “weak lemon drink” I think there is nothing wrong in it.
Ciara
weak lemon drink
Argh! What's that from?!
Fist of Fun with Lee & Herring! (More specifically — the Simon Quinlack — Collector segments with Kevin Eldon as the assidious collector of things from Railway numbers to Old People).
Ta! (Nerd
)
Once again, your coolness astounds me!
I'm a big fan of doing away with drudgery (and a lot of potential errors) by shoving a bag of bits into one end of a Cunningly Crafted Sausage Machine™ and scooping up the Gold that pops out the other. I've created a few of these engines in my time and I love it; so I well understand the joy you appear to get from it. OK, sometimes it occurs to you that you've just spent 100's of hours creating something to do a job that you could have done manually in half the time; but that's not the point, is it?
Keep it up!
Mildly Diverting: Super Public, Super Sexy
You can tell you're a "hobbyist", because you're obviously excited about what you're doing and want to share it with everyone.
This is a Good Thing.
If you were a "professional coder" you'd write better code, but it wouldn't have the joy you're getting out of it.
Just think of your audience as a huge diffuse parent saying "that's nice dear" without really having a clue what you're doing but still pretty impressed. ![]()
I like that
You're on good form at the moment Becks ![]()
If the boobs are too big and worn over long extended periods of time then they could give the wearer back problems, not sure what that would do to the posture.
Won't be good I suspect.
Channel4.com : The Perfect Penis
"This programme meets the Russian surgeons who chopped off a man's penis and re-grew it on his arm" — WHY?! (11pm tonight)
(Insert "A quick one off the wrist" joke here)
I used to find I had better posture in a bra. I also found that wearing heels was very good for when my arches fell. I'd come home hobling in great pain, slip on my heels and be fine straight away.
James
when my arches fell
What does that actually mean? I have a mental impression of feet collapsing into a gooey mess now.
(I know, STFW
)
Still on a TV television¹ theme, on ITV4 right now, there's a film starring CLint Eastwood, all about "a veteran pilot called back from retirement and sent on a dangerous mission behind Soviet lines" to (I presume, given the title of the film) steal the code of some kind of web browser...
¹ Just so no-one thinks I'm talking about transvestism...
Its something to do with a tendon that supports the arch, it feels like squidgy feet though
. Heels took the strain off it apparantly and allowed it to relax. I never managed to tell my doctor quite how they recovered so quickly each time.
james
I haven't seen that movie in ages. Just finished watching the girl on girl action in last nights Torchwood.
james
Your code is nice, don't be afraid of wrapping lines, it actually makes it easier to read.
........ I tried to show you the formatting, but it wasn't showing correctly, so i pastebined it:
http://pastebin.ca/260025
I find that aligning vertically these blocks of arithmeticstuffs makes it easier read, and the indenting makes it easier to know what depends on what.
Someone said, that the perfect width of a text for comprehension is about 80 characters per line, I don't know if that's true.
--
Someone should make a study of the /benefits/ of wearing girl's clothes, so that when confronted, we could just say "I'm doing it for X pseudo-medical reason!", that would at least make people treat me as a disabled person....... Which is not much better, I don't think so..
...perfect width of a text ... about 80 characters per line...
Interesting that. You know, back in the day, when 'green screens' were the 'bees knees', they were 80 characters wide. It always puzzled me, why 80? Then it dawned on me: punch cards were 80 columns wide, and I stopped worrying about it!
Isn't 'fallen arches' just another term for 'flat feet'?
Lovely, this Illustrator trick. Here's a solution to your #2, both turning off the listener and deleting the script:
/////////////////////////////////////////////////////////
list params;
vector colour; // There's a bloody U in it. Dammit
integer iHandle; // got to shut her down too
default
{
on_rez(integer param)
{
iHandle = llListen( param, "", NULL_KEY, "" );
}
listen( integer channel, string data, key id, string message )
{
params = llParseString2List(message, ["|"],[]);
colour = (vector)llList2String(params,4);
llSetPrimitiveParams([PRIM_POSITION,
llGetPos() +
<llList2Float(params,0), llList2Float(params,1), 0>,
PRIM_SIZE,
<llList2Float(params,2), llList2Float(params,3), 1>,
PRIM_COLOR, ALL_SIDES, colour , 1.0 ]);
// nice tidying here
llListenRemove(iHandle);
llRemoveInventory(llGetScriptName()); // delete this script
}
}
/////////////////////////////////////////////////////////
And, speaking as someone who fancies herself a professional coder, it's excellent, as it works, quickly, and quite elegantly. ![]()
Ta!
"Hmm, I just noticed that when I wear a bra, my back arches itself like a reflex."
Stop sticking your tits out then, you old tart.
![]()



Sorry.. you lost me at 'Chuffed'....