/* * La procedure "plane_norme" calcule le vecteur norme orthogonal au plan * defini par les 3 points. * Entree : * np Le vecteur norme orthogonal au plan. * ap, bp, cp Points formant un repere du plan. */ void plane_norme (Vector *np, Point3f *ap, Point3f *bp, Point3f *cp) { Vector u, v; DIF_COORD3(u,*bp,*ap); /* base orthonorme (ap, u, v) */ DIF_COORD3(v,*cp,*ap); norm_vector (&u); norm_vector (&v); CROSS_PRODUCT (*np,u,v); }
/* * La procedure "rotate_vector" transforme le vecteur * par la rotation de sens trigonometrique d'angle et d'axe donnes. * Entree : * vp Vecteur a transformer. * a Angle de rotation en degres. * axis Vecteur directeur de l'axe de rotation. */ void rotate_vector (Vector *vp, float a, Vector *axis) { Vector n, u, v, cross; float f; a *= (float)M_PI / (float)180.0; /* passage en radians */ n = *axis; /* norme le vecteur directeur */ norm_vector (&n); /* * Avant rotation, vp vaut : * u + v * Apres rotation, vp vaut : * u + cos(a) * v + sin(a) * (n^vp) * = u + cos(a) * v + sin(a) * (n^v) * avec u = (vp.n) * n, v = vp-u; * ou "u" est la projection de "vp" sur l'axe "axis", * et "v" est la composante de "vp" perpendiculaire a "axis". */ f = DOT_PRODUCT(*vp, n); u = n; MUL_COORD3(u,f,f,f); /* (vp.n) * n */ DIF_COORD3(v,*vp,u); /* calcule "v" */ f = (float) cos ((double) a); MUL_COORD3(v,f,f,f); /* v * cos(a) */ CROSS_PRODUCT(cross,n,*vp); f = (float) sin ((double) a); MUL_COORD3(cross,f,f,f); /* (n^v) * sin(a) */ SET_COORD3(*vp, u.x + v.x + cross.x, u.y + v.y + cross.y, u.z + v.z + cross.z); }
/* * La procedure "Rotaxis_to_Matrix" initialise la matrice par la rotation * d'angle et d'axe donnes. * Si M est la matrice, O l'angle et N le vecteur directeur de l'axe : * * M = cos(O) Id3 + (1 - cosO) Nt N + sinO N~ * * | NxNxverO+ cosO NxNyverO+NzsinO NxNzverO-NxsinO 0 | * M = | NxNyverO-NzsinO NyNyverO+ cosO NyNzverO+NxsinO 0 | * | NxNzverO+NysinO NyNzverO-NxsinO NzNzverO+ cosO 0 | * | 0 0 0 1 | * * O angle de rotation. * N Vecteur directeur norme de l'axe de rotation. * Nt Vecteur transpose. * N~ | 0 Nz -Ny| * |-Nz 0 Nx| * | Ny -Nx 0 | * Entree : * a Angle de rotation en degres. * axis Vecteur directeur de l'axe de la rotation. * m Matrice a initialiser. */ void Rotaxis_to_Matrix (float a, Vector *axis, Matrix m) { float cosa; float sina; float vera; /* 1 - cosa */ Vector n; /* vecteur norme*/ Vector conv; /* verO n */ Vector tilde; /* sinO n */ a *= (float)M_PI / (float)180.0; /* passage en radians */ cosa = (float) cos ((double) a); sina = (float) sin ((double) a); vera = (float)1.0 - cosa; n = *axis; /* norme le vecteur directeur */ norm_vector (&n); tilde = conv = n; MUL_COORD3(conv,vera,vera,vera); MUL_COORD3(tilde,sina,sina,sina); m[0][0] = conv.x * n.x + cosa; m[0][1] = conv.x * n.y + tilde.z; m[0][2] = conv.x * n.z - tilde.y; m[1][0] = conv.y * n.x - tilde.z; m[1][1] = conv.y * n.y + cosa; m[1][2] = conv.y * n.z + tilde.x; m[2][0] = conv.z * n.x + tilde.y; m[2][1] = conv.z * n.y - tilde.x; m[2][2] = conv.z * n.z + cosa; m[0][3] = m[2][3] = m[1][3] = 0.0; m[3][0] = m[3][1] = m[3][2] = 0.0; m[3][3] = 1.0; }
/* 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); } }