summaryrefslogtreecommitdiff
path: root/src/svg.c
diff options
context:
space:
mode:
authorJesper Jensen <jesper@jnsn.dev>2026-07-24 20:19:48 +0200
committerJesper Jensen <jesper@jnsn.dev>2026-07-24 20:19:48 +0200
commit2667aa2806877d6fdd31b6ad34b0440197c14e1f (patch)
tree2c7fc9ded8170e3794c505c3ff50f610dd538c3e /src/svg.c
parent1af2dfbde432af9f13e8fba09b7ca29f5de71863 (diff)
Fix some layout issuesHEADmaster
Diffstat (limited to 'src/svg.c')
-rw-r--r--src/svg.c158
1 files changed, 153 insertions, 5 deletions
diff --git a/src/svg.c b/src/svg.c
index 7144482..9cdb5dc 100644
--- a/src/svg.c
+++ b/src/svg.c
@@ -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 = &current->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");