// 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;
}
示例#2
0
// 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;
}