]> granicus.if.org Git - poly2tri-c/commitdiff
Major refactor to the SVG rendering code
authorBarak Itkin <lightningismyname@gmail.com>
Sat, 4 Aug 2012 16:43:34 +0000 (19:43 +0300)
committerBarak Itkin <lightningismyname@gmail.com>
Sat, 4 Aug 2012 16:43:34 +0000 (19:43 +0300)
bin/main.c
poly2tri-c/refine/mesh.c
poly2tri-c/refine/mesh.h
poly2tri-c/render/svg-plot.c
poly2tri-c/render/svg-plot.h

index 52c73cae787c88901b15c63a603ba9e59dcc54a8..234a4ed11f7e0cc694268b7ac17cf15851e6636b 100644 (file)
@@ -394,7 +394,7 @@ gint main (int argc, char *argv[])
   if (render_svg)
     {
       g_print ("Rendering SVG outline!");
-      p2tr_plot_svg (rcdt->mesh, svg_out);
+      p2tr_render_svg (rcdt->mesh, svg_out);
       fclose (svg_out);
     }
 
index ba1dd5bc7356220a544131591991422c39907d14..44781780b72c002166145808110a85d044563ef8 100644 (file)
@@ -374,3 +374,33 @@ p2tr_mesh_find_point_local2 (P2trMesh          *self,
 
   return result;
 }
+
+void
+p2tr_mesh_get_bounds (P2trMesh    *self,
+                      gdouble     *min_x,
+                      gdouble     *min_y,
+                      gdouble     *max_x,
+                      gdouble     *max_y)
+{
+  gdouble lmin_x = + G_MAXDOUBLE, lmin_y = + G_MAXDOUBLE;
+  gdouble lmax_x = - G_MAXDOUBLE, lmax_y = - G_MAXDOUBLE;
+
+  P2trHashSetIter iter;
+  P2trPoint *pt;
+
+  p2tr_hash_set_iter_init (&iter, self->points);
+  while (p2tr_hash_set_iter_next (&iter, (gpointer*) &pt))
+    {
+      gdouble x = pt->c.x;
+      gdouble y = pt->c.y;
+
+      lmin_x = MIN (lmin_x, x);
+      lmin_y = MIN (lmin_y, y);
+      lmax_x = MAX (lmax_x, x);
+      lmax_y = MAX (lmax_y, y);
+    }
+  *min_x = lmin_x;
+  *min_y = lmin_y;
+  *max_x = lmax_x;
+  *max_y = lmax_y;
+}
index 68a09fb000de54693290ae6bf08e9d87b0aea964..c814df4585bd75a65f5d6b185587d0fb37cfdcb1 100644 (file)
@@ -344,5 +344,18 @@ P2trTriangle* p2tr_mesh_find_point_local2 (P2trMesh *self,
                                            gdouble *u,
                                            gdouble *v);
 
+/**
+ * Find the bounding rectangle containing this mesh.
+ * @param[in] self The mesh whose bounding rectangle should be computed
+ * @param[out] min_x The minimal X coordinate of the mesh
+ * @param[out] min_y The minimal Y coordinate of the mesh
+ * @param[out] max_x The maximal X coordinate of the mesh
+ * @param[out] max_y The maximal Y coordinate of the mesh
+ */
+void          p2tr_mesh_get_bounds        (P2trMesh    *self,
+                                           gdouble     *min_x,
+                                           gdouble     *min_y,
+                                           gdouble     *max_x,
+                                           gdouble     *max_y);
 /** @} */
 #endif
index 708a97afeb57f35bfb9812700a40ed70be917c32..66f636cc5e50ed23aacd41db8ae97411bbb14962 100644 (file)
 
 #include "svg-plot.h"
 
-void
-p2tr_plot_svg_plot_group_start (const gchar *Name, FILE *outfile)
-{
-  if (Name == NULL)
-    fprintf (outfile, "<g>" "\n");
-  else
-    fprintf (outfile, "<g name=\"%s\">" "\n", Name);
-}
+#define P2TR_SVG_NEWLINE "\n"
 
 void
