diff options
Diffstat (limited to 'src/svg.c')
| -rw-r--r-- | src/svg.c | 158 |
1 files changed, 153 insertions, 5 deletions
@@ -2,8 +2,32 @@ #define SIGNOF(x) ((typeof(x))((x)>0) - ((x)<0)) -void plot_line_between_style(struct canvas *canvas, struct point p1, struct point p2, enum LineStyle style) { +static void end_coordinate(struct canvas *canvas) { + assert(canvas->state == CANVAS_COORDINATE); + fprintf(canvas->f, "</g>\n"); + canvas->state = CANVAS_DRAWING; +} + +static void begin_coordinate(struct canvas *canvas) { + if(canvas->state == CANVAS_COORDINATE) { + end_coordinate(canvas); + } + assert(canvas->state == CANVAS_DRAWING); + fprintf(canvas->f, "<g transform=\"translate(%lf, %lf)\">\n", canvas->next_offset[0], canvas->next_offset[1]); + // canvas->next_offset[0] += 7.5; + // canvas->next_offset[1] += 7.5; + canvas->state = CANVAS_COORDINATE; +} + +static bool point_valid(struct point p) { + return !isnan(p.pos[0]) && !isnan(p.pos[1]); +} + +void plot_line_between_style(struct canvas *canvas, struct point p1, struct point p2, enum LineStyle style) { + assert(canvas->state == CANVAS_COORDINATE); + + if(!point_valid(p1) || !point_valid(p2)) return; char *style_str; switch(style) { @@ -29,7 +53,9 @@ void plot_line_between(struct canvas *canvas, struct point p1, struct point p2) } void plot_arc_between_style(struct canvas *canvas, struct point c, struct point p1, struct point p2, enum LineStyle style) { - assert(canvas->state == CANVAS_DRAWING); + assert(canvas->state == CANVAS_COORDINATE); + + if(!point_valid(p1) || !point_valid(p2) || !point_valid(c)) return; char *style_str; switch(style) { @@ -72,14 +98,35 @@ void plot_arc_between(struct canvas *canvas, struct point c, struct point p1, st plot_arc_between_style(canvas, c, p1, p2, LSTYLE_NORMAL); } +void plot_point(struct canvas *canvas, struct point p1, enum LineStyle style) { + assert(canvas->state == CANVAS_COORDINATE); + + char *style_str = ""; + switch(style) { + case LSTYLE_NORMAL: + break; + case LSTYLE_CONSTRUCTION: + style_str = "fill=\"blue\""; + break; + case LSTYLE_INDICATOR: + break; + case LSTYLE_INDICATOR_INLINE: + break; + } + + fprintf(canvas->f, "<circle %s r=\".3\" cx=\"%f\" cy=\"%f\" />\n", style_str, p1.pos[0], -p1.pos[1]); +} + void plot_text(struct canvas *canvas, struct point p, double angle, char* str) { - assert(canvas->state == CANVAS_DRAWING); + assert(canvas->state == CANVAS_COORDINATE); + + if(!point_valid(p)) return; fprintf(canvas->f, "<text text-anchor=\"middle\" dominant-baseline=\"central\" transform=\"translate(%f, %f) scale(1, -1) rotate(%f) scale(1, -1)\" font-size=\"0.75\">%s</text>\n", p.pos[0], -p.pos[1], angle * (180.0/M_PI), str); } void plot_angle(struct canvas *canvas, struct line l1, struct line l2, double theta, struct point *intersect, struct point *p1, struct point *p2) { - assert(canvas->state == CANVAS_DRAWING); + assert(canvas->state == CANVAS_COORDINATE); line_line_intersect(l1, l2, intersect); @@ -148,7 +195,7 @@ void extend_line_to(struct component* c, struct point *p) { } static void plot_distance_indicator(struct canvas *canvas, struct point p1, struct point p2, double distance, bool offset) { - assert(canvas->state == CANVAS_DRAWING); + assert(canvas->state == CANVAS_COORDINATE); vec2 dir; glm_vec2_sub(p2.pos, p1.pos, dir); @@ -226,8 +273,101 @@ void line_distance_to_point(struct line l, double d, struct point *p) { glm_vec2_muladds(perp, d, p->pos); } +static bool clip_line_box(vec2 norm, float c, vec2 min, vec2 max, vec2 out[2]) { + vec2 p; + vec2 d = { -norm[1], norm[0] }; + + if (fabsf(norm[0]) > fabsf(norm[1])) { + p[0] = -c / norm[0]; + p[1] = 0.0f; + } else { + p[0] = 0.0f; + p[1] = -c / norm[1]; + } + + float t0 = -INFINITY; + float t1 = INFINITY; + + for (int i = 0; i < 2; i++) { + if (fabsf(d[i]) < DBL_EPSILON * 1e1) { + if (p[i] < min[i] || p[i] > max[i]) + return false; + } else { + float lo = (min[i] - p[i]) / d[i]; + float hi = (max[i] - p[i]) / d[i]; + + if (lo > hi) { + float tmp = lo; + lo = hi; + hi = tmp; + } + + t0 = fmaxf(t0, lo); + t1 = fminf(t1, hi); + } + } + + if (t0 > t1) return false; + + glm_vec2_copy(p, out[0]); + glm_vec2_copy(p, out[1]); + + glm_vec2_muladds(d, t0, out[0]); + glm_vec2_muladds(d, t1, out[1]); + + return true; +} + +void draw_elements(struct canvas *canvas, struct drawing *drawing) { + assert(canvas->state == CANVAS_DRAWING); + + for(struct command *current = drawing->root; current != NULL && current != drawing->error; current = current->next) { + // if(current->hidden) continue; + if(!current->placed) continue; + + if(current->op == CMD_ORIGIN) { + begin_coordinate(canvas); + } + + switch(current->result.type) { + case ETYPE_POINT: { + plot_point(canvas, current->result.point, LSTYLE_CONSTRUCTION); + }break; + case ETYPE_CIRCLE: { + }break; + case ETYPE_LINE: { + vec2 p[2] = {}; + struct line *line = ¤t->result.line; + normalize_line(line); + clip_line_box(current->result.line.norm, current->result.line.C, (vec2){-50, -50}, (vec2){50, 50}, p); + + struct point p1 = {}; + glm_vec2_copy(p[0], p1.pos); + struct point p2 = {}; + glm_vec2_copy(p[1], p2.pos); + + plot_line_between_style(canvas, p1, p2, LSTYLE_CONSTRUCTION); + + { + struct point closestPointOnLine = {}; + glm_vec2_muladds(line->norm, -line->C, closestPointOnLine.pos); + struct point p2 = {}; + glm_vec2_copy(closestPointOnLine.pos, p2.pos); + glm_vec2_muladds(line->norm, 2, p2.pos); + plot_line_between_style(canvas, closestPointOnLine, p2, LSTYLE_NORMAL); + } + }break; + case ETYPE_VALUE: { + }break; + } + } + + if(canvas->state == CANVAS_COORDINATE) end_coordinate(canvas); +} + void draw_constraints(struct canvas *canvas, struct constraints *constraints) { assert(canvas->state == CANVAS_DRAWING); + begin_coordinate(canvas); for(size_t i = 0; i < constraints->length; i++) { struct constraint *constraint = &constraints->elements[i]; @@ -332,10 +472,12 @@ void draw_constraints(struct canvas *canvas, struct constraints *constraints) { case CT_END: abort(); } } + end_coordinate(canvas); } void draw_topology(struct canvas *canvas, struct topology *topo) { assert(canvas->state == CANVAS_DRAWING); + begin_coordinate(canvas); struct component *head = NULL; for(size_t i = 0; i < topo->length; i++) { @@ -363,6 +505,8 @@ void draw_topology(struct canvas *canvas, struct topology *topo) { abort(); } } + + end_coordinate(canvas); } void begin_drawing(struct canvas *canvas) { @@ -380,9 +524,13 @@ void begin_drawing(struct canvas *canvas) { fprintf(canvas->f, "<line x1=\"-1000\" y1=\"0\" x2=\"1000\" y2=\"0\" stroke=\"black\" stroke-width=\"0.1\" stroke-opacity=\"0.4\" />\n"); fprintf(canvas->f, "<line y1=\"-1000\" x1=\"0\" y2=\"1000\" x2=\"0\" stroke=\"black\" stroke-width=\"0.1\" stroke-opacity=\"0.4\" />\n"); canvas->state = CANVAS_DRAWING; + glm_vec2_zero(canvas->next_offset); } void end_drawing(struct canvas *canvas) { + if(canvas->state == CANVAS_COORDINATE) { + end_coordinate(canvas); + } assert(canvas->state == CANVAS_DRAWING); fprintf(canvas->f, "</svg>\n"); |
