int main() { point p, q; assert(line_intersection(-1, 1, 0, 1, 1, -3, &p) == 0); assert(EQP(p, point(1.5, 1.5))); assert(line_intersection(point(0, 0), point(1, 1), point(0, 4), point(4, 0), &p) == 0); assert(EQP(p, point(2, 2))); { #define test(a, b, c, d, e, f, g, h) seg_intersection( \ point(a, b), point(c, d), point(e, f), point(g, h), &p, &q) // Intersection is a point. assert(0 == test(-4, 0, 4, 0, 0, -4, 0, 4) && EQP(p, point(0, 0))); assert(0 == test(0, 0, 10, 10, 2, 2, 16, 4) && EQP(p, point(2, 2))); assert(0 == test(-2, 2, -2, -2, -2, 0, 0, 0) && EQP(p, point(-2, 0))); assert(0 == test(0, 4, 4, 4, 4, 0, 4, 8) && EQP(p, point(4, 4))); // Intersection is a segment. assert(1 == test(10, 10, 0, 0, 2, 2, 6, 6)); assert(EQP(p, point(2, 2)) && EQP(q, point(6, 6))); assert(1 == test(6, 8, 14, -2, 14, -2, 6, 8)); assert(EQP(p, point(6, 8)) && EQP(q, point(14, -2))); // No intersection. assert(-1 == test(6, 8, 8, 10, 12, 12, 4, 4)); assert(-1 == test(-4, 2, -8, 8, 0, 0, -4, 6)); assert(-1 == test(4, 4, 4, 6, 0, 2, 0, 0)); assert(-1 == test(4, 4, 6, 4, 0, 2, 0, 0)); assert(-1 == test(-2, -2, 4, 4, 10, 10, 6, 6)); assert(-1 == test(0, 0, 2, 2, 4, 0, 1, 4)); assert(-1 == test(2, 2, 2, 8, 4, 4, 6, 4)); assert(-1 == test(4, 2, 4, 4, 0, 8, 10, 0)); } assert(EQP(point(2.5, 2.5), closest_point(-1, -1, 5, point(0, 0)))); assert(EQP(point(3, 0), closest_point(1, 0, -3, point(0, 0)))); assert(EQP(point(0, 3), closest_point(0, 1, -3, point(0, 0)))); assert(EQP(point(3, 0), closest_point(point(3, 0), point(3, 3), point(0, 0)))); assert(EQP(point(2, -1), closest_point(point(2, -1), point(4, -1), point(0, 0)))); assert(EQP(point(4, -1), closest_point(point(2, -1), point(4, -1), point(5, 0)))); return 0; }
int do_fraction (struct Plex *plex, struct PlexEdge *plexedg, double *p1, double *p2, double *p3, double *p4) { int k; double fraction; struct PlexVertex *newvtx; struct PlexEdge *newedg; char message[MAXLINE]; if (plex -> n_vertex >= plex -> maxvertex) { set_error1 ("too many vertices"); return (0); } if (plex -> n_edge >= plex -> maxedge) { sprintf (message, "do_fraction: too many edges (%6ld)", plex -> maxedge); set_error1 (message); return (0); } fraction = line_intersection (p1, p2, p3, p4); /* new vertex */ newvtx = plex -> plexvertices + plex -> n_vertex; for (k = 0; k < 3; k++) newvtx -> center[k] = (1.0 - fraction) * *(p1 + k) + fraction * *(p2 + k); newvtx -> type = PolyVertex; plex -> n_vertex++; /* new edge */ newedg = plex -> plexedges + plex -> n_edge; newedg -> vns[0] = plex -> n_vertex; newedg -> vns[1] = plexedg -> vns[1]; plexedg -> vns[1] = plex -> n_vertex; plex -> n_edge++; plex -> n_cut++; return (1); }
bool ray_crosses_segment(segment *s, ray *r, point *intersect) { if(line_intersection(s->a.x, s->a.y, s->b.x, s->b.y, r->center.x, r->center.y, r->out.x, r->out.y, intersect)) { if(is_intersect_in_ray(r, intersect) && is_intersect_in_segment(s, intersect)) { return true; } } return false; }
point closest_point(double a, double b, double c, const point &p) { if (EQ(a, 0)) { return point(p.x, -c); // Horizontal line. } if (EQ(b, 0)) { return point(-c, p.y); // Vertical line. } point res; line_intersection(a, b, c, -b, a, b*p.x - a*p.y, &res); return res; }
bool aabr_smallest_subaabr_containing_line (aabr const& r, move2 const& line, aabr& res__aabr) { real2 p1,p2; real unused, thouShaltNotPass; if( line_intersection(r, line, p1, unused, p2, thouShaltNotPass) ) { real2 bottom_left( MIN(p1.x,p2.x), MIN(p1.y,p2.y)); real2 top_right( MAX(p1.x,p2.x), MAX(p1.y,p2.y)); res__aabr = aabr( bottom_left, top_right - bottom_left ); return true; } else return false; }
/* input line must be looped */ static void convolution_line(struct line_pnts *Points, double da, double db, double dalpha, int side, int round, int caps, double tol, struct line_pnts *nPoints) { int i, j, res, np; double *x, *y; double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry; double vx1, vy1, wx1, wy1; double a0, b0, c0, a1, b1, c1; double phi1, phi2, delta_phi; double nsegments, angular_tol, angular_step; double angle0, angle1; int inner_corner, turns360; G_debug(3, "convolution_line() side = %d", side); np = Points->n_points; x = Points->x; y = Points->y; if ((np == 0) || (np == 1)) return; if ((x[0] != x[np - 1]) || (y[0] != y[np - 1])) { G_fatal_error(_("Line is not looped")); return; } Vect_reset_line(nPoints); if ((da == 0) || (db == 0)) { Vect_copy_xyz_to_pnts(nPoints, x, y, NULL, np); return; } side = (side >= 0) ? (1) : (-1); /* normalize variable */ dalpha *= PI / 180; /* convert dalpha from degrees to radians */ angular_tol = angular_tolerance(tol, da, db); i = np - 2; norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty); elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy); angle1 = atan2(ty, tx); nx = x[i] + vx; ny = y[i] + vy; mx = x[i + 1] + vx; my = y[i + 1] + vy; if (!round) line_coefficients(nx, ny, mx, my, &a1, &b1, &c1); for (i = 0; i <= np - 2; i++) { G_debug(4, "point %d, segment %d-%d", i, i, i + 1); /* save the old values */ if (!round) { a0 = a1; b0 = b1; c0 = c1; } wx = vx; wy = vy; angle0 = angle1; norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty); if ((tx == 0) && (ty == 0)) continue; elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy); angle1 = atan2(ty, tx); nx = x[i] + vx; ny = y[i] + vy; mx = x[i + 1] + vx; my = y[i + 1] + vy; if (!round) line_coefficients(nx, ny, mx, my, &a1, &b1, &c1); delta_phi = angle1 - angle0; if (delta_phi > PI) delta_phi -= 2 * PI; else if (delta_phi <= -PI) delta_phi += 2 * PI; /* now delta_phi is in [-pi;pi] */ turns360 = (fabs(fabs(delta_phi) - PI) < 1e-15); inner_corner = (side * delta_phi <= 0) && (!turns360); /* if <line turns 360> and (<caps> and <not round>) */ if (turns360 && caps && (!round)) { norm_vector(0, 0, vx, vy, &tx, &ty); elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty); Vect_append_point(nPoints, x[i] + wx + tx, y[i] + wy + ty, 0); G_debug(4, " append point (c) x=%.16f y=%.16f", x[i] + wx + tx, y[i] + wy + ty); Vect_append_point(nPoints, nx + tx, ny + ty, 0); /* nx == x[i] + vx, ny == y[i] + vy */ G_debug(4, " append point (c) x=%.16f y=%.16f", nx + tx, ny + ty); } if ((!turns360) && (!round) && (!inner_corner)) { res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry); if (res == 1) { Vect_append_point(nPoints, rx, ry, 0); G_debug(4, " append point (o) x=%.16f y=%.16f", rx, ry); } else if (res == 2) { /* no need to append point in this case */ } else G_fatal_error ("unexpected result of line_intersection() res = %d", res); } if (round && (!inner_corner) && (!turns360 || caps)) { /* we should draw elliptical arc for outside corner */ /* inverse transforms */ elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1); elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1); phi1 = atan2(wy1, wx1); phi2 = atan2(vy1, vx1); delta_phi = side * (phi2 - phi1); /* make delta_phi in [0, 2pi] */ if (delta_phi < 0) delta_phi += 2 * PI; nsegments = (int)(delta_phi / angular_tol) + 1; angular_step = side * (delta_phi / nsegments); phi1 += angular_step; for (j = 1; j <= nsegments - 1; j++) { elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx, &ty); Vect_append_point(nPoints, x[i] + tx, y[i] + ty, 0); G_debug(4, " append point (r) x=%.16f y=%.16f", x[i] + tx, y[i] + ty); phi1 += angular_step; } } Vect_append_point(nPoints, nx, ny, 0); G_debug(4, " append point (s) x=%.16f y=%.16f", nx, ny); Vect_append_point(nPoints, mx, my, 0); G_debug(4, " append point (s) x=%.16f y=%.16f", mx, my); } /* close the output line */ Vect_append_point(nPoints, nPoints->x[0], nPoints->y[0], nPoints->z[0]); Vect_line_prune ( nPoints ); }
/* * This function generates parallel line (with loops, but not like the old ones). * It is not to be used directly for creating buffers. * + added elliptical buffers/par.lines support * * dalpha - direction of elliptical buffer major axis in degrees * da - distance along major axis * db: distance along minor (perp.) axis * side: side >= 0 - right side, side < 0 - left side * when (da == db) we have plain distances (old case) * round - 1 for round corners, 0 for sharp corners. (tol is used only if round == 1) */ static void parallel_line(struct line_pnts *Points, double da, double db, double dalpha, int side, int round, int caps, int looped, double tol, struct line_pnts *nPoints) { int i, j, res, np; double *x, *y; double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry; double vx1, vy1, wx1, wy1; double a0, b0, c0, a1, b1, c1; double phi1, phi2, delta_phi; double nsegments, angular_tol, angular_step; int inner_corner, turns360; G_debug(3, "parallel_line()"); if (looped && 0) { /* start point != end point */ return; } Vect_reset_line(nPoints); if (looped) { Vect_append_point(Points, Points->x[1], Points->y[1], Points->z[1]); } np = Points->n_points; x = Points->x; y = Points->y; if ((np == 0) || (np == 1)) return; if ((da == 0) || (db == 0)) { Vect_copy_xyz_to_pnts(nPoints, x, y, NULL, np); return; } side = (side >= 0) ? (1) : (-1); /* normalize variable */ dalpha *= PI / 180; /* convert dalpha from degrees to radians */ angular_tol = angular_tolerance(tol, da, db); for (i = 0; i < np - 1; i++) { /* save the old values */ a0 = a1; b0 = b1; c0 = c1; wx = vx; wy = vy; norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty); if ((tx == 0) && (ty == 0)) continue; elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy); nx = x[i] + vx; ny = y[i] + vy; mx = x[i + 1] + vx; my = y[i + 1] + vy; line_coefficients(nx, ny, mx, my, &a1, &b1, &c1); if (i == 0) { if (!looped) Vect_append_point(nPoints, nx, ny, 0); continue; } delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1], x[i] - x[i - 1]); if (delta_phi > PI) delta_phi -= 2 * PI; else if (delta_phi <= -PI) delta_phi += 2 * PI; /* now delta_phi is in [-pi;pi] */ turns360 = (fabs(fabs(delta_phi) - PI) < 1e-15); inner_corner = (side * delta_phi <= 0) && (!turns360); if ((turns360) && (!(caps && round))) { if (caps) { norm_vector(0, 0, vx, vy, &tx, &ty); elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty); } else { tx = 0; ty = 0; } Vect_append_point(nPoints, x[i] + wx + tx, y[i] + wy + ty, 0); Vect_append_point(nPoints, nx + tx, ny + ty, 0); /* nx == x[i] + vx, ny == y[i] + vy */ } else if ((!round) || inner_corner) { res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry); /* if (res == 0) { G_debug(4, "a0=%.18f, b0=%.18f, c0=%.18f, a1=%.18f, b1=%.18f, c1=%.18f", a0, b0, c0, a1, b1, c1); G_fatal_error("Two consequtive line segments are parallel, but not on one straight line! This should never happen."); return; } */ if (res == 1) { if (!round) Vect_append_point(nPoints, rx, ry, 0); else { /* d = dig_distance2_point_to_line(rx, ry, 0, x[i-1], y[i-1], 0, x[i], y[i], 0, 0, NULL, NULL, NULL, NULL, NULL); if ( */ Vect_append_point(nPoints, rx, ry, 0); } } } else { /* we should draw elliptical arc for outside corner */ /* inverse transforms */ elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1); elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1); phi1 = atan2(wy1, wx1); phi2 = atan2(vy1, vx1); delta_phi = side * (phi2 - phi1); /* make delta_phi in [0, 2pi] */ if (delta_phi < 0) delta_phi += 2 * PI; nsegments = (int)(delta_phi / angular_tol) + 1; angular_step = side * (delta_phi / nsegments); for (j = 0; j <= nsegments; j++) { elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx, &ty); Vect_append_point(nPoints, x[i] + tx, y[i] + ty, 0); phi1 += angular_step; } } if ((!looped) && (i == np - 2)) { Vect_append_point(nPoints, mx, my, 0); } } if (looped) { Vect_append_point(nPoints, nPoints->x[0], nPoints->y[0], nPoints->z[0]); } Vect_line_prune(nPoints); if (looped) { Vect_line_delete_point(Points, Points->n_points - 1); } }
// returns true if further calls could possibly result in a mesh void LightCaster::add_triangle(Mesh* result, const Vector_& light, Wall* last_closest, float beginAngle, float nextAngle) { // within our angle bounds? float da1 = signed_angular_distance(angle, beginAngle); if(da1 > halfwidth) return; // swath begins after our cutoff float da2 = signed_angular_distance(angle, nextAngle); if(da2 < -halfwidth) return; // swath ends before our cutoff // clamp the values we did get float ada1 = ABS(da1); if(ada1 > halfwidth) { float fixup = halfwidth - ada1; beginAngle += fixup * sign(da1); } float ada2 = ABS(da2); if(ada2 > halfwidth) { float fixup = halfwidth - ada2; nextAngle += fixup * sign(da2); } int steps = ceilf(signed_angular_distance(beginAngle, nextAngle) / max_angle_step); float oldBegin = beginAngle; float oldNext = nextAngle; for(int ii = 0; ii < steps; ++ii) { beginAngle = oldBegin + ii * max_angle_step; float delta = signed_angular_distance(beginAngle, oldNext); nextAngle = beginAngle + MIN(delta, max_angle_step); // interset the discovered angle range with the previously // closest wall segment Vector_ a1; a1.x = light.x + cosf(beginAngle); a1.y = light.y + sinf(beginAngle); Vector_ a2; a2.x = light.x + cosf(nextAngle); a2.y = light.y + sinf(nextAngle); Vector_ i1, i2; line_intersection(&i1, &last_closest->start, &last_closest->end, &light, &a1); line_intersection(&i2, &last_closest->start, &last_closest->end, &light, &a2); Color c1, c2; float d1 = vector_dist(&i1, &light); float d2 = vector_dist(&i2, &light); color_lerp(&c1, &min_color, &max_color, MIN(1.0f, d1 / max_range)); color_lerp(&c2, &min_color, &max_color, MIN(1.0f, d2 / max_range)); if(d1 > max_range) { vector_direction_scaled(&i1, &i1, &light, max_range); vector_add(&i1, &i1, &light); } if(d2 > max_range) { vector_direction_scaled(&i2, &i2, &light, max_range); vector_add(&i2, &i2, &light); } // add a triangle to the mesh result->add_point(light, min_color); result->add_point(i1, c1); result->add_point(i2, c2); } }