X-Git-Url: https://git.cworth.org/git?p=akamaru;a=blobdiff_plain;f=akamaru.c;h=fd3c468a82d34f5467f1cfbb17ff6b9ecbe57c38;hp=eee05e24a1d68f28bd4893c431e11235e5487664;hb=HEAD;hpb=1c5cfec7a396c39cfcdeadfcf48c2dd15ba21ea8 diff --git a/akamaru.c b/akamaru.c index eee05e2..fd3c468 100644 --- a/akamaru.c +++ b/akamaru.c @@ -1,4 +1,4 @@ -/* -*- mode: c; c-basic-offset: 2 -*- +/* -*- mode: c; c-basic-offset: 8 -*- * See: * * http://en.wikipedia.org/wiki/Verlet_integration @@ -21,200 +21,233 @@ #include "akamaru.h" const double elasticity = 0.7; -const double friction = 1; -const double gravity = 20; +const double friction = 8; +const double gravity = 50; void object_init (Object *object, double x, double y, double mass) { - object->position.x = x; - object->position.y = y; - object->previous_position.x = x; - object->previous_position.y = y; - object->mass = mass; + object->position.x = x; + object->position.y = y; + object->previous_position.x = x; + object->previous_position.y = y; + object->mass = mass; } void spring_init (Spring *spring, Object *a, Object *b, double length) { - spring->a = a; - spring->b = b; - spring->length = length; + spring->a = a; + spring->b = b; + spring->length = length; +} + +void +stick_init (Stick *stick, Object *a, Object *b, double length) +{ + stick->a = a; + stick->b = b; + stick->length = length; } void string_init (String *string, Object *a, Object *b, double length) { - string->a = a; - string->b = b; - string->length = length; + string->a = a; + string->b = b; + string->length = length; } void offset_spring_init (OffsetSpring *spring, Object *a, Object *b, double dx, double dy) { - spring->a = a; - spring->b = b; - spring->dx = dx; - spring->dy = dy; + spring->a = a; + spring->b = b; + spring->dx = dx; + spring->dy = dy; +} + +void +spacer_init (Spacer *spacer, Object *a, Object *b, double length) +{ + spacer->a = a; + spacer->b = b; + spacer->length = length; +} + +void +anchor_init (Anchor *anchor, Object *object, double x, double y) +{ + anchor->object = object; + anchor->x = x; + anchor->y = y; } void -polygon_init (Polygon *p, int num_points, ...) +polygon_init (Polygon *p, int enclosing, int num_points, ...) { - double dx, dy, length; - int i, j; - va_list ap; - - /* Polygons are defined counter-clock-wise in a coordinate system - * with the y-axis pointing down. */ - - va_start (ap, num_points); - p->num_points = num_points; - p->points = g_new (Point, num_points); - - for (i = 0; i < num_points; i++) { - p->points[i].x = va_arg (ap, double); - p->points[i].y = va_arg (ap, double); - } - va_end (ap); + double dx, dy, length; + int i, j; + va_list ap; + + /* Polygons are defined counter-clock-wise in a coordinate system + * with the y-axis pointing down. */ + + va_start (ap, num_points); + p->num_points = num_points; + p->points = g_new (Point, num_points); + p->enclosing = enclosing; + + for (i = 0; i < num_points; i++) { + p->points[i].x = va_arg (ap, double); + p->points[i].y = va_arg (ap, double); + } + va_end (ap); - p->normals = g_new (Vector, p->num_points); - /* Compute outward pointing normals. p->normals[i] is the normal - * for the edged between p->points[i] and p->points[i + 1]. */ - for (i = 0; i < p->num_points; i++) { - j = (i + 1) % p->num_points; - dx = p->points[j].x - p->points[i].x; - dy = p->points[j].y - p->points[i].y; - length = sqrt (dx * dx + dy * dy); - p->normals[i].x = -dy / length; - p->normals[i].y = dx / length; - } + p->normals = g_new (Vector, p->num_points); + /* Compute outward pointing normals. p->normals[i] is the normal + * for the edged between p->points[i] and p->points[i + 1]. */ + for (i = 0; i < p->num_points; i++) { + j = (i + 1) % p->num_points; + dx = p->points[j].x - p->points[i].x; + dy = p->points[j].y - p->points[i].y; + length = sqrt (dx * dx + dy * dy); + p->normals[i].x = -dy / length; + p->normals[i].y = dx / length; + } } void polygon_init_diamond (Polygon *polygon, double x, double y) { - return polygon_init (polygon, 5, - x, y, - x + 10, y + 40, - x + 90, y + 40, - x + 100, y, - x + 50, y - 20); + return polygon_init (polygon, FALSE, 5, + x, y, + x + 10, y + 40, + x + 90, y + 40, + x + 100, y, + x + 50, y - 20); } void polygon_init_rectangle (Polygon *polygon, double x0, double y0, double x1, double y1) { - return polygon_init (polygon, 4, x0, y0, x0, y1, x1, y1, x1, y0); + return polygon_init (polygon, FALSE, 4, x0, y0, x0, y1, x1, y1, x1, y0); +} + +void +polygon_init_enclosing_rectangle (Polygon *polygon, double x0, double y0, + double x1, double y1) +{ + return polygon_init (polygon, TRUE, 4, x0, y0, x0, y1, x1, y1, x1, y0); } void model_fini (Model *model) { - int i; - - g_free (model->objects); - g_free (model->sticks); - g_free (model->strings); - for (i = 0; i < model->num_offsets; i++) - g_free (model->offsets[i].objects); - g_free (model->springs); - g_free (model->offset_springs); - for (i = 0; i < model->num_polygons; i++) - g_free (model->polygons[i].points); - g_free (model->polygons); - - memset (model, 0, sizeof *model); + int i; + + g_free (model->objects); + g_free (model->sticks); + g_free (model->strings); + for (i = 0; i < model->num_offsets; i++) + g_free (model->offsets[i].objects); + g_free (model->springs); + g_free (model->offset_springs); + g_free (model->spacers); + for (i = 0; i < model->num_polygons; i++) + g_free (model->polygons[i].points); + g_free (model->polygons); + + memset (model, 0, sizeof *model); } static void model_accumulate_forces (Model *model) { - int i; - double x, y, dx, dy, distance, displacement; - Point middle; - Vector u, v; - - for (i = 0; i < model->num_objects; i++) { - /* Gravity */ - model->objects[i].force.x = 0; - model->objects[i].force.y = gravity * model->objects[i].mass; - - /* Friction */ - v.x = model->objects[i].position.x - model->objects[i].previous_position.x; - v.y = model->objects[i].position.y - model->objects[i].previous_position.y; - model->objects[i].force.x -= v.x * friction; - model->objects[i].force.y -= v.y * friction; - } - - for (i = 0; i < model->num_springs; i++) { - x = model->springs[i].a->position.x; - y = model->springs[i].a->position.y; - dx = model->springs[i].b->position.x - x; - dy = model->springs[i].b->position.y - y; - distance = sqrt (dx * dx + dy * dy); - u.x = dx / distance; - u.y = dy / distance; - displacement = distance - model->springs[i].length; - model->springs[i].a->force.x += u.x * model->k * displacement; - model->springs[i].a->force.y += u.y * model->k * displacement; - model->springs[i].b->force.x -= u.x * model->k * displacement; - model->springs[i].b->force.y -= u.y * model->k * displacement; - } - - for (i = 0; i < model->num_offset_springs; i++) { - middle.x = - (model->offset_springs[i].a->position.x + - model->offset_springs[i].b->position.x) / 2; - middle.y = - (model->offset_springs[i].a->position.y + - model->offset_springs[i].b->position.y) / 2; - - x = middle.x - model->offset_springs[i].dx / 2; - y = middle.y - model->offset_springs[i].dy / 2; - - dx = x - model->offset_springs[i].a->position.x; - dy = y - model->offset_springs[i].a->position.y; - - model->offset_springs[i].a->force.x += dx * model->k; - model->offset_springs[i].a->force.y += dy * model->k; - model->offset_springs[i].b->force.x -= dx * model->k; - model->offset_springs[i].b->force.y -= dy * model->k; - } - - for (i = 0; i < model->num_objects; i++) { - double f = - model->objects[i].force.x * model->objects[i].force.x + - model->objects[i].force.y * model->objects[i].force.y; - - if (f > 100000000) - abort(); - } + int i; + double x, y, dx, dy, distance, displacement; + Point middle; + Vector u, v; + + for (i = 0; i < model->num_objects; i++) { + /* Gravity */ + model->objects[i].force.x = 0; + model->objects[i].force.y = gravity * model->objects[i].mass; + + /* Friction */ + v.x = model->objects[i].position.x - model->objects[i].previous_position.x; + v.y = model->objects[i].position.y - model->objects[i].previous_position.y; + model->objects[i].force.x -= v.x * friction; + model->objects[i].force.y -= v.y * friction; + } + + for (i = 0; i < model->num_springs; i++) { + x = model->springs[i].a->position.x; + y = model->springs[i].a->position.y; + dx = model->springs[i].b->position.x - x; + dy = model->springs[i].b->position.y - y; + distance = sqrt (dx * dx + dy * dy); + u.x = dx / distance; + u.y = dy / distance; + displacement = distance - model->springs[i].length; + model->springs[i].a->force.x += u.x * model->k * displacement; + model->springs[i].a->force.y += u.y * model->k * displacement; + model->springs[i].b->force.x -= u.x * model->k * displacement; + model->springs[i].b->force.y -= u.y * model->k * displacement; + } + + for (i = 0; i < model->num_offset_springs; i++) { + middle.x = + (model->offset_springs[i].a->position.x + + model->offset_springs[i].b->position.x) / 2; + middle.y = + (model->offset_springs[i].a->position.y + + model->offset_springs[i].b->position.y) / 2; + + x = middle.x - model->offset_springs[i].dx / 2; + y = middle.y - model->offset_springs[i].dy / 2; + + dx = x - model->offset_springs[i].a->position.x; + dy = y - model->offset_springs[i].a->position.y; + + model->offset_springs[i].a->force.x += dx * model->k; + model->offset_springs[i].a->force.y += dy * model->k; + model->offset_springs[i].b->force.x -= dx * model->k; + model->offset_springs[i].b->force.y -= dy * model->k; + } + + for (i = 0; i < model->num_objects; i++) { + double f = + model->objects[i].force.x * model->objects[i].force.x + + model->objects[i].force.y * model->objects[i].force.y; + + if (f > 100000000) + abort(); + } } static void model_integrate (Model *model, double step) { - double x, y; - Object *o; - int i; - - for (i = 0; i < model->num_objects; i++) { - o = &model->objects[i]; - x = o->position.x; - y = o->position.y; + double x, y; + Object *o; + int i; + + for (i = 0; i < model->num_objects; i++) { + o = &model->objects[i]; + x = o->position.x; + y = o->position.y; - o->position.x = - x + (x - o->previous_position.x) + o->force.x * step * step; - o->position.y = - y + (y - o->previous_position.y) + o->force.y * step * step; - - o->previous_position.x = x; - o->previous_position.y = y; - } + o->position.x = + x + (x - o->previous_position.x) + o->force.x * step * step; + o->position.y = + y + (y - o->previous_position.y) + o->force.y * step * step; + + o->previous_position.x = x; + o->previous_position.y = y; + } } /* The square root in the distance computation for the string and @@ -234,184 +267,205 @@ static inline double estimate_distance (double dx, double dy, double r) { #ifdef APPROXIMATE_SQUARE_ROOTS - return (r + (dx * dx + dy * dy) / r) / 2; + return (r + (dx * dx + dy * dy) / r) / 2; #else - return sqrt (dx * dx + dy * dy); + return sqrt (dx * dx + dy * dy); #endif } static int polygon_contains_point (Polygon *polygon, Point *point) { - int i; - double dx, dy; + int i; + double dx, dy; - for (i = 0; i < polygon->num_points; i++) { - dx = point->x - polygon->points[i].x; - dy = point->y - polygon->points[i].y; + for (i = 0; i < polygon->num_points; i++) { + dx = point->x - polygon->points[i].x; + dy = point->y - polygon->points[i].y; - if (polygon->normals[i].x * dx + polygon->normals[i].y * dy >= 0) - return FALSE; - } + if (polygon->normals[i].x * dx + polygon->normals[i].y * dy >= 0) + return polygon->enclosing; + } - return TRUE; + return !polygon->enclosing; } static void polygon_reflect_object (Polygon *polygon, Object *object) { - int i, edge; - double d, distance; - Vector *n; - - distance = -1000; - for (i = 0; i < polygon->num_points; i++) { - d = polygon->normals[i].x * (object->position.x - polygon->points[i].x) + - polygon->normals[i].y * (object->position.y - polygon->points[i].y); - - if (d > distance) { - distance = d; - edge = i; - polygon->edge = i; - n = &polygon->normals[i]; - } - } - - object->position.x -= (1 + elasticity) * distance * n->x; - object->position.y -= (1 + elasticity) * distance * n->y; - - distance = - n->x * (object->previous_position.x - polygon->points[edge].x) + - n->y * (object->previous_position.y - polygon->points[edge].y); - - object->previous_position.x -= (1 + elasticity) * distance * n->x; - object->previous_position.y -= (1 + elasticity) * distance * n->y; + int i, edge; + double d, distance; + Vector *n; + + distance = -1000; + for (i = 0; i < polygon->num_points; i++) { + d = polygon->normals[i].x * (object->position.x - polygon->points[i].x) + + polygon->normals[i].y * (object->position.y - polygon->points[i].y); + + if (d > distance) { + distance = d; + edge = i; + n = &polygon->normals[i]; + } + } + + object->position.x -= (1 + elasticity) * distance * n->x; + object->position.y -= (1 + elasticity) * distance * n->y; + + distance = + n->x * (object->previous_position.x - polygon->points[edge].x) + + n->y * (object->previous_position.y - polygon->points[edge].y); + + object->previous_position.x -= (1 + elasticity) * distance * n->x; + object->previous_position.y -= (1 + elasticity) * distance * n->y; } static void model_constrain_polygon (Model *model, Polygon *polygon) { - int i; + int i; + + for (i = 0; i < model->num_objects; i++) { + if (polygon_contains_point (polygon, &model->objects[i].position)) + polygon_reflect_object (polygon, &model->objects[i]); + } +} - for (i = 0; i < model->num_objects; i++) { - if (polygon_contains_point (polygon, &model->objects[i].position)) - polygon_reflect_object (polygon, &model->objects[i]); - } +static void +model_constrain_anchor (Model *model, Anchor *anchor) +{ + anchor->object->position.x = anchor->x; + anchor->object->position.y = anchor->y; + anchor->object->previous_position.x = anchor->x; + anchor->object->previous_position.y = anchor->y; } static void model_constrain_offset (Model *model, Offset *offset) { - double x, y; - int i; - - x = 0; - y = 0; - for (i = 0; i < offset->num_objects; i++) { - x += offset->objects[i]->position.x; - y += offset->objects[i]->position.y; - } - - x = x / offset->num_objects - offset->dx * (offset->num_objects - 1) / 2; - y = y / offset->num_objects - offset->dy * (offset->num_objects - 1) / 2; + double x, y; + int i; + + x = 0; + y = 0; + for (i = 0; i < offset->num_objects; i++) { + x += offset->objects[i]->position.x; + y += offset->objects[i]->position.y; + } + + x = x / offset->num_objects - offset->dx * (offset->num_objects - 1) / 2; + y = y / offset->num_objects - offset->dy * (offset->num_objects - 1) / 2; - for (i = 0; i < offset->num_objects; i++) { - offset->objects[i]->position.x = x + offset->dx * i; - offset->objects[i]->position.y = y + offset->dy * i; - } + for (i = 0; i < offset->num_objects; i++) { + offset->objects[i]->position.x = x + offset->dx * i; + offset->objects[i]->position.y = y + offset->dy * i; + } } static void model_constrain (Model *model) { - double dx, dy, x, y, distance, fraction; - int i; - - /* Anchor object constraint. */ - if (model->anchor_object != NULL) { - model->anchor_object->position.x = model->anchor_position.x; - model->anchor_object->position.y = model->anchor_position.y; - model->anchor_object->previous_position.x = model->anchor_position.x; - model->anchor_object->previous_position.y = model->anchor_position.y; - } - - /* String constraints. */ - for (i = 0; i < model->num_strings; i++) { - x = model->strings[i].a->position.x; - y = model->strings[i].a->position.y; - dx = model->strings[i].b->position.x - x; - dy = model->strings[i].b->position.y - y; - distance = estimate_distance (dx, dy, model->strings[i].length); - if (distance < model->strings[i].length) - continue; - fraction = (distance - model->strings[i].length) / distance / 2; - model->strings[i].a->position.x = x + dx * fraction; - model->strings[i].a->position.y = y + dy * fraction; - model->strings[i].b->position.x = x + dx * (1 - fraction); - model->strings[i].b->position.y = y + dy * (1 - fraction); - } - - /* Stick constraints. */ - for (i = 0; i < model->num_sticks; i++) { - x = model->sticks[i].a->position.x; - y = model->sticks[i].a->position.y; - dx = model->sticks[i].b->position.x - x; - dy = model->sticks[i].b->position.y - y; - distance = estimate_distance (dx, dy, model->sticks[i].length); - fraction = (distance - model->sticks[i].length) / distance / 2; - model->sticks[i].a->position.x = x + dx * fraction; - model->sticks[i].a->position.y = y + dy * fraction; - model->sticks[i].b->position.x = x + dx * (1 - fraction); - model->sticks[i].b->position.y = y + dy * (1 - fraction); - } - - /* Offset constraints. */ - for (i = 0; i < model->num_offsets; i++) - model_constrain_offset (model, &model->offsets[i]); - - /* Polygon constraints. */ - for (i = 0; i < model->num_polygons; i++) - model_constrain_polygon (model, &model->polygons[i]); + double dx, dy, x, y, distance, fraction; + int i; + + if (model->mouse_anchor.object != NULL) + model_constrain_anchor (model, &model->mouse_anchor); + for (i = 0; i < model->num_anchors; i++) + model_constrain_anchor (model, &model->anchors[i]); + + /* String constraints. */ + for (i = 0; i < model->num_strings; i++) { + x = model->strings[i].a->position.x; + y = model->strings[i].a->position.y; + dx = model->strings[i].b->position.x - x; + dy = model->strings[i].b->position.y - y; + distance = estimate_distance (dx, dy, model->strings[i].length); + if (distance < model->strings[i].length) + continue; + fraction = (distance - model->strings[i].length) / distance / 2; + model->strings[i].a->position.x = x + dx * fraction; + model->strings[i].a->position.y = y + dy * fraction; + model->strings[i].b->position.x = x + dx * (1 - fraction); + model->strings[i].b->position.y = y + dy * (1 - fraction); + } + + /* Spacer constraints. */ + for (i = 0; i < model->num_spacers; i++) { + x = model->spacers[i].a->position.x; + y = model->spacers[i].a->position.y; + dx = model->spacers[i].b->position.x - x; + dy = model->spacers[i].b->position.y - y; + distance = estimate_distance (dx, dy, model->spacers[i].length); + if (distance > model->spacers[i].length) + continue; + fraction = (distance - model->spacers[i].length) / distance / 2; + model->spacers[i].a->position.x = x + dx * fraction; + model->spacers[i].a->position.y = y + dy * fraction; + model->spacers[i].b->position.x = x + dx * (1 - fraction); + model->spacers[i].b->position.y = y + dy * (1 - fraction); + } + + /* Stick constraints. */ + for (i = 0; i < model->num_sticks; i++) { + x = model->sticks[i].a->position.x; + y = model->sticks[i].a->position.y; + dx = model->sticks[i].b->position.x - x; + dy = model->sticks[i].b->position.y - y; + distance = estimate_distance (dx, dy, model->sticks[i].length); + fraction = (distance - model->sticks[i].length) / distance / 2; + model->sticks[i].a->position.x = x + dx * fraction; + model->sticks[i].a->position.y = y + dy * fraction; + model->sticks[i].b->position.x = x + dx * (1 - fraction); + model->sticks[i].b->position.y = y + dy * (1 - fraction); + } + + /* Offset constraints. */ + for (i = 0; i < model->num_offsets; i++) + model_constrain_offset (model, &model->offsets[i]); + + /* Polygon constraints. */ + for (i = 0; i < model->num_polygons; i++) + model_constrain_polygon (model, &model->polygons[i]); } void model_step (Model *model, double delta_t) { - int i; + int i; - model_accumulate_forces (model); - model_integrate (model, delta_t); - for (i = 0; i < 50; i++) - model_constrain (model); + model_accumulate_forces (model); + model_integrate (model, delta_t); + for (i = 0; i < 20; i++) + model_constrain (model); - model->theta += delta_t; + model->theta += delta_t; } static double object_distance (Object *object, double x, double y) { - double dx, dy; + double dx, dy; - dx = object->position.x - x; - dy = object->position.y - y; + dx = object->position.x - x; + dy = object->position.y - y; - return sqrt (dx*dx + dy*dy); + return sqrt (dx*dx + dy*dy); } Object * model_find_nearest (Model *model, double x, double y) { - Object *object; - double distance, min_distance; - int i; - - for (i = 0; i < model->num_objects; i++) { - distance = object_distance (&model->objects[i], x, y); - if (i == 0 || distance < min_distance) { - min_distance = distance; - object = &model->objects[i]; - } - } - - return object; + Object *object; + double distance, min_distance; + int i; + + for (i = 0; i < model->num_objects; i++) { + distance = object_distance (&model->objects[i], x, y); + if (i == 0 || distance < min_distance) { + min_distance = distance; + object = &model->objects[i]; + } + } + + return object; }