From: Barak Itkin Date: Sat, 4 Aug 2012 16:43:34 +0000 (+0300) Subject: Major refactor to the SVG rendering code X-Git-Tag: p2tc-0.1.0~6 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=840799732f135b609fd0f8e02e13c94528f4e012;p=poly2tri-c Major refactor to the SVG rendering code --- diff --git a/bin/main.c b/bin/main.c index 52c73ca..234a4ed 100644 --- a/bin/main.c +++ b/bin/main.c @@ -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); } diff --git a/poly2tri-c/refine/mesh.c b/poly2tri-c/refine/mesh.c index ba1dd5b..4478178 100644 --- a/poly2tri-c/refine/mesh.c +++ b/poly2tri-c/refine/mesh.c @@ -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; +} diff --git a/poly2tri-c/refine/mesh.h b/poly2tri-c/refine/mesh.h index 68a09fb..c814df4 100644 --- a/poly2tri-c/refine/mesh.h +++ b/poly2tri-c/refine/mesh.h @@ -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 diff --git a/poly2tri-c/render/svg-plot.c b/poly2tri-c/render/svg-plot.c index 708a97a..66f636c 100644 --- a/poly2tri-c/render/svg-plot.c +++ b/poly2tri-c/render/svg-plot.c @@ -39,143 +39,166 @@ #include "svg-plot.h" -void -p2tr_plot_svg_plot_group_start (const gchar *Name, FILE *outfile) -{ - if (Name == NULL) - fprintf (outfile, "" "\n"); - else - fprintf (outfile, "" "\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, "" "\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, "" "\n", color, PLOT_LINE_WIDTH); - fprintf (outfile, "" "\n"); -} + /* Begin with the header of the document */ + fprintf (out, "%s", + P2TR_SVG_NEWLINE); + fprintf (out, "%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, "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, "" "\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, "" "\n", color); - fprintf (outfile, "" "\n"); + fprintf (out, "%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, "" "\n", color, PLOT_LINE_WIDTH); - fprintf (outfile, "" "\n"); + fprintf (out, "%s", P2TR_SVG_NEWLINE); + fprintf (out, "%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, "" "\n"); - fprintf (outfile, "" "\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, "" "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, " " "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, " " "\n"); - fprintf (outfile, " " "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, "" "\n"); - fprintf (outfile, "" "\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, "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, "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, "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); } diff --git a/poly2tri-c/render/svg-plot.h b/poly2tri-c/render/svg-plot.h index e031605..a94acd6 100644 --- a/poly2tri-c/render/svg-plot.h +++ b/poly2tri-c/render/svg-plot.h @@ -35,51 +35,41 @@ #include -#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