-p2tr_plot_svg_plot_group_end (FILE *outfile)
+p2tr_render_svg_init (FILE              *out,
+                      const P2trVector2 *bottom_left,
+                      const P2trVector2 *top_right)
 {
-  fprintf (outfile, "</g>" "\n");
-}
+  gdouble real_width = top_right->x - bottom_left->x;
+  gdouble real_height = top_right->y - bottom_left->y;
 
-void
-p2tr_plot_svg_plot_line (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar *color, FILE *outfile)
-{
-  fprintf (outfile, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"" "\n", x1, y1, x2, y2);
-  fprintf (outfile, "style=\"stroke: %s; stroke-width: %f\" />" "\n", color, PLOT_LINE_WIDTH);
-  fprintf (outfile, "" "\n");
-}
+  /* Begin with the header of the document */
+  fprintf (out, "<?xml version=\"1.0\" standalone=\"no\"?>%s",
+      P2TR_SVG_NEWLINE);
+  fprintf (out, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"%s",
+      P2TR_SVG_NEWLINE);
+  fprintf (out, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">%s",
+      P2TR_SVG_NEWLINE);
 
-void
-p2tr_plot_svg_plot_arrow (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar* color, FILE *outfile)
-{
-  gdouble dy = y2 - y1;
-  gdouble dx = x2 - x1;
-  gdouble angle = atan2 (dy, dx);
-  gdouble temp = angle - ARROW_SIDE_ANGLE;
+  fprintf (out, "<svg xmlns=\"http://www.w3.org/2000/svg\""
+                "     version=\"1.1\"%s", P2TR_SVG_NEWLINE);
 
-  p2tr_plot_svg_plot_line (x1, y1, x2, y2, color, outfile);
+  fprintf (out, "     viewBox=\"%f %f %f %f\"%s",
+      + bottom_left->x, - (bottom_left->y + real_height),
+      + real_width,     + real_height,
+      P2TR_SVG_NEWLINE);
 
-  p2tr_plot_svg_plot_line (x2, y2, x2 - ARROW_HEAD_SIZE * cos (temp), y2 - ARROW_HEAD_SIZE * sin (temp), color, outfile);
-
-  temp = angle + ARROW_SIDE_ANGLE;
-  p2tr_plot_svg_plot_line (x2, y2, x2 - ARROW_HEAD_SIZE * cos (temp), y2 - ARROW_HEAD_SIZE * sin (temp), color, outfile);
-}
+  fprintf (out, "     preserveAspectRatio=\"xMidYMid meet\"%s",
+      P2TR_SVG_NEWLINE);
 
-void
-p2tr_plot_svg_fill_triangle (gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, const gchar *color, FILE *outfile)
-{
-  fprintf (outfile, "<polyline points=\"%f,%f %f,%f %f,%f\"" "\n", x1, y1, x2, y2, x3, y3);
-  fprintf (outfile, "style=\"fill: %s\" />" "\n", color);
-  fprintf (outfile, "" "\n");
-}
+  /* Close the SVG tag */
+  fprintf (out, ">%s", P2TR_SVG_NEWLINE);
 
-void
-p2tr_plot_svg_fill_point (gdouble x1, gdouble y1, const gchar* color, FILE *outfile)
-{
-  fprintf (outfile, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\"" "\n", x1, y1, MAX (1, PLOT_LINE_WIDTH));
-  fprintf (outfile, "style=\"fill: %s; stroke: none\" />" "\n", color);
-  fprintf (outfile, "" "\n");
+  fprintf (out, "<g transform=\"scale(1,-1)\">%s",
+      P2TR_SVG_NEWLINE);
 }
 
 void
