static spiro_seg * setup_path(const spiro_cp *src, int n) { int n_seg = src[0].ty == '{' ? n - 1 : n; spiro_seg *r = (spiro_seg *)malloc((n_seg + 1) * sizeof(spiro_seg)); int i; int ilast; for (i = 0; i < n_seg; i++) { r[i].x = src[i].x; r[i].y = src[i].y; r[i].ty = src[i].ty; r[i].ks[0] = 0.; r[i].ks[1] = 0.; r[i].ks[2] = 0.; r[i].ks[3] = 0.; } r[n_seg].x = src[n_seg % n].x; r[n_seg].y = src[n_seg % n].y; r[n_seg].ty = src[n_seg % n].ty; for (i = 0; i < n_seg; i++) { double dx = r[i + 1].x - r[i].x; double dy = r[i + 1].y - r[i].y; r[i].seg_ch = hypot(dx, dy); r[i].seg_th = atan2(dy, dx); } ilast = n_seg - 1; for (i = 0; i < n_seg; i++) { if (r[i].ty == '{' || r[i].ty == '}' || r[i].ty == 'v') r[i].bend_th = 0.; else r[i].bend_th = mod_2pi(r[i].seg_th - r[ilast].seg_th); ilast = i; } return r; }
static double spiro_iter(spiro_seg *s, bandmat *m, int *perm, double *v, int n, int nmat) { int cyclic, i, j, jthl, jthr, jk0l, jk0r, jk1l, jk1r, jk2l, jk2r, jinc, jj, k, n_invert; char ty0, ty1; double dk, norm, th; double ends[2][4]; double derivs[4][2][4]; cyclic = s[0].ty != '{' && s[0].ty != 'v'; for (i = 0; i < nmat; i++) { v[i] = 0.; for (j = 0; j < 11; j++) m[i].a[j] = 0.; for (j = 0; j < 5; j++) m[i].al[j] = 0.; } j = 0; if (s[0].ty == 'o') jj = nmat - 2; else if (s[0].ty == 'c') jj = nmat - 1; else jj = 0; for (i = 0; i < n; i++) { ty0 = s[i].ty; ty1 = s[i + 1].ty; jinc = compute_jinc(ty0, ty1); th = s[i].bend_th; jthl = jk0l = jk1l = jk2l = -1; jthr = jk0r = jk1r = jk2r = -1; compute_pderivs(&s[i], ends, derivs, jinc); /* constraints crossing left */ if (ty0 == 'o' || ty0 == 'c' || ty0 == '[' || ty0 == ']' || \ ty0 == 'a' || ty0 == 'h') { jthl = jj++; jj %= nmat; jk0l = jj++; if (ty0 == 'o') { jj %= nmat; jk1l = jj++; jk2l = jj++; } } /* constraints on left */ if ((ty0 == '[' || ty0 == 'v' || ty0 == '{' || ty0 == 'c' || \ ty0 == 'a') && jinc == 4) { if (ty0 != 'c') jk1l = jj++; jk2l = jj++; } /* constraints on right */ if ((ty1 == ']' || ty1 == 'v' || ty1 == '}' || ty1 == 'c' || \ ty1 == 'h') && jinc == 4) { if (ty1 != 'c') jk1r = jj++; jk2r = jj++; } /* constraints crossing right */ if (ty1 == 'o' || ty1 == 'c' || ty1 == '[' || ty1 == ']' || \ ty1 == 'a' || ty1 == 'h') { jthr = jj; jk0r = (jj + 1) % nmat; if (ty1 == 'o') { jk1r = (jj + 2) % nmat; jk2r = (jj + 3) % nmat; } } add_mat_line(m, v, derivs[0][0], th - ends[0][0], 1, j, jthl, jinc, nmat); add_mat_line(m, v, derivs[1][0], ends[0][1], -1, j, jk0l, jinc, nmat); add_mat_line(m, v, derivs[2][0], ends[0][2], -1, j, jk1l, jinc, nmat); add_mat_line(m, v, derivs[3][0], ends[0][3], -1, j, jk2l, jinc, nmat); add_mat_line(m, v, derivs[0][1], -ends[1][0], 1, j, jthr, jinc, nmat); add_mat_line(m, v, derivs[1][1], -ends[1][1], 1, j, jk0r, jinc, nmat); add_mat_line(m, v, derivs[2][1], -ends[1][2], 1, j, jk1r, jinc, nmat); add_mat_line(m, v, derivs[3][1], -ends[1][3], 1, j, jk2r, jinc, nmat); if (jthl >= 0) v[jthl] = mod_2pi(v[jthl]); if (jthr >= 0) v[jthr] = mod_2pi(v[jthr]); j += jinc; } if (cyclic) { memcpy(m + nmat, m, sizeof(bandmat) * nmat); memcpy(m + 2 * nmat, m, sizeof(bandmat) * nmat); memcpy(v + nmat, v, sizeof(double) * nmat); memcpy(v + 2 * nmat, v, sizeof(double) * nmat); n_invert = 3 * nmat; j = nmat; #ifdef VERBOSE printf("cyclic\n"); #endif } else { n_invert = nmat; j = 0; } #ifdef VERBOSE for (i = 0; i < n; i++) { for (k = 0; k < 11; k++) printf(" %2.4f", m[i].a[k]); printf(": %2.4f\n", v[i]); } printf("---\n"); #endif bandec11(m, perm, n_invert); banbks11(m, perm, v, n_invert); norm = 0.; for (i = 0; i < n; i++) { jinc = compute_jinc(s[i].ty, s[i + 1].ty); for (k = 0; k < jinc; k++) { dk = v[j++]; #ifdef VERBOSE printf("s[%d].ks[%d] += %f\n", i, k, dk); #endif s[i].ks[k] += dk; norm += dk * dk; } s[i].ks[0] = 2.0 * mod_2pi(s[i].ks[0]/2.0); } return norm; }
static spiro_seg * setup_path0(const spiro_cp *src, double *dm, int n) { int i, ilast, n_seg; double dx, dy; double xmin, xmax, ymin, ymax; spiro_seg *r; if (src[0].ty == 'h' || src[n - 1].ty == 'a') { /* pair */ #ifdef VERBOSE fprintf(stderr, "ERROR: LibSpiro: cannot use cp type 'h' as start, or 'a' as end.\n"); #endif return 0; } #ifdef CHECK_INPUT_FINITENESS /* Verify that input values are within realistic limits */ for (i = 0; i < n; i++) { if (IS_FINITE(src[i].x)==0 || IS_FINITE(src[i].y)==0) { #ifdef VERBOSE fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} is not finite.\n", \ i, src[i].ty, src[i].x, src[i].y); #endif return 0; } } #endif n_seg = src[0].ty == '{' ? n - 1 : n; r = (spiro_seg *)malloc((n_seg + 1) * sizeof(spiro_seg)); if (r==NULL) return 0; if (dm[0] < 0.9) { /* for math to be scalable fit it within -0.5..+0.5 */ xmin = xmax = src[0].x; ymin = ymax = src[0].y; for (i = 0; i < n_seg; i++) { if (src[i].ty != 'z' && src[i].ty != 'h') { if (src[i].x < xmin) xmin = src[i].x; else if (src[i].x > xmax) xmax = src[i].x; if (src[i].y < ymin) ymin = src[i].y; else if (src[i].y > ymax) ymax = src[i].y; } } dm[1] /* xoff */ = (xmin + xmax) / 2; xmax -= xmin; dm[2] /* yoff */ = (ymin + ymax) / 2; ymax -= ymin; dm[0] /* scale */ = fabs((fabs(xmax) >= fabs(ymax)) ? xmax : ymax); if (xmax >= ymax) dm[0] = xmax; else dm[0] = ymax; dm[0] /* scale */ /= 500.; /* ~ backwards compatible */ /* set_dm_to_1(dm); testing */ } #ifdef VERBOSE printf("scale=%g, x_offset=%g, y_offset=%g\n", dm[0], dm[1], dm[2]); #endif // } for (i = 0; i < n_seg; i++) { r[i].x = (src[i].x - dm[1]) / dm[0]; r[i].y = (src[i].y - dm[2]) / dm[0]; r[i].ty = src[i].ty; r[i].ks[0] = 0.; r[i].ks[1] = 0.; r[i].ks[2] = 0.; r[i].ks[3] = 0.; } r[n_seg].x = (src[n_seg % n].x - dm[1]) / dm[0]; r[n_seg].y = (src[n_seg % n].y - dm[2]) / dm[0]; r[n_seg].ty = src[n_seg % n].ty; for (i = 0; i < n_seg; i++) { if (r[i].ty == 'h' || (i == n_seg-1 && i > 0 && r[i].ty == '}' && r[i - 1].ty == 'a')) { /* behave like a disconnected pair of '[' & ']' */ /* point 'a' holds vector to old 'h' and now we */ /* change x,y here to be the same as point 'a'. */ /* curve fitting is based on vectors and angles */ /* but final curves will be based on x,y points */ r[i].x = r[i - 1].x; r[i].y = r[i - 1].y; } dx = r[i + 1].x - r[i].x; dy = r[i + 1].y - r[i].y; #ifndef CHECK_INPUT_FINITENESS r[i].seg_ch = hypot(dx, dy); #else if (IS_FINITE(dx)==0 || IS_FINITE(dy)==0 || \ IS_FINITE((r[i].seg_ch = hypot(dx, dy)))==0) { #ifdef VERBOSE fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} hypot error.\n", \ i, src[i].ty, src[i].x, src[i].y); #endif free(r); return 0; } #endif r[i].seg_th = atan2(dy, dx); } ilast = n_seg - 1; for (i = 0; i < n_seg; i++) { if (r[i].ty == '{' || r[i].ty == '}' || r[i].ty == 'v') r[i].bend_th = 0.; else r[i].bend_th = mod_2pi(r[i].seg_th - r[ilast].seg_th); ilast = i; #ifdef VERBOSE printf("input #%d={'%c',%g=>%g,%g=>%g}, hypot=%g, atan2=%g, bend_th=%g\n", \ i, src[i].ty, src[i].x, r[i].x, src[i].y, r[i].y, r[i].seg_ch, r[i].seg_th, r[i].bend_th); #endif } #ifdef VERBOSE if (n_seg < n) printf("input #%d={'%c',%g=>%g,%g=>%g}\n", i, src[i].ty, src[i].x, r[i].x, src[i].y, r[i].y); #endif return r; }
static spiro_seg * setup_path(const spiro_cp *src, int n) { int i, ilast, n_seg; double dx, dy; spiro_seg *r; #ifdef CHECK_INPUT_FINITENESS /* Verify that input values are within realistic limits */ for (i = 0; i < n; i++) { if (IS_FINITE(src[i].x)==0 || IS_FINITE(src[i].y)==0) { #ifdef VERBOSE fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} is not finite.\n", \ i, src[i].ty, src[i].x, src[i].y); #endif return 0; } } #endif n_seg = src[0].ty == '{' ? n - 1 : n; r = (spiro_seg *)malloc((n_seg + 1) * sizeof(spiro_seg)); if ( r==NULL ) return 0; for (i = 0; i < n_seg; i++) { r[i].x = src[i].x; r[i].y = src[i].y; r[i].ty = src[i].ty; r[i].ks[0] = 0.; r[i].ks[1] = 0.; r[i].ks[2] = 0.; r[i].ks[3] = 0.; } r[n_seg].x = src[n_seg % n].x; r[n_seg].y = src[n_seg % n].y; r[n_seg].ty = src[n_seg % n].ty; for (i = 0; i < n_seg; i++) { dx = r[i + 1].x - r[i].x; dy = r[i + 1].y - r[i].y; #ifndef CHECK_INPUT_FINITENESS r[i].seg_ch = hypot(dx, dy); #else if (IS_FINITE(dx)==0 || IS_FINITE(dy)==0 || \ IS_FINITE((r[i].seg_ch = hypot(dx, dy)))==0) { #ifdef VERBOSE fprintf(stderr, "ERROR: LibSpiro: #%d={'%c',%g,%g} hypot error.\n", \ i, src[i].ty, r[i].x, r[i].y); #endif free(r); return 0; } #endif r[i].seg_th = atan2(dy, dx); } ilast = n_seg - 1; for (i = 0; i < n_seg; i++) { if (r[i].ty == '{' || r[i].ty == '}' || r[i].ty == 'v') r[i].bend_th = 0.; else r[i].bend_th = mod_2pi(r[i].seg_th - r[ilast].seg_th); ilast = i; #ifdef VERBOSE printf("input #%d={'%c',%g,%g}, hypot=%g, atan2=%g, bend_th=%g\n", \ i, src[i].ty, r[i].x, r[i].y, r[i]. seg_th, r[i].seg_th, r[i].bend_th); #endif } #ifdef VERBOSE if (n_seg < n) printf("input #%d={'%c',%g,%g}\n", i, src[i].ty, r[i].x, r[i].y); #endif return r; }