/*
* svg2poly.ulp
* Jan 2013, By Cruz Monrreal II (Cruz.Monrreal@gmail.com)
*
* Imports Plain .svg file and will draw it as a set of polygons
* For best results, follow GitHub instructions as closely as
* possible.
*
*
* NOTE: This is not a universal .svg converter. The spec is
* simply too large, and the .ulp language is not robust
* enough to create an entire .svg parser.
*
*/
#usage "Import a Plain SVG file to a Polygon\n"
"
NOTE: Polygons will automatically be centered about the current 'mark'
"
"Usage: run svg2poly [ -ratio num ] [ -layer name ] [ -outline thickness ]"
"
Options:
"
"
"
"-ratio num | scale SVG with the given ratio, default 1 |
"
"-layer name | change layer that SVG is drawn on, default tDocu |
"
"-outline thickness | draw an outline of the given size, default 0 |
"
"
"
"Example:"
"
run svg2poly -ratio 2 -layer tDocu"
"
This will import a Plain SVG file, scale it 2x, and draw it on the tDocu layer with no outline"
"
"
""
"Cruz Monrreal |
"
"cruz.monrreal@gmail.com |
"
"http://anomalousmaker.com |
"
"
"
/* Inputs, Defaults */
string layer = "tNames";
real outline = 0.0005;
real ratioX = 0.01, ratioY = 0.01;
/* Globals */
string tmp[], master_xml;
int poly_start[], global_pts=0, num_polys=0;
real pts_x[], pts_y[];
real tmp_coords[];
real scaleFactor = 1.0; // SVG defined
string file; // filename of SVG
/* Output */
string cmd;
/*
* Stack imlemented to get around lack of recursion
*/
string stack = "";
/*** Stack Helper Functions ***/
void push(string s){ stack = (stack == "") ? s : stack + "|" + s; }
string pull()
{
string tmp;
if (stack == "")
// Nothing in stack
return "";
else if (strrstr(stack, "|") == -1){
// Stack only has one element
tmp = stack;
stack = "";
return tmp;
}
// Search for the last `|` in string
// Return string past last `|`
tmp = strsub(stack, strrstr(stack, "|") + 1);
stack = strsub(stack, 0, strrstr(stack, "|"));
return tmp;
}
/*
* Encodes all necessary information into a single string
* for stack-based recursion
*/
string pack(string xml, int global_pts)
{
string tmp;
sprintf(tmp, "%s^%d", xml, global_pts);
return tmp;
}
/*** Functions ***/
void print(string s) {printf("%s\n", s);}
/*
* Sets up the eagle commands for the script.
*/
void setup_cmd()
{
int i;
// Search for parameters
for(i=0; i= 0)
{
string scaleString = strsub(transform,scalePos+6);
scaleFactor = strtod(strsub(scaleString,0, strlen(scaleString)-1)); // trim last char ")"
}
else
{
scaleFactor = 1.0;
}
printf("Scale factor = %f\n",scaleFactor);
string svg_pts[];
int size = strsplit(svg_pts, pts, ' '),
new_pts = 0;
int i = 2;
int mode;
if(svg_pts[0] == "M"){
// Coords are Absolute
mode = 1;
sprintf(svg_pts[1], "%s,%s", svg_pts[1], svg_pts[2]);
}else{
// Coords are Relative
mode = 0;
}
poly_start[global_pts] = 1;
// Path format:
// m x,y x,y L X,Y l x,y .... z
svgcoords_to_coords(svg_pts[1]);
pts_x[global_pts] = tmp_coords[0] * scaleFactor;
pts_y[global_pts] = tmp_coords[1] * scaleFactor;
new_pts++;
printf("%2d) %2.2f,%2.2f\n", num_polys, tmp_coords[0], tmp_coords[1]);
while (i < size - 1){
if (svg_pts[i] == "m" || svg_pts[i] == "M")
{
if(svg_pts[i] == "M")
{
// Coords are Absolute
mode = 1;
sprintf(svg_pts[i], "%s,%s", svg_pts[i], svg_pts[i+1]);
}else{
// Coords are Relative
mode = 0;
}
svgcoords_to_coords(svg_pts[++i]);
if(mode == 0){
pts_x[global_pts + new_pts] += tmp_coords[0] * scaleFactor;
pts_y[global_pts + new_pts] += tmp_coords[1] * scaleFactor;
}else{
pts_x[global_pts + new_pts] = tmp_coords[0] * scaleFactor;
pts_y[global_pts + new_pts] = tmp_coords[1] * scaleFactor;
i++;
}
new_pts++;
}
else if (svg_pts[i] == "L" )
{
// Coords are Absolute, command is L
mode = 1;
}
else if (svg_pts[i] == "l")
{
// Coords are Offset, command is l
mode = 0;
}
else if (svg_pts[i] == "H")
{
// Coords are Absolute, command is H
mode = 3;
}
else if (svg_pts[i] == "h")
{
// Coords are Offset, command is h
mode = 2;
}
else if (svg_pts[i] == "V" )
{
// Coords are Absolute, command is V
mode = 5;
}
else if (svg_pts[i] == "v")
{
// Coords are Offset, command is v
mode = 4;
}
// assume numerical coords if none of the above conditions are met
else
{
if (mode == 1)
{
sprintf(svg_pts[i], "%s,%s", svg_pts[i], svg_pts[i+1]);
}
// Line-to command, parse coordinates from text
if ((mode == 0) || (mode == 1))
{
svgcoords_to_coords(svg_pts[i]);
}
// horizontal line, update X only
else if ((mode == 2) || (mode == 3))
{
mode -= 2;
tmp_coords[0] = strtod(svg_pts[i]);
}
// vertical line, update Y only
if ((mode == 4) || (mode == 5))
{
mode -= 4;
tmp_coords[1] = strtod(svg_pts[i]);
}
if (tmp_coords[0] == 0 && tmp_coords[1] == 0)
{
print("ERROR");
}
else
{
poly_start[global_pts + new_pts] = 0;
if (mode == 0)
{
pts_x[global_pts + new_pts] = pts_x[global_pts + new_pts - 1] + tmp_coords[0] * scaleFactor;
pts_y[global_pts + new_pts] = pts_y[global_pts + new_pts - 1] + tmp_coords[1] * scaleFactor;
}
else if (mode == 1)
{
pts_x[global_pts + new_pts] = tmp_coords[0] * scaleFactor;
pts_y[global_pts + new_pts] = tmp_coords[1] * scaleFactor;
}
printf(" %2.2f,%2.2f\n", pts_x[global_pts + new_pts], pts_y[global_pts + new_pts]);
poly_start[global_pts + new_pts] = 0;
new_pts++;
}
}
i++;
}
// Close the polygon with the starting point
svgcoords_to_coords(svg_pts[1]);
pts_x[global_pts + new_pts] = tmp_coords[0] * scaleFactor;
pts_y[global_pts + new_pts] = tmp_coords[1] * scaleFactor;
new_pts++;
global_pts += new_pts;
num_polys++;
}
/*
* Traverse through the tree of groups, adding points to paths,
* while applying group transforms in the process
*/
void extract_nested_data()
{
string xml[];
string elements[];
string tags[];
int size;
while(stack != ""){
// Pop xml to parse
strsplit(xml, pull(), '^');
// Find name of root
string tmp[], root;
xmltags(tmp, xml[0], "");
root = tmp[0];
if (root == "path"){
// Path found
print(" PATH " + xmlattribute(xml[0], "path", "id") + " FOUND ");
extract_pts(xmlattribute(xml[0], "path", "d"), xmlattribute(xml[0], "path", "transform"));
//}else if (root == ""){
// Add more cases here
}else{
int a = xmltags(tags, xml[0], root);
for(int i=0; i max_x)
max_x = pts_x[i];
if (pts_y[i] < min_y)
min_y = pts_y[i];
if (pts_y[i] > max_y)
max_y = pts_y[i];
}
real x_center = (max_x - min_x)/2,
y_center = (max_y - min_y)/2;
// Apply offsets to all points
for(i=0; i < global_pts; i++){
pts_x[i] -= min_x + x_center;
pts_y[i] -= min_y + y_center;
}
printf("\nObject origin:\n%f %f\n", x_center, y_center);
// Generate eagle command
for(i=0; i