summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesper Jensen <jesper@jnsn.dev>2026-03-29 12:07:19 +0200
committerJesper Jensen <jesper@jnsn.dev>2026-03-29 12:07:19 +0200
commite49c0ac340da53f3460a2aa02b514340ab0866e0 (patch)
treef96fd5ec9fb085e0f4a55554bebcd8e5fc7e626c
parent770216abb4bde565f824eb9010ae641ae118bb2d (diff)
Start testing as a cad tool
-rw-r--r--examples/mount.c119
-rw-r--r--examples/triangle_tip.c2
-rw-r--r--src/solve.c18
-rw-r--r--src/svg.c2
-rw-r--r--test/solve.c19
5 files changed, 141 insertions, 19 deletions
diff --git a/examples/mount.c b/examples/mount.c
new file mode 100644
index 0000000..7ffdc34
--- /dev/null
+++ b/examples/mount.c
@@ -0,0 +1,119 @@
+#include "cad.h"
+
+void draw_from_constraints(struct constraints *c, struct topology *t, struct canvas *cv) {
+ struct drawing drawing = {};
+ struct subassembly assemblies[16] = {};
+ size_t assemblies_num;
+ bool rc = solve_constraints(c, &drawing, assemblies, &assemblies_num);
+ assert(rc);
+
+ // Copy over all the parameter values to a new array
+ // @PERF: Maybe we should just store them in a separate array to start with
+ double *params = malloc(sizeof(double) * (c->length));
+ for(size_t i = 0; i < c->length; i++) {
+ params[i] = c->elements[i].v;
+ }
+
+ place_points(&drawing, params);
+ free(params);
+
+ reconstruct_drawing(c, assemblies, &assemblies_num);
+
+ begin_drawing(cv);
+ draw_topology(cv, t);
+ draw_constraints(cv, c);
+ end_drawing(cv);
+
+ free_drawing(&drawing);
+}
+
+int main(int argc, char *argv[]) {
+ struct constraints constraints = {};
+ struct topology topo = {};
+
+ struct component mid_bot = {.type = COM_POINT};
+ struct component pseudo = {.type = COM_POINT};
+ struct component bot = {.type = COM_LINE};
+
+ struct component symmetry = {.type = COM_LINE};
+
+ struct component right_lower = {.type = COM_LINE};
+ struct component left_lower = {.type = COM_LINE};
+
+ struct component right_under_hole_mid = {.type = COM_POINT};
+
+ struct component right_hole_bot_tan = {.type = COM_LINE};
+ struct component left_hole_bot_tan = {.type = COM_LINE};
+ struct component right_hole_top_tan = {.type = COM_LINE};
+ struct component left_hole_top_tan = {.type = COM_LINE};
+
+ struct component right_hole_mid = {.type = COM_POINT};
+ struct component left_hole_mid = {.type = COM_POINT};
+
+ struct component swoop_mid = {.type = COM_POINT};
+ struct component swoop_top_tan = {.type = COM_POINT};
+
+ struct component left_bend = {.type = COM_POINT};
+ struct component lb2 = {.type = COM_POINT};
+
+ struct component l1 = {.type = COM_LINE};
+
+ add_constraint(&constraints, (struct constraint[]){
+ PP_DISTANCE(&mid_bot, &pseudo, 10),
+ POINT_ON_LINE(&mid_bot, &bot),
+ POINT_ON_LINE(&pseudo, &bot),
+
+ LL_ANGLE(&bot, &symmetry, DEG(90)),
+ POINT_ON_LINE(&mid_bot, &symmetry),
+
+ // @HACK This is going in the wrong direction?
+ PL_DISTANCE(&mid_bot, &right_lower, 35),
+ LL_ANGLE(&bot, &right_lower, DEG(-90)),
+ PL_DISTANCE(&left_lower, &mid_bot, 35),
+ LL_ANGLE(&bot, &left_lower, DEG(90)),
+
+ PL_DISTANCE(&right_hole_mid, &bot, 80),
+ PL_DISTANCE(&left_hole_mid, &bot, 80),
+ PL_DISTANCE(&right_hole_mid, &symmetry, -60),
+ PL_DISTANCE(&left_hole_mid, &symmetry, 60),
+
+ PL_DISTANCE(&right_under_hole_mid, &right_lower, 20),
+ PL_DISTANCE(&right_under_hole_mid, &right_hole_bot_tan, 20),
+
+ LL_ANGLE(&right_hole_bot_tan, &symmetry, DEG(270)),
+
+ PL_DISTANCE(&right_hole_mid, &right_hole_bot_tan, -28),
+ // PL_DISTANCE(&left_hole_mid, &left_hole_bot_tan, 56),
+ PL_DISTANCE(&right_hole_mid, &right_hole_top_tan, 28),
+ // PL_DISTANCE(&left_hole_mid, &left_hole_top_tan, 56),
+
+ POINT_ON_LINE(&swoop_mid, &symmetry),
+ PP_DISTANCE(&swoop_mid, &right_hole_mid, 120 - 28),
+ // PL_DISTANCE(&swoop_mid, &swoop_top_tan, 120),
+ PL_DISTANCE(&swoop_mid, &right_hole_top_tan, 120),
+
+
+ // Make a triangle
+ CEND(),
+ });
+
+ add_fragment(&topo, (struct topology_elem[]){
+ TOPO_MOVETO(&mid_bot),
+ TOPO_LINETO(&right_hole_mid),
+
+ TOPO_MOVETO(&mid_bot),
+ // TOPO_LINETO(&p2),
+ // TOPO_LINETO(&p3),
+ TOPO_END(),
+ });
+
+ struct canvas canvas = {
+ .state = CANVAS_INIT,
+ .f = stdout,
+ };
+
+ draw_from_constraints(&constraints, &topo, &canvas);
+
+ free_constraints(&constraints);
+ return 0;
+}
diff --git a/examples/triangle_tip.c b/examples/triangle_tip.c
index b6fcf99..4da57da 100644
--- a/examples/triangle_tip.c
+++ b/examples/triangle_tip.c
@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
POINT_ON_LINE(&p2, &t1base),
POINT_ON_LINE(&p1, &t1bas2),
- LL_ANGLE(&t1base, &t1bas2, DEG(-10)),
+ LL_ANGLE(&t1base, &t1bas2, DEG(-5)),
// With another triangle sharing a point
PP_DISTANCE(&p4, &p5, 30),
diff --git a/src/solve.c b/src/solve.c
index 5b3cdce..66cbb7f 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -810,8 +810,8 @@ constraint_matches_j:
// Here we have two assemblies, one fixed and the other not,
// that share a single point and each one other point that
- // share a constraint. We can hopefully place the rest of the
- // assembly from that information
+ // share a constraint. Try place the rigid body based on that
+ // information
float theta = atan2(constraint->c1->e->line.norm[1], constraint->c1->e->line.norm[0]) - atan2(constraint->c2->e->line.norm[1], constraint->c2->e->line.norm[0]);
theta = forward ? -theta : theta;
@@ -865,22 +865,22 @@ constraint_matches_j:
// Find a point on the line, what point doesn't matter
// since the whole line is moving
struct line line = c->e->line;
- double a = line.norm[0];
- double b = line.norm[1];
- double rec = pow(a, 2) + pow(b, 2);
- double x0 = -a*line.C / rec;
- double y0 = -b*line.C / rec;
- vec2 p = {x0, y0};
+ vec2 p;
+ glm_vec2_zero(p);
+
+ glm_vec2_muladds(line.norm, line.C, p);
+ double rec = glm_vec2_norm2(line.norm);
+ glm_vec2_divs(p, rec, p);
// Rotate the line to the new orientation
glm_vec2_rotate(line.norm, theta, line.norm);
// Transform the fixed point
affine_transform_vec2(transform, p, p);
- glm_vec2_negate(p);
// Calculate a C to follow the new point
+ glm_vec2_negate(p);
line.C = glm_vec2_dot(line.norm, p);
c->e->line = line;
diff --git a/src/svg.c b/src/svg.c
index 7480e4f..a59f57b 100644
--- a/src/svg.c
+++ b/src/svg.c
@@ -369,7 +369,7 @@ void begin_drawing(struct canvas *canvas) {
assert(canvas->f != NULL);
assert(canvas->state == CANVAS_INIT);
- fprintf(canvas->f, "<svg version=\"1.1\" viewBox=\"-50 -50 100 100\" width=\"1200\" height=\"1200\" xmlns=\"http://www.w3.org/2000/svg\">\n");
+ fprintf(canvas->f, "<svg version=\"1.1\" viewBox=\"-100 -100 200 200\" width=\"1200\" height=\"1200\" xmlns=\"http://www.w3.org/2000/svg\">\n");
fprintf(canvas->f, "<defs>\n");
fprintf(canvas->f, "\t<marker id=\"triangle\" viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerUnits=\"strokeWidth\" markerWidth=\"6\" markerHeight=\"6\" orient=\"auto-start-reverse\">\n");
fprintf(canvas->f, "\t\t<path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"blue\" opacity=\"0.3\" />\n");
diff --git a/test/solve.c b/test/solve.c
index e1729ff..65b51d6 100644
--- a/test/solve.c
+++ b/test/solve.c
@@ -1,5 +1,6 @@
#include "cad/solve.h"
#include <assert.h>
+#include <string.h>
int main(int argc, char *argv[]) {
struct subassembly assemblies[16] = {};
@@ -146,7 +147,7 @@ int main(int argc, char *argv[]) {
POINT_ON_LINE(&p5, &t2base),
// The edge they don't share is constrained
- LL_ANGLE(&t1base, &t2base, DEG(40)),
+ LL_ANGLE(&t1base, &t2base, DEG(70)),
CEND(),
});
@@ -159,17 +160,19 @@ int main(int argc, char *argv[]) {
for(size_t i = 0; i < constraints.length; i++) {
params[i] = constraints.elements[i].v;
}
-
place_points(&drawing, params);
+ free(params);
reconstruct_drawing(&constraints, assemblies, &assemblies_num);
- // @COMPL: We don't currently know how to derive an angle constraint
- // from the rigid triangle. We'd probably need to do some sort of
- // recursive solving, and even then you can't construct it without some
- // sort of math in the construction phase.
- // assert(!solved);
- // assert(solved);
+ assert(solved);
+
+ assert(glm_vec2_eqv_eps(p1.e->point.pos, (vec2){ 0.0 , 0.0 }));
+ assert(glm_vec2_eqv_eps(p2.e->point.pos, (vec2){30.0 , 0.0 }));
+ assert(glm_vec2_eqv_eps(p3.e->point.pos, (vec2){15.0 , 25.980762}));
+
+ assert(glm_vec2_eqv_eps(p4.e->point.pos, (vec2){34.283630, 2.999428}));
+ assert(glm_vec2_eqv_eps(p5.e->point.pos, (vec2){44.544235, 31.190207}));
free_drawing(&drawing);
free_constraints(&constraints);