diff options
| author | Jesper Jensen <jesper@jnsn.dev> | 2026-03-28 09:47:34 +0100 |
|---|---|---|
| committer | Jesper Jensen <jesper@jnsn.dev> | 2026-03-28 09:47:34 +0100 |
| commit | ebb61f7bec9a6affa2be7b0eeb94bb737b9edcb2 (patch) | |
| tree | 570251bc426ccb4ee6cc88b06754ef14c7c834fb /src/solve.c | |
| parent | d8a6d8a8b046dcb73f1c1daf0e013a703517da68 (diff) | |
Add support for post solve assembling
Diffstat (limited to 'src/solve.c')
| -rw-r--r-- | src/solve.c | 162 |
1 files changed, 108 insertions, 54 deletions
diff --git a/src/solve.c b/src/solve.c index 789b977..1401f44 100644 --- a/src/solve.c +++ b/src/solve.c @@ -220,17 +220,6 @@ static bool fix_first(struct constraint *constraints, size_t constraints_num, si return false; } -struct subassembly { - struct solve_step *steps; - size_t steps_num; - - struct component **articulation; - struct element *articulation_position; - size_t articulation_num; - - bool fixed; -}; - static size_t build_triangles(struct constraint *constraints, size_t constraints_num, size_t origin, uint8_t useid, struct subassembly *assembly) { struct solve_step *steps = assembly->steps; struct frontier frontier = {}; @@ -691,7 +680,8 @@ static void draw_solution(struct constraint *constraints, size_t fix, struct sol } } -bool solve_constraints(struct constraints *constraints, struct drawing *drawing) { +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 for(size_t i = 0; i < constraints->aliases_num; i++) { struct alias *alias = &constraints->aliases[i]; @@ -706,52 +696,81 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing) // Pick some point point distance constraint as the base size_t fix; - struct subassembly assemblies[16] = {0}; - size_t assemblies_num = 0; while(fix_first(constraints->elements, constraints->length, &fix)) { // Build triangles on that root - assemblies[assemblies_num].steps = malloc(sizeof(struct solve_step) * constraints->length); - assemblies[assemblies_num].articulation = malloc(sizeof(struct component*) * constraints->length); - assemblies[assemblies_num].articulation_position = malloc(sizeof(struct element) * constraints->length); - assemblies[assemblies_num].steps_num = build_triangles(constraints->elements, constraints->length, fix, assemblies_num+1, &assemblies[assemblies_num]); - - printf("Assembly %ld\n", assemblies_num); - for(size_t i = 0; i < assemblies[assemblies_num].articulation_num; i++) { - printf(" Articulation %p\n", assemblies[assemblies_num].articulation[i]); - } + assemblies[*assemblies_num].steps = malloc(sizeof(struct solve_step) * constraints->length); + assemblies[*assemblies_num].articulation = malloc(sizeof(struct component*) * constraints->length); + assemblies[*assemblies_num].articulation_position = malloc(sizeof(struct element*) * constraints->length); + assemblies[*assemblies_num].steps_num = build_triangles(constraints->elements, constraints->length, fix, *assemblies_num+1, &assemblies[*assemblies_num]); + assemblies[*assemblies_num].fix = fix; + + // printf("Assembly %ld\n", *assemblies_num); + // 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); - draw_solution(constraints->elements, fix, assemblies[assemblies_num].steps, assemblies[assemblies_num].steps_num, drawing); - for(size_t i = 0; i < assemblies[assemblies_num].articulation_num; i++) { - memcpy(&assemblies[assemblies_num].articulation_position[i], assemblies[assemblies_num].articulation[i]->e, sizeof(struct component)); + draw_solution(constraints->elements, fix, assemblies[*assemblies_num].steps, assemblies[*assemblies_num].steps_num, drawing); + for(size_t i = 0; i < assemblies[*assemblies_num].articulation_num; i++) { + assemblies[*assemblies_num].articulation_position[i] = assemblies[*assemblies_num].articulation[i]->e; } - assemblies_num++; - assert(assemblies_num <= 16); + (*assemblies_num)++; + assert(*assemblies_num <= 16); } + // Fill out the aliased points out with the values from their targets + for(size_t i = 0; i < constraints->aliases_num; i++) { + struct alias *alias = &constraints->aliases[i]; + + memcpy(alias->alias, alias->target, sizeof(struct component)); + } + + // Check for unsolved constraints + bool complete = true; + // for(size_t i = 0; i < constraints->length; i++) { + // if(!constraints->elements[i].used) { + // complete = false; + // } + // } + + return complete; +} + +static void affine_transform_vec2(mat3 m, vec2 in, vec2 out) { + vec3 h = {in[0], in[1], 1.0f}; + vec3 result; + glm_mat3_mulv(m, h, result); + out[0] = result[0]; + out[1] = result[1]; +} + +void reconstruct_drawing(struct constraints *constraints, struct subassembly *assemblies, size_t *assemblies_num) { // We build everything from the first assembly assemblies[0].fixed = true; while(true) { // Look for unfixed assembly we can connect to something that is fixed - for(size_t i = 0; i < assemblies_num; i++) { + for(size_t i = 0; i < *assemblies_num; i++) { if(assemblies[i].fixed) continue; // Find a fixed asssembly it connects to - for(size_t j = 0; j < assemblies_num; j++) { + for(size_t j = 0; j < *assemblies_num; j++) { if(!assemblies[j].fixed) continue; - struct component *articulation1 = NULL; + size_t articulation_i; + size_t articulation_j; // Find a shared articulation - for(size_t articuation_i = 0; articuation_i < assemblies[i].articulation_num; articuation_i++) { - for(size_t articuation_j = 0; articuation_j < assemblies[j].articulation_num; articuation_j++) { - if(assemblies[i].articulation[articuation_i] == assemblies[j].articulation[articuation_j]) { - articulation1 = assemblies[i].articulation[articuation_i]; - break; + for(articulation_i = 0; articulation_i < assemblies[i].articulation_num; articulation_i++) { + for(articulation_j = 0; articulation_j < assemblies[j].articulation_num; articulation_j++) { + if(assemblies[i].articulation[articulation_i] == assemblies[j].articulation[articulation_j]) { + goto articulation_found; } } } + continue; +articulation_found: + ; struct constraint *constraint = NULL; bool forward; @@ -794,26 +813,61 @@ constraint_matches_j: // share a constraint. We can hopefully place the rest of the // assembly from that information - printf("We found a match %p, %p\n", articulation1, constraint); - } - } - break; - } + 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; - // Fill out the aliased points out with the values from their targets - for(size_t i = 0; i < constraints->aliases_num; i++) { - struct alias *alias = &constraints->aliases[i]; + constraint->used = true; + theta += constraint->forward ? constraint->v : -constraint->v; - memcpy(alias->alias, alias->target, sizeof(struct component)); - } + assert(assemblies[i].articulation_position[articulation_i]->type == ETYPE_POINT); + assert(assemblies[j].articulation_position[articulation_j]->type == ETYPE_POINT); - // Check for unsolved constraints - bool complete = true; - // for(size_t i = 0; i < constraints->length; i++) { - // if(!constraints->elements[i].used) { - // complete = false; - // } - // } + mat3 transform; + glm_mat3_identity(transform); - return complete; + glm_translate2d(transform, assemblies[i].articulation_position[articulation_i]->point.pos); + + glm_rotate2d(transform, theta); + + { + vec2 negative_translate; + glm_vec2_negate_to(assemblies[j].articulation_position[articulation_j]->point.pos, negative_translate); + glm_translate2d(transform, negative_translate); + } + + // Transform the baseline points + { + struct component *c = constraints->elements[assemblies[i].fix].c1; + assert(c->type == COM_POINT); + + affine_transform_vec2(transform, c->e->point.pos, c->e->point.pos); + } + { + struct component *c = constraints->elements[assemblies[i].fix].c2; + assert(c->type == COM_POINT); + + affine_transform_vec2(transform, c->e->point.pos, c->e->point.pos); + } + + // Transform all other points in the body by iterating the + // steps. Each step places a single component. + for(size_t k = 0; k < assemblies[i].steps_num; k++) { + struct solve_step *step = &assemblies[i].steps[k]; + + struct component *c = step->i_forward ? + constraints->elements[step->i].c2 : + constraints->elements[step->i].c1; + + if(c->type == COM_POINT) { + affine_transform_vec2(transform, c->e->point.pos, c->e->point.pos); + } + // @HACK We're not transforming lines, this relies on the + // user not requiring/caring about the lines AFTER solving. + // This is wrong, but useful enough for getting something + // on screen. + } + } + } + break; + } } |
