summaryrefslogtreecommitdiff
path: root/src/solve.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/solve.c')
-rw-r--r--src/solve.c141
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++) {