-p2tr_plot_svg_plot_circle (gdouble xc, gdouble yc, gdouble R, const gchar* color, FILE *outfile)
+p2tr_render_svg_finish (FILE *out)
 {
-  fprintf (outfile, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\"" "\n", xc, yc, R);
-  fprintf (outfile, "style=\"stroke: %s; stroke-width: %f; fill: none\" />" "\n", color, PLOT_LINE_WIDTH);
-  fprintf (outfile, "" "\n");
+  fprintf (out, "</g>%s", P2TR_SVG_NEWLINE);
+  fprintf (out, "</svg>%s", P2TR_SVG_NEWLINE);
 }
 
-void
-p2tr_plot_svg_plot_end (FILE *outfile)
+static void
+p2tr_render_svg_style (FILE           *out,
+                       P2trSVGContext *context,
+                       gboolean        no_fill)
 {
-  fprintf (outfile, "</g>" "\n");
-  fprintf (outfile, "</svg>" "\n");
+  fprintf (out, "style=\"");
+    {
+      if (context->stroke)
+        {
+          fprintf (out, "stroke: #%02x%02x%02x; stroke-opacity: %f; ",
+              context->stroke_color[0], context->stroke_color[1],
+              context->stroke_color[2], context->stroke_color[3] / 255.0);
+          fprintf (out, "stroke-:width: %f; stroke-linejoin: round; ",
+              context->stroke_width);
+        }
+
+      if (context->fill && ! no_fill)
+        fprintf (out, "fill: #%02x%02x%02x; fill-opacity: %f; ",
+            context->fill_color[0], context->fill_color[1],
+            context->fill_color[2], context->fill_color[3] / 255.0);
+
+      if (context->opacity != 1)
+        fprintf (out, "opacity: %f; ", context->opacity);
+    }
+  fprintf (out, "\"");
 }
 
 void
-p2tr_plot_svg_plot_init (FILE *outfile)
+p2tr_render_svg_draw_line (FILE              *out,
+                           P2trSVGContext    *context,
+                           const P2trVector2 *start,
+                           const P2trVector2 *end)
 {
-  fprintf (outfile, "<?xml version=\"1.0\" standalone=\"no\"?>" "\n");
-  fprintf (outfile, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" "\n");
-  fprintf (outfile, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" "\n");
-  fprintf (outfile, "<svg width=\"100%%\" height=\"100%%\" version=\"1.1\"" "\n");
-  fprintf (outfile, "xmlns=\"http://www.w3.org/2000/svg\">" "\n");
-  fprintf (outfile, "" "\n");
-  fprintf (outfile, "<defs>" "\n");
-  fprintf (outfile, "  <marker id=\"arrow\" viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\"" "\n");
-  fprintf (outfile, "     markerUnits=\"strokeWidth\" orient=\"auto\"" "\n");
-  fprintf (outfile, "     markerWidth=\"12\" markerHeight=\"9\">" "\n");
-  fprintf (outfile, "" "\n");
-  fprintf (outfile, "     <polyline points=\"0,0 10,5 0,10\" fill=\"none\" stroke-width=\"2px\" stroke=\"inherit\" />" "\n");
-  fprintf (outfile, "  </marker>" "\n");
-  fprintf (outfile, "</defs>" "\n");
-  fprintf (outfile, "" "\n");
-  fprintf (outfile, "<g transform=\"translate(%f,%f)  scale(%f,-%f)\">" "\n", X_TRANSLATE, Y_TRANSLATE, X_SCALE, Y_SCALE);
-
-  p2tr_plot_svg_plot_arrow (-20, 0, 100, 0, "black", outfile);
-  p2tr_plot_svg_plot_arrow (0, -20, 0, 100, "black", outfile);
+  fprintf (out, "<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
+      start->x, start->y, end->x, end->y);
+  p2tr_render_svg_style (out, context, TRUE);
+  fprintf (out, " />%s", P2TR_SVG_NEWLINE);
 }
 
 void
-p2tr_plot_svg_plot_edge (P2trEdge *self, const gchar* color, FILE* outfile)
+p2tr_render_svg_draw_triangle (FILE              *out,
+                               P2trSVGContext    *context,
+                               const P2trVector2 *p1,
+                               const P2trVector2 *p2,
+                               const P2trVector2 *p3)
 {
-  gdouble x1 = P2TR_EDGE_START (self)->c.x;
-  gdouble y1 = P2TR_EDGE_START (self)->c.y;
-  gdouble x2 = self->end->c.x;
-  gdouble y2 = self->end->c.y;
-
-  p2tr_plot_svg_plot_line (x1, y1, x2, y2, color, outfile);
-
-#if FALSE
-  if (p2tr_edge_is_encroached (self))
-    p2tr_plot_svg_plot_circle ((x1 + x2) / 2, (y1 + y2) / 2, R, "red", outfile);
-#endif
+  fprintf (out, "<polygon points=\"%f,%f %f,%f %f,%f\" ",
+      p1->x, p1->y, p2->x, p2->y, p3->x, p3->y);
+  p2tr_render_svg_style (out, context, FALSE);
+  fprintf (out, " />%s", P2TR_SVG_NEWLINE);
 }
 
 void
-p2tr_plot_svg_plot_triangle (P2trTriangle *self, const gchar* color, FILE* outfile)
+p2tr_render_svg_draw_circle (FILE              *out,
+                             P2trSVGContext    *context,
+                             const P2trVector2 *center,
+                             gdouble            radius)
 {
-  P2trCircle c;
-  p2tr_triangle_get_circum_circle (self, &c);
-  p2tr_plot_svg_plot_edge (self->edges[0], color, outfile);
-  p2tr_plot_svg_plot_edge (self->edges[1], color, outfile);
-  p2tr_plot_svg_plot_edge (self->edges[2], color, outfile);
-  p2tr_plot_svg_plot_circle (c.center.x, c.center.y, c.radius, "green", outfile);
-  p2tr_plot_svg_fill_point (self->edges[0]->end->c.x, self->edges[0]->end->c.y, "blue", outfile);
-  p2tr_plot_svg_fill_point (self->edges[1]->end->c.x, self->edges[1]->end->c.y, "blue", outfile);
-  p2tr_plot_svg_fill_point (self->edges[2]->end->c.x, self->edges[2]->end->c.y, "blue", outfile);
+  fprintf (out, "<circle cx=\"%f\" cy=\"%f\" r=\"%f\" ",
+      center->x, center->y, radius);
+  p2tr_render_svg_style (out, context, FALSE);
+  fprintf (out, " />%s", P2TR_SVG_NEWLINE);
 }
 
 void
-p2tr_plot_svg (P2trMesh *T, FILE *outfile)
+p2tr_render_svg (P2trMesh *mesh,
+                 FILE     *out)
 {
   P2trHashSetIter  siter;
   P2trTriangle    *tr;
-
-  g_debug ("Starting to write SVG output\n");
-  p2tr_plot_svg_plot_init (outfile);
-
-  p2tr_hash_set_iter_init (&siter, T->triangles);
+  P2trPoint       *pt;
+
+  /* Colors taken from the Tango Icon Theme color palette */
+  P2trSVGContext  TRI = {
+      TRUE,
+      1,
+      /* Sky Blue 3 */
+      { 32, 74, 135, 255 },
+      TRUE,
+      /* Sky Blue 1 */
+      { 114, 159, 207, 255 },
+      1
+  };
+
+  P2trSVGContext PT = {
+      FALSE,
+      0,
+      /* Orange 3 */
+      { 206, 92, 0, 1 },
+      TRUE,
+      /* Orange 1 */
+      { 245, 121, 0, 255 },
+      1
+  };
+
+  P2trVector2 bottom_left, top_right;
+
+  p2tr_mesh_get_bounds (mesh,
+      &bottom_left.x, &bottom_left.y,
+      &top_right.x,   &top_right.y);
+
+  bottom_left.x -= 10;
+  bottom_left.y -= 10;
+  top_right.x += 10;
+  top_right.y += 10;
+  p2tr_render_svg_init (out, &bottom_left, &top_right);
+
+  p2tr_hash_set_iter_init (&siter, mesh->triangles);
   while (p2tr_hash_set_iter_next (&siter, (gpointer*)&tr))
-    p2tr_plot_svg_plot_triangle (tr, "black", outfile);
+    p2tr_render_svg_draw_triangle (out, &TRI,
+        &P2TR_TRIANGLE_GET_POINT(tr, 0)->c,
+        &P2TR_TRIANGLE_GET_POINT(tr, 1)->c,
+        &P2TR_TRIANGLE_GET_POINT(tr, 2)->c);
+
+  p2tr_hash_set_iter_init (&siter, mesh->points);
+  while (p2tr_hash_set_iter_next (&siter, (gpointer*)&pt))
+    p2tr_render_svg_draw_circle (out, &PT, &pt->c, 1);
 
-  p2tr_plot_svg_plot_end (outfile);
-  g_debug ("Finished writing SVG output\n");
+  p2tr_render_svg_finish (out);
 }
index e031605a48711b789bd709ef52b16b4a3d6a4890..a94acd64b53a6fee100158a96846bf24f25d3d35 100644 (file)
 
 #include <poly2tri-c/refine/refine.h>
 
-#define PLOT_LINE_WIDTH 0.40
-#define ARROW_SIDE_ANGLE (G_PI / 180 * 30)
-#define ARROW_HEAD_SIZE 2.0
-
-#define X_SCALE 1.
-#define Y_SCALE 1.
-#define X_TRANSLATE 500.
-#define Y_TRANSLATE 500.
-
-void
-p2tr_plot_svg_plot_group_start (const gchar *Name, FILE* outfile);
-
-void
-p2tr_plot_svg_plot_group_end (FILE* outfile);
-
-void
-p2tr_plot_svg_plot_line (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar *color, FILE* outfile);
-
-void
-p2tr_plot_svg_plot_arrow (gdouble x1, gdouble y1, gdouble x2, gdouble y2, const gchar* color, FILE* outfile);
-
-void
-p2tr_plot_svg_fill_triangle (gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, const gchar *color, FILE* outfile);
-
-void
-p2tr_plot_svg_fill_point (gdouble x1, gdouble y1, const gchar* color, FILE* outfile);
-
-void
-p2tr_plot_svg_plot_circle (gdouble xc, gdouble yc, gdouble R, const gchar* color, FILE* outfile);
-
-void
-p2tr_plot_svg_plot_end (FILE* outfile);
-
-void
-p2tr_plot_svg_plot_init (FILE* outfile);
-
-void
-p2tr_plot_svg_plot_edge (P2trEdge *self, const gchar* color, FILE* outfile);
-
-void
-p2tr_plot_svg_plot_triangle (P2trTriangle *self, const gchar* color, FILE* outfile);
-
-#define r() (10+(rand () % 91))
-
-void
-p2tr_plot_svg (P2trMesh *T, FILE* outfile);
+typedef guint8 P2trSVGColor[4];
+
+typedef struct
+{
+  gboolean     stroke;
+  gdouble      stroke_width;
+  P2trSVGColor stroke_color;
+  gboolean     fill;
+  P2trSVGColor fill_color;
+  gdouble      opacity;
+} P2trSVGContext;
+
+void p2tr_render_svg_init          (FILE              *out,
+                                    const P2trVector2 *bottom_left,
+                                    const P2trVector2 *top_right);
+
+void p2tr_render_svg_draw_line     (FILE              *out,
+                                    P2trSVGContext    *context,
+                                    const P2trVector2 *start,
+                                    const P2trVector2 *end);
+
+void p2tr_render_svg_draw_triangle (FILE              *out,
+                                    P2trSVGContext    *context,
+                                    const P2trVector2 *p1,
+                                    const P2trVector2 *p2,
+                                    const P2trVector2 *p3);
+
+void p2tr_render_svg_draw_circle   (FILE              *out,
+                                    P2trSVGContext    *context,
+                                    const P2trVector2 *center,
+                                    gdouble            radius);
+
+void p2tr_render_svg_finish        (FILE              *out);
+
+void p2tr_render_svg               (P2trMesh          *mesh,
+                                    FILE              *out);
 
 #endif