// Detect if lines l1 and l2 will intersect between now and the next time step. inline IntersectionType intersect(Line *l1, Line *l2, double time) { assert(compareLines(l1, l2) < 0); if (!rectanglesOverlap(l1, l2)) { return NO_INTERSECTION; } Vec p1 = {.x = l2->p3.x - l1->delta.x, .y = l2->p3.y - l1->delta.y}; Vec p2 = {.x = l2->p4.x - l1->delta.x, .y = l2->p4.y - l1->delta.y}; if (intersectLines(l1->p1, l1->p2, l2->p1, l2->p2)) { return ALREADY_INTERSECTED; } int num_line_intersections = 0; bool top_intersected = false; bool bot_intersected = false; if (intersectLines(l1->p1, l1->p2, p1, p2)) { num_line_intersections++; } if (intersectLines(l1->p1, l1->p2, p1, l2->p1)) { num_line_intersections++; top_intersected = true; } if (intersectLines(l1->p1, l1->p2, p2, l2->p2)) { num_line_intersections++; bot_intersected = true; } if (num_line_intersections == 2) { return L2_WITH_L1; } if (pointInParallelogram(l1->p1, l2->p1, l2->p2, p1, p2) && pointInParallelogram(l1->p2, l2->p1, l2->p2, p1, p2)) { return L1_WITH_L2; } if (num_line_intersections == 0) { return NO_INTERSECTION; } Vec v1 = Vec_makeFromLine(*l1); Vec v2 = Vec_makeFromLine(*l2); double angle = Vec_angle(v1, v2); if ((top_intersected && angle < 0) || (bot_intersected && angle > 0)) { return L2_WITH_L1; } return L1_WITH_L2; } // Check if a point is in the parallelogram. inline bool pointInParallelogram(Vec point, Vec p1, Vec p2, Vec p3, Vec p4) { double d1 = direction(p1, p2, point); double d2 = direction(p3, p4, point); double d3 = direction(p1, p3, point); double d4 = direction(p2, p4, point); return d1 * d2 < 0 && d3 * d4 < 0; } // Check if two lines intersect. inline bool intersectLines(Vec p1, Vec p2, Vec p3, Vec p4) { return side(p1, p2, p3) != side(p1, p2, p4) && side(p3, p4, p1) != side(p3, p4, p2); } // Obtain the intersection point for two intersecting line segments. inline Vec getIntersectionPoint(Vec p1, Vec p2, Vec p3, Vec p4) { double u; u = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)) / ((p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y)); Vec p; p.x = p1.x + (p2.x - p1.x) * u; p.y = p1.y + (p2.y - p1.y) * u; return p; }
// Read in lines from line.in and add them into collision world for simulation. void LineDemo_createLines(LineDemo* lineDemo) { unsigned int lineId = 0; unsigned int numOfLines; window_dimension px1; window_dimension py1; window_dimension px2; window_dimension py2; window_dimension vx; window_dimension vy; int isGray; FILE *fin; fin = fopen(LineDemo_input_file_path, "r"); assert(fin != NULL); fscanf(fin, "%d\n", &numOfLines); lineDemo->collisionWorld = CollisionWorld_new(numOfLines); while (EOF != fscanf(fin, "(%lf, %lf), (%lf, %lf), %lf, %lf, %d\n", &px1, &py1, &px2, &py2, &vx, &vy, &isGray)) { Line *line = malloc(sizeof(Line)); // convert window coordinates to box coordinates windowToBox(&line->p1.x, &line->p1.y, px1, py1); windowToBox(&line->p2.x, &line->p2.y, px2, py2); // convert window velocity to box velocity velocityWindowToBox(&line->velocity.x, &line->velocity.y, vx, vy); // store color line->color = (Color) isGray; // store line ID line->id = lineId; lineId++; // precompute some information about the line line->relative_vector = Vec_makeFromLine(*line); line->top_left = (Vec) {.x = MIN(line->p1.x, line->p2.x), .y = MIN(line->p1.y, line->p2.y)}; line->bottom_right = (Vec) {.x = MAX(line->p1.x, line->p2.x), .y = MAX(line->p1.y, line->p2.y)}; // transfer ownership of line to collisionWorld CollisionWorld_addLine(lineDemo->collisionWorld, line); } fclose(fin); } void LineDemo_setNumFrames(LineDemo* lineDemo, const unsigned int numFrames) { lineDemo->numFrames = numFrames; } void LineDemo_initLine(LineDemo* lineDemo) { LineDemo_createLines(lineDemo); } Line* LineDemo_getLine(LineDemo* lineDemo, const unsigned int index) { return CollisionWorld_getLine(lineDemo->collisionWorld, index); } unsigned int LineDemo_getNumOfLines(LineDemo* lineDemo) { return CollisionWorld_getNumOfLines(lineDemo->collisionWorld); } unsigned int LineDemo_getNumLineWallCollisions(LineDemo* lineDemo) { return CollisionWorld_getNumLineWallCollisions(lineDemo->collisionWorld); } unsigned int LineDemo_getNumLineLineCollisions(LineDemo* lineDemo) { return CollisionWorld_getNumLineLineCollisions(lineDemo->collisionWorld); } // The main simulation loop bool LineDemo_update(LineDemo* lineDemo) { lineDemo->count++; CollisionWorld_updateLines(lineDemo->collisionWorld); if (lineDemo->count > lineDemo->numFrames) { return false; } return true; }