SVG output for cad3d - 2nd attempt

John Pybus john@pybus.org
Wed, 05 May 2004 00:25:13 +0100


This is a multi-part message in MIME format.
--------------090707080105060605060601
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

...and this time, as a special bonus, it even creates maps that're the 
right way up!

It also sets the initial viewport to match the scale specified.

Yours,

John

--------------090707080105060605060601
Content-Type: text/plain;
 name="cad3d.patch2"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="cad3d.patch2"

--- src/cad3d.c.orig	2004-05-03 23:45:21.000000000 +0100
+++ src/cad3d.c	2004-05-05 00:15:31.000000000 +0100
@@ -49,6 +49,12 @@
 #define POINTS_PER_INCH	72.0
 #define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
 
+#define SQRT_2          1.41421356237309504880168872420969
+
+#define LEGS 1
+#define STNS 2
+#define LABELS 4
+
 /* default to DXF */
 #define FMT_DEFAULT FMT_DXF
 
@@ -62,6 +68,7 @@
 static double grid; /* grid spacing (or 0 for no grid) */
 static double scale = 500.0;
 static double factor;
+static const char *unit = "mm";
 
 static img *pimg;
 static const char *survey = NULL;
@@ -333,26 +340,6 @@
 static point **htab;
 
 static void
-plt_header(void)
-{
-   size_t i;
-   htab = osmalloc(HTAB_SIZE * ossizeof(point *));
-   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
-   /* Survex is E, N, Alt - PLT file is N, E, Alt */
-   fprintf(fh, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
-           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
-           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
-           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
-   fprintf(fh, "N%s D 1 1 1 C%s\r\n", survey ? survey : "X", pimg->title);
-}
-
-static void
-plt_start_pass(int layer)
-{
-   layer = layer;
-}
-
-static void
 set_name(const img_point *p, const char *s)
 {
    int hash;
@@ -368,9 +355,9 @@
    hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
    for (pt = htab[hash]; pt; pt = pt->next) {
       if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z) {
-	 /* already got name for these coordinates */
-	 /* FIXME: what about multiple names for the same station? */
-	 return;
+         /* already got name for these coordinates */
+         /* FIXME: what about multiple names for the same station? */
+         return;
       }
    }
 
@@ -406,6 +393,122 @@
 }
 
 static void
+svg_header(void)
+{
+   size_t i;
+   htab = osmalloc(HTAB_SIZE * ossizeof(point *));
+   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
+   fprintf(fh, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
+   fprintf(fh, "<svg width=\"%.3f%s\" height=\"%.3f%s\""
+               " viewBox=\"0 0 %0.3f %0.3f\">\n",
+           (max_x - min_x) * factor, unit, (max_y - min_y) * factor, unit,
+           (max_x - min_x) * factor, (max_y - min_y) * factor );
+   fprintf(fh, "<g transform=\"translate(%.3f %.3f)\">\n",
+           min_x * -factor, max_y * factor);
+}
+
+static bool to_close = 0;
+static bool close_g = 0;
+
+static void
+svg_start_pass(int layer)
+{
+   if (to_close) {
+      fprintf(fh, "\"/>\n");
+      to_close = 0;
+   }
+   if (close_g) {
+      fprintf(fh, "</g>\n");
+   }
+   close_g = 1;
+
+   fprintf(fh, "<g id=\"%s\"", layer_names[layer]);
+   if (layer & LEGS)
+      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.4\"");
+   else if (layer & STNS)
+      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.05\"");
+   else if (layer & LABELS)
+      fprintf(fh, " style=\"font-size:%.3f\"", text_height);
+   fprintf(fh, ">\n");
+}
+
+static void
+svg_move(const img_point *p)
+{
+   if (to_close) {
+      fprintf(fh, "\"/>\n");
+   }
+   fprintf(fh, "<path d=\"M %.3f %.3f",
+           p->x * factor, p->y * -factor);
+   to_close = 1;
+}
+
+static void
+svg_line(const img_point *p1, const img_point *p, bool fSurface)
+{
+   fSurface = fSurface; /* unused */
+   p1 = p1; /* unused */
+   fprintf(fh, "L%.3f %.3f", p->x * factor, p->y * -factor);
+   to_close = 1;
+}
+
+static void
+svg_label(const img_point *p, const char *s, bool fSurface)
+{
+   fSurface = fSurface; /* unused */
+   fprintf(fh, "<text transform=\"translate(%.3f %.3f)\">",
+           p->x * factor, p->y * -factor);
+   fprintf(fh, s);
+   fprintf(fh, "</text>\n");
+   set_name(p, s);
+}
+
+static void
+svg_cross(const img_point *p, bool fSurface)
+{
+   fSurface = fSurface; /* unused */
+   fprintf(fh, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
+           find_name(p), p->x * factor,
+           p->y * -factor, MARKER_SIZE * SQRT_2);
+   fprintf(fh, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
+	   p->x * factor - MARKER_SIZE, p->y * -factor - MARKER_SIZE,
+	   p->x * factor + MARKER_SIZE, p->y * -factor + MARKER_SIZE,
+	   p->x * factor + MARKER_SIZE, p->y * -factor - MARKER_SIZE,
+	   p->x * factor - MARKER_SIZE, p->y * -factor + MARKER_SIZE );
+}
+
+static void
+svg_footer(void) ////
+{
+   if (to_close) {
+      fprintf(fh, "\"/>\n");
+      to_close = 0;
+   }
+   fprintf(fh, "</g>\n");
+   fprintf(fh, "</g>\n</svg>");
+}
+
+static void
+plt_header(void)
+{
+   size_t i;
+   htab = osmalloc(HTAB_SIZE * ossizeof(point *));
+   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
+   /* Survex is E, N, Alt - PLT file is N, E, Alt */
+   fprintf(fh, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
+           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
+           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
+           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
+   fprintf(fh, "N%s D 1 1 1 C%s\r\n", survey ? survey : "X", pimg->title);
+}
+
+static void
+plt_start_pass(int layer)
+{
+   layer = layer;
+}
+
+static void
 plt_move(const img_point *p)
 {
    /* Survex is E, N, Alt - PLT file is N, E, Alt */
@@ -458,12 +561,10 @@
    putc('\x1a', fh);
 }
 
-#define LEGS 1
-#define STNS 2
-#define LABELS 4
 static int dxf_passes[] = { LEGS|STNS|LABELS, 0 };
 static int sketch_passes[] = { LEGS, STNS, LABELS, 0 };
 static int plt_passes[] = { LABELS, LEGS, 0 };
+static int svg_passes[] = { LEGS, LABELS, STNS, 0 };
 
 int
 main(int argc, char **argv)
@@ -476,8 +577,8 @@
    int elevation = 0;
    double elev_angle = 0;
    double s = 0, c = 0;
-   enum { FMT_DXF = 0, FMT_SKETCH, FMT_PLT, FMT_AUTO } format;
-   static const char *extensions[] = { "dxf", "sk", "plt" };
+   enum { FMT_DXF = 0, FMT_SKETCH, FMT_PLT, FMT_SVG, FMT_AUTO } format;
+   static const char *extensions[] = { "dxf", "sk", "plt", "svg" };
    int *pass;
 
    void (*header)(void);
@@ -504,12 +605,13 @@
 	{"dxf", no_argument, 0, 'D'},
 	{"sketch", no_argument, 0, 'S'},
 	{"plt", no_argument, 0, 'P'},
+        {"svg", no_argument, 0, 'V'},
 	{"help", no_argument, 0, HLP_HELP},
 	{"version", no_argument, 0, HLP_VERSION},
 	{0,0,0,0}
    };
 
-#define short_opts "s:cnlg::t:m:e:r:DSP"
+#define short_opts "s:cnlg::t:m:e:r:DSPV"
 
    /* TRANSLATE */
    static struct help_msg help[] = {
@@ -525,6 +627,7 @@
 	{HLP_ENCODELONG(9), "produce DXF output"},
 	{HLP_ENCODELONG(10), "produce Sketch output"},
 	{HLP_ENCODELONG(11), "produce Compass PLT output for Carto"},
+        {HLP_ENCODELONG(12), "produce SVG output"},
 	{0,0}
    };
 
@@ -588,6 +691,9 @@
        case 'P':
 	 format = FMT_PLT;
 	 break;
+       case 'V':
+         format = FMT_SVG;
+         break;
        case 's':
 	 survey = optarg;
 	 break;
@@ -656,6 +762,18 @@
       pass = plt_passes;
       mode = "wb"; /* Binary file output */
       break;
+    case FMT_SVG:
+      header = svg_header;
+      start_pass = svg_start_pass;
+      move = svg_move;
+      line = svg_line;
+      label = svg_label;
+      cross = svg_cross;
+      footer = svg_footer;
+      pass = svg_passes;
+      factor = 1000.0 / scale;
+      mode = "wb"; /* Binary file output */
+      break;
     default:
       exit(1);
    }

--------------090707080105060605060601--