void bezctx_ink_lineto(bezctx *bc, double x, double y) { bezctx_ink *bi = (bezctx_ink *) bc; if ( IS_FINITE(x) && IS_FINITE(y) ) { bi->curve->lineto(x, y); } #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS else { g_message("lpe lineto not finite"); } #endif }
void bezctx_ink_curveto(bezctx *bc, double x1, double y1, double x2, double y2, double x3, double y3) { bezctx_ink *bi = (bezctx_ink *) bc; if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) { bi->curve->curveto(x1, y1, x2, y2, x3, y3); } #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS else { g_message("lpe curveto not finite"); } #endif }
void bezctx_ink_quadto(bezctx *bc, double xm, double ym, double x3, double y3) { bezctx_ink *bi = (bezctx_ink *) bc; if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) { bi->curve->quadto(xm, ym, x3, y3); } #ifdef SPIRO_SHOW_INFINITE_COORDINATE_CALLS else { g_message("lpe quadto not finite"); } #endif }
static int check_finiteness(spiro_seg * segs, int num_segs) { /* Check if all values are "finite", return true=0, else return fail=-1 */ int i, j; for (i = 0; i < num_segs; ++i) for (j = 0; j < 4; ++j) if ( IS_FINITE( segs[i].ks[j])==0 ) return -1; return 0; }
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; }
/* * set attributes via outer (t=1) knot point: * [default] increase/decrease revolution factor * [control] constrain inner arg to round per PI/4 */ void SpiralKnotHolderEntityOuter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int snaps = prefs->getInt("/options/rotationsnapsperpi/value", 12); SPSpiral *spiral = SP_SPIRAL(item); gdouble dx = p[Geom::X] - spiral->cx; gdouble dy = p[Geom::Y] - spiral->cy; if (state & GDK_SHIFT_MASK) { // rotate without roll/unroll spiral->arg = atan2(dy, dx) - 2.0*M_PI*spiral->revo; if (!(state & GDK_MOD1_MASK)) { // if alt not pressed, change also rad; otherwise it is locked spiral->rad = MAX(hypot(dx, dy), 0.001); } if ( ( state & GDK_CONTROL_MASK ) && snaps ) { spiral->arg = sp_round(spiral->arg, M_PI/snaps); } } else { // roll/unroll // arg of the spiral outer end double arg_1; spiral->getPolar(1, NULL, &arg_1); // its fractional part after the whole turns are subtracted double arg_r = arg_1 - sp_round(arg_1, 2.0*M_PI); // arg of the mouse point relative to spiral center double mouse_angle = atan2(dy, dx); if (mouse_angle < 0) mouse_angle += 2*M_PI; // snap if ctrl if ( ( state & GDK_CONTROL_MASK ) && snaps ) { mouse_angle = sp_round(mouse_angle, M_PI/snaps); } // by how much we want to rotate the outer point double diff = mouse_angle - arg_r; if (diff > M_PI) diff -= 2*M_PI; else if (diff < -M_PI) diff += 2*M_PI; // calculate the new rad; // the value of t corresponding to the angle arg_1 + diff: double t_temp = ((arg_1 + diff) - spiral->arg)/(2*M_PI*spiral->revo); // the rad at that t: double rad_new = 0; if (t_temp > spiral->t0) spiral->getPolar(t_temp, &rad_new, NULL); // change the revo (converting diff from radians to the number of turns) spiral->revo += diff/(2*M_PI); if (spiral->revo < 1e-3) spiral->revo = 1e-3; // if alt not pressed and the values are sane, change the rad if (!(state & GDK_MOD1_MASK) && rad_new > 1e-3 && rad_new/spiral->rad < 2) { // adjust t0 too so that the inner point stays unmoved double r0; spiral->getPolar(spiral->t0, &r0, NULL); spiral->rad = rad_new; spiral->t0 = pow(r0 / spiral->rad, 1.0/spiral->exp); } if (!IS_FINITE(spiral->t0)) spiral->t0 = 0.0; spiral->t0 = CLAMP(spiral->t0, 0.0, 0.999); } (static_cast<SPObject *>(spiral))->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); }