diff options
| author | Jesper Jensen <jesper@jnsn.dev> | 2026-07-24 20:19:48 +0200 |
|---|---|---|
| committer | Jesper Jensen <jesper@jnsn.dev> | 2026-07-24 20:19:48 +0200 |
| commit | 2667aa2806877d6fdd31b6ad34b0440197c14e1f (patch) | |
| tree | 2c7fc9ded8170e3794c505c3ff50f610dd538c3e /src/solve.c | |
| parent | 1af2dfbde432af9f13e8fba09b7ca29f5de71863 (diff) | |
Diffstat (limited to 'src/solve.c')
| -rw-r--r-- | src/solve.c | 141 |
1 files changed, 88 insertions, 53 deletions
diff --git a/src/solve.c b/src/solve.c index 0eab611..67a7bff 100644 --- a/src/solve.c +++ b/src/solve.c @@ -143,6 +143,7 @@ static bool fix_first(struct constraint *constraints, size_t constraints_num, si if(constraints[i].c1->ein != NULL) continue; if(constraints[i].c2->ein != NULL) continue; + fprintf(stderr, "Fix %ld\n", i); *c = i; return true; } @@ -553,7 +554,7 @@ static size_t build_triangles(struct constraints *constraints_in, struct compone if(possibly_angle_c == NULL) continue; - fprintf(stderr, "Assembly %p and %p, %d %d %s %s\n", ein_a, ein_b, f1_c, f2_c, constraint_type_name[not_angle_c->type], constraint_type_name[possibly_angle_c->type]); + fprintf(stderr, "%ld %ld Assembly %p and %p, %d %d %s %s\n", i, j, ein_a, ein_b, f1_c, f2_c, constraint_type_name[not_angle_c->type], constraint_type_name[possibly_angle_c->type]); // We've fixed the subcomponents, so we have to fix // the whole thing @@ -640,6 +641,49 @@ nomatch: return steps_i; } +static void point_from_line_and_distance(struct drawing *drawing, struct constraint *constraints, size_t c1, size_t c2, struct element *line, struct element *point, int root, struct element **result) { + assert(line->type == ETYPE_LINE); + assert(point->type == ETYPE_POINT); + + struct element *d1 = insert_cmd(drawing, (struct command){ + .op = CMD_VALUE_INPUT, + .index = c1, + .dir = constraints[c1].forward, + .result.type = ETYPE_VALUE, + }); + struct element *d2 = insert_cmd(drawing, (struct command){ + .op = CMD_VALUE_INPUT, + .index = c2, + .dir = constraints[c2].forward, + .result.type = ETYPE_VALUE, + }); + + struct element *l = insert_cmd(drawing, (struct command){ + .op = CMD_LINE_LINE_DISTANCE_PARALLEL, + .hidden = false, + .result.type = ETYPE_LINE, + .arg1 = line, + .arg2 = d1, + }); + + struct element *c = insert_cmd(drawing, (struct command){ + .op = CMD_CIRCLE_CENTER_RADIUS, + .hidden = false, + .result.type = ETYPE_CIRCLE, + .arg1 = point, + .arg2 = d2, + }); + + *result = insert_cmd(drawing, (struct command){ + .op = CMD_POINT_CIRCLE_LINE, + .hidden = false, + .root = root, + .result.type = ETYPE_POINT, + .arg1 = c, + .arg2 = l, + }); +} + static void draw_point_from_2_distance(struct drawing *drawing, struct constraint *constraints, size_t i, size_t j, struct component *local_i, struct component *local_j, struct element **e, bool shown) { struct element *d1 = insert_cmd(drawing, (struct command){ .op = CMD_VALUE_INPUT, @@ -722,10 +766,33 @@ static void draw_for_subassembly(struct constraint *constraints, size_t fix, str // @HACK Let's only solve for an explicit angle for now assert(constraints[step->j].type == CT_LINE_LINE_ANGLE); - // The point we share with the subassembly struct element *p = NULL; - draw_point_from_2_distance(drawing, constraints, step->i, step->k, local_i, local_k, &p, false); - assert(p != NULL); + if(constraints[step->i].type == CT_POINT_POINT_DISTANCE + && local_i->type == COM_POINT + && constraints[step->k].type == CT_POINT_POINT_DISTANCE + && local_k->type == COM_POINT) { + + draw_point_from_2_distance(drawing, constraints, step->i, step->k, local_i, local_k, &p, false); + assert(p != NULL); + } else if(constraints[step->i].type == CT_POINT_LINE_DISTANCE + && local_i->type == COM_LINE + && constraints[step->k].type == CT_POINT_POINT_DISTANCE + && local_k->type == COM_POINT) { + assert(oppo_i->type == COM_POINT); + + point_from_line_and_distance(drawing, constraints, step->i, step->k, local_i->e, local_k->e, constraints[step->k].c2 == local_k, &p); + } else if(constraints[step->i].type == CT_POINT_POINT_DISTANCE + && local_i->type == COM_POINT + && constraints[step->k].type == CT_POINT_LINE_DISTANCE + && local_k->type == COM_LINE) { + assert(oppo_i->type == COM_POINT); + + point_from_line_and_distance(drawing, constraints, step->k, step->i, local_k->e, local_i->e, constraints[step->i].c2 == local_i, &p); + } else { + abort(); + } + + // The point we share with the subassembly // The line that matches the angle struct element *theta = insert_cmd(drawing, (struct command){ @@ -755,49 +822,6 @@ static void draw_for_subassembly(struct constraint *constraints, size_t fix, str }); } -void point_from_line_and_distance(struct drawing *drawing, struct constraint *constraints, size_t c1, size_t c2, struct element *line, struct element *point, int root, struct element **result) { - assert(line->type == ETYPE_LINE); - assert(point->type == ETYPE_POINT); - - struct element *d1 = insert_cmd(drawing, (struct command){ - .op = CMD_VALUE_INPUT, - .index = c1, - .dir = constraints[c1].forward, - .result.type = ETYPE_VALUE, - }); - struct element *d2 = insert_cmd(drawing, (struct command){ - .op = CMD_VALUE_INPUT, - .index = c2, - .dir = constraints[c2].forward, - .result.type = ETYPE_VALUE, - }); - - struct element *l = insert_cmd(drawing, (struct command){ - .op = CMD_LINE_LINE_DISTANCE_PARALLEL, - .hidden = false, - .result.type = ETYPE_LINE, - .arg1 = line, - .arg2 = d1, - }); - - struct element *c = insert_cmd(drawing, (struct command){ - .op = CMD_CIRCLE_CENTER_RADIUS, - .hidden = false, - .result.type = ETYPE_CIRCLE, - .arg1 = point, - .arg2 = d2, - }); - - *result = insert_cmd(drawing, (struct command){ - .op = CMD_POINT_CIRCLE_LINE, - .hidden = false, - .root = root, - .result.type = ETYPE_POINT, - .arg1 = c, - .arg2 = l, - }); -} - #define expand_constraint(NAME, IDX) \ struct constraint *NAME = &constraints[IDX]; \ struct component *NAME##_local; \ @@ -853,7 +877,7 @@ static void draw_for_double_subassembly(struct constraint *constraints, size_t f // The basic idea here is to create some new points for ax_oppo and bx_oppo // which we can then use to place a circle or line struct element *ax_oppo_locally = {}; - point_from_line_and_distance(drawing, constraints, step->j, step->i, a2_local->e, a1_local->e, constraints[step->j].c2 == a2_local, &ax_oppo_locally); + point_from_line_and_distance(drawing, constraints, step->j, step->i, a2_local->e, a1_local->e, constraints[step->j].c2 != a2_local, &ax_oppo_locally); struct element *bx_oppo_locally = {}; build_angle_point_line2(drawing, constraints, step->x, step->k, b2_local->e, b1_local->e, true, &bx_oppo_locally); @@ -1175,7 +1199,7 @@ static void draw_solution(struct constraint *constraints, size_t fix, struct sol // @COPYPASTA: Taken from above but with params swapped assert(oppo_i->type == COM_POINT); - point_from_line_and_distance(drawing, constraints, step->j, step->i, local_j->e, local_i->e, constraints[step->j].c2 == local_i, &oppo_i->e); + point_from_line_and_distance(drawing, constraints, step->j, step->i, local_j->e, local_i->e, constraints[step->i].c2 == local_i, &oppo_i->e); } else { CRASH("Unknown constraint combination %s and %s\n", constraint_type_name[constraints[step->i].type], constraint_type_name[constraints[step->j].type]); } @@ -1185,13 +1209,20 @@ static void draw_solution(struct constraint *constraints, size_t fix, struct sol assembly->last_command = drawing->tail; } -int unt64_t_compar(const void *a, const void *b) { +int uint64_t_compar(const void *a, const void *b) { uint64_t x = *(const uint64_t*)a; uint64_t y = *(const uint64_t*)b; return (x > y) - (x < y); } +int id_ptr_compar(const void *a, const void *b) { + const struct component *x = *(const struct component**)a; + const struct component *y = *(const struct component**)b; + + return (x->id > y->id) - (x->id < y->id); +} + bool solve_constraints(struct constraints *constraints, struct drawing *drawing, struct subassembly *assemblies, size_t *assemblies_num) { *assemblies_num = 0; // Replace all the aliased points with the point they point to @@ -1210,11 +1241,13 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing, size_t component_num = 0; for(size_t i = 0; i < constraints->length; i++) { + constraints->elements[i].c1->id = constraints->elements[i].c1->id != 0 ? constraints->elements[i].c1->id : i+1; components[component_num++] = constraints->elements[i].c1; + constraints->elements[i].c2->id = constraints->elements[i].c2->id != 0 ? constraints->elements[i].c2->id : i+1; components[component_num++] = constraints->elements[i].c2; } - qsort(components, component_num, sizeof(struct component*), unt64_t_compar); + qsort(components, component_num, sizeof(struct component*), uint64_t_compar); size_t dest_num = 1; for(size_t i = 1; i < component_num; i++) { @@ -1222,6 +1255,8 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing, components[dest_num++] = components[i]; } + qsort(components, dest_num, sizeof(struct component*), id_ptr_compar); + // Pick some point point distance constraint as the base size_t fix; while(fix_first(constraints->elements, constraints->length, &fix)) { @@ -1232,12 +1267,12 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing, assemblies[*assemblies_num].steps_num = build_triangles(constraints, components, dest_num, fix, *assemblies_num+1, &assemblies[*assemblies_num]); assemblies[*assemblies_num].fix = fix; - // printf("Assembly %ld\n", *assemblies_num); + // printf("Assembly %ld %ld\n", *assemblies_num, fix); // for(size_t i = 0; i < assemblies[*assemblies_num].articulation_num; i++) { // printf(" Articulation %p\n", assemblies[*assemblies_num].articulation[i]); // } - // printf("Solved in %ld steps\n", steps_num); + // printf("Solved in %ld steps\n", assemblies[*assemblies_num].steps_num); draw_solution(constraints->elements, fix, assemblies[*assemblies_num].steps, assemblies[*assemblies_num].steps_num, drawing, &assemblies[*assemblies_num]); for(size_t i = 0; i < assemblies[*assemblies_num].articulation_num; i++) { |
