/* Transform a distance with a fixed-point result. */ int gs_distance_transform2fixed(const gs_matrix_fixed * pmat, floatp dx, floatp dy, gs_fixed_point * ppt) { fixed px, py, t; double xtemp, ytemp; int code; if ((code = CHECK_DFMUL2FIXED_VARS(px, dx, pmat->xx, xtemp)) < 0 || (code = CHECK_DFMUL2FIXED_VARS(py, dy, pmat->yy, ytemp)) < 0 ) return code; FINISH_DFMUL2FIXED_VARS(px, xtemp); FINISH_DFMUL2FIXED_VARS(py, ytemp); if (!is_fzero(pmat->yx)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, dy, pmat->yx, ytemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, ytemp); if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0) return code; } if (!is_fzero(pmat->xy)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, dx, pmat->xy, xtemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, xtemp); if ((code = CHECK_SET_FIXED_SUM(py, py, t)) < 0) return code; } ppt->x = px; ppt->y = py; return 0; }
/* Since this is used heavily, we check for shortcuts. */ int gs_matrix_multiply(const gs_matrix * pm1, const gs_matrix * pm2, gs_matrix * pmr) { double xx1 = pm1->xx, yy1 = pm1->yy; double tx1 = pm1->tx, ty1 = pm1->ty; double xx2 = pm2->xx, yy2 = pm2->yy; double xy2 = pm2->xy, yx2 = pm2->yx; if (is_xxyy(pm1)) { pmr->tx = tx1 * xx2 + pm2->tx; pmr->ty = ty1 * yy2 + pm2->ty; if (is_fzero(xy2)) pmr->xy = 0; else pmr->xy = xx1 * xy2, pmr->ty += tx1 * xy2; pmr->xx = xx1 * xx2; if (is_fzero(yx2)) pmr->yx = 0; else pmr->yx = yy1 * yx2, pmr->tx += ty1 * yx2; pmr->yy = yy1 * yy2; } else { double xy1 = pm1->xy, yx1 = pm1->yx; pmr->xx = xx1 * xx2 + xy1 * yx2; pmr->xy = xx1 * xy2 + xy1 * yy2; pmr->yy = yx1 * xy2 + yy1 * yy2; pmr->yx = yx1 * xx2 + yy1 * yx2; pmr->tx = tx1 * xx2 + ty1 * yx2 + pm2->tx; pmr->ty = tx1 * xy2 + ty1 * yy2 + pm2->ty; } return 0; }
/* Invert a matrix. Return gs_error_undefinedresult if not invertible. */ int gs_matrix_invert(const gs_matrix *pm, gs_matrix *pmr) { /* We have to be careful about fetch/store order, */ /* because pm might be the same as pmr. */ if ( is_xxyy(pm) ) { if ( is_fzero(pm->xx) || is_fzero(pm->yy) ) return_error(gs_error_undefinedresult); pmr->tx = - (pmr->xx = 1.0 / pm->xx) * pm->tx; pmr->xy = 0.0; pmr->yx = 0.0; pmr->ty = - (pmr->yy = 1.0 / pm->yy) * pm->ty; } else { double det = pm->xx * pm->yy - pm->xy * pm->yx; double mxx = pm->xx, mtx = pm->tx; if ( det == 0 ) return_error(gs_error_undefinedresult); pmr->xx = pm->yy / det; pmr->xy = - pm->xy / det; pmr->yx = - pm->yx / det; pmr->yy = mxx / det; /* xx is already changed */ pmr->tx = - (mtx * pmr->xx + pm->ty * pmr->yx); pmr->ty = - (mtx * pmr->xy + pm->ty * pmr->yy); /* tx ditto */ } return 0; }
/* Return gs_error_undefinedresult if the matrix is not invertible. */ int gs_point_transform_inverse(floatp x, floatp y, const gs_matrix * pmat, gs_point * ppt) { if (is_xxyy(pmat)) { if (is_fzero(pmat->xx) || is_fzero(pmat->yy)) return_error(gs_error_undefinedresult); ppt->x = (x - pmat->tx) / pmat->xx; ppt->y = (y - pmat->ty) / pmat->yy; return 0; } else if (is_xyyx(pmat)) { if (is_fzero(pmat->xy) || is_fzero(pmat->yx)) return_error(gs_error_undefinedresult); ppt->x = (y - pmat->ty) / pmat->xy; ppt->y = (x - pmat->tx) / pmat->yx; return 0; } else { /* There are faster ways to do this, */ /* but we won't implement one unless we have to. */ gs_matrix imat; int code = gs_matrix_invert(pmat, &imat); if (code < 0) return code; return gs_point_transform(x, y, &imat, ppt); } }
int gs_matrix_invert_to_double(const gs_matrix * pm, gs_matrix_double * pmr) { /* We have to be careful about fetch/store order, */ /* because pm might be the same as pmr. */ if (is_xxyy(pm)) { if (is_fzero(pm->xx) || is_fzero(pm->yy)) return_error(gs_error_undefinedresult); pmr->tx = -(pmr->xx = 1.0 / pm->xx) * pm->tx; pmr->xy = 0.0; pmr->yx = 0.0; pmr->ty = -(pmr->yy = 1.0 / pm->yy) * pm->ty; } else { double mxx = pm->xx, myy = pm->yy, mxy = pm->xy, myx = pm->yx; double mtx = pm->tx, mty = pm->ty; double det = (mxx * myy) - (mxy * myx); /* * We are doing the math as floats instead of doubles to reproduce * the results in page 1 of CET 10-09.ps */ if (det == 0) return_error(gs_error_undefinedresult); pmr->xx = myy / det; pmr->xy = -mxy / det; pmr->yx = -myx / det; pmr->yy = mxx / det; pmr->tx = (((mty * myx) - (mtx * myy))) / det; pmr->ty = (((mtx * mxy) - (mty * mxx))) / det; } return 0; }
/* from Ghostscript */ int matrix_invert(const MATRIX *pm, MATRIX *pmr) { /* We have to be careful about fetch/store order, */ /* because pm might be the same as pmr. */ if ( is_xxyy(pm) ) { if ( is_fzero(pm->xx) || is_fzero(pm->yy) ) return -1 ; pmr->tx = (float)(- (pmr->xx = (float)(1.0 / pm->xx)) * pm->tx); pmr->xy = 0.0; pmr->yx = 0.0; pmr->ty = (float)(- (pmr->yy = (float)(1.0 / pm->yy)) * pm->ty); } else { double det = pm->xx * pm->yy - pm->xy * pm->yx; double mxx = pm->xx, mtx = pm->tx; if ( det == 0 ) return -1 ; pmr->xx = (float)(pm->yy / det); pmr->xy = (float)(- pm->xy / det); pmr->yx = (float)(- pm->yx / det); pmr->yy = (float)(mxx / det); /* xx is already changed */ pmr->tx = (float)(- (mtx * pmr->xx + pm->ty * pmr->yx)); pmr->ty = (float)(- (mtx * pmr->xy + pm->ty * pmr->yy)); /* tx ditto */ } return 0; }
/* Transform a distance. */ int gs_distance_transform(floatp dx, floatp dy, const gs_matrix *pmat, gs_point *pdpt) { pdpt->x = dx * pmat->xx; pdpt->y = dy * pmat->yy; if ( !is_fzero(pmat->yx) ) pdpt->x += dy * pmat->yx; if ( !is_fzero(pmat->xy) ) pdpt->y += dx * pmat->xy; return 0; }
/* Transform a point. */ int gs_point_transform(floatp x, floatp y, const gs_matrix *pmat, gs_point *ppt) { ppt->x = x * pmat->xx + pmat->tx; ppt->y = y * pmat->yy + pmat->ty; if ( !is_fzero(pmat->yx) ) ppt->x += y * pmat->yx; if ( !is_fzero(pmat->xy) ) ppt->y += x * pmat->xy; return 0; }
/* Transform a point. */ int gs_point_transform(floatp x, floatp y, const gs_matrix * pmat, gs_point * ppt) { /* * The float casts are there to reproduce results in CET 10-01.ps * page 4. */ ppt->x = (float)(x * pmat->xx) + pmat->tx; ppt->y = (float)(y * pmat->yy) + pmat->ty; if (!is_fzero(pmat->yx)) ppt->x += (float)(y * pmat->yx); if (!is_fzero(pmat->xy)) ppt->y += (float)(x * pmat->xy); return 0; }
/* Test whether an image has a default ImageMatrix. */ bool gx_image_matrix_is_default(const gs_data_image_t *pid) { return (is_xxyy(&pid->ImageMatrix) && pid->ImageMatrix.xx == pid->Width && pid->ImageMatrix.yy == -pid->Height && is_fzero(pid->ImageMatrix.tx) && pid->ImageMatrix.ty == pid->Height); }
/* * Determine the flatness for rendering a character in an outline font. * This may be less than the flatness in the imager state. * The second argument is the default scaling for the font: 0.001 for * Type 1 fonts, 1.0 for TrueType fonts. */ double gs_char_flatness(const gs_imager_state *pis, floatp default_scale) { /* * Set the flatness to a value that is likely to produce reasonably * good-looking curves, regardless of its current value in the * graphics state. If the character is very small, set the flatness * to zero, which will produce very accurate curves. */ double cxx = fabs(pis->ctm.xx), cyy = fabs(pis->ctm.yy); if (is_fzero(cxx) || (cyy < cxx && !is_fzero(cyy))) cxx = cyy; if (!is_xxyy(&pis->ctm)) { double cxy = fabs(pis->ctm.xy), cyx = fabs(pis->ctm.yx); if (is_fzero(cxx) || (cxy < cxx && !is_fzero(cxy))) cxx = cxy; if (is_fzero(cxx) || (cyx < cxx && !is_fzero(cyx))) cxx = cyx; } /* Correct for the default scaling. */ cxx *= 0.001 / default_scale; /* Don't let the flatness be worse than the default. */ if (cxx > pis->flatness) cxx = pis->flatness; /* If the character is tiny, force accurate curves. */ if (cxx < 0.2) cxx = 0; return cxx; }
/* Invert a matrix. Return gs_error_undefinedresult if not invertible. */ int gs_matrix_invert(const gs_matrix * pm, gs_matrix * pmr) { /* We have to be careful about fetch/store order, */ /* because pm might be the same as pmr. */ if (is_xxyy(pm)) { if (is_fzero(pm->xx) || is_fzero(pm->yy)) return_error(gs_error_undefinedresult); pmr->tx = -(pmr->xx = 1.0 / pm->xx) * pm->tx; pmr->xy = 0.0; pmr->yx = 0.0; pmr->ty = -(pmr->yy = 1.0 / pm->yy) * pm->ty; } else { float mxx = pm->xx, myy = pm->yy, mxy = pm->xy, myx = pm->yx; float mtx = pm->tx, mty = pm->ty; /* we declare det as double since on at least some computer (i.e. peeves) declaring it as a float results in different values for pmr depending on whether or not optimization is turned on. I believe this is caused by the compiler keeping the det value in an internal register when optimization is enable. As evidence of this if you add a debugging statement to print out det the optimized code acts the same as the unoptimized code. declearing det as double does not change the CET 10-09.ps output. */ double det = (float)(mxx * myy) - (float)(mxy * myx); /* * We are doing the math as floats instead of doubles to reproduce * the results in page 1 of CET 10-09.ps */ if (det == 0) return_error(gs_error_undefinedresult); pmr->xx = myy / det; pmr->xy = -mxy / det; pmr->yx = -myx / det; pmr->yy = mxx / det; pmr->tx = (((float)(mty * myx) - (float)(mtx * myy))) / det; pmr->ty = (((float)(mtx * mxy) - (float)(mty * mxx))) / det; } return 0; }
/* Return gs_error_undefinedresult if the matrix is not invertible. */ int gs_distance_transform_inverse(floatp dx, floatp dy, const gs_matrix * pmat, gs_point * pdpt) { if (is_xxyy(pmat)) { if (is_fzero(pmat->xx) || is_fzero(pmat->yy)) return_error(gs_error_undefinedresult); pdpt->x = dx / pmat->xx; pdpt->y = dy / pmat->yy; } else if (is_xyyx(pmat)) { if (is_fzero(pmat->xy) || is_fzero(pmat->yx)) return_error(gs_error_undefinedresult); pdpt->x = dy / pmat->xy; pdpt->y = dx / pmat->yx; } else { double det = pmat->xx * pmat->yy - pmat->xy * pmat->yx; if (det == 0) return_error(gs_error_undefinedresult); pdpt->x = (dx * pmat->yy - dy * pmat->yx) / det; pdpt->y = (dy * pmat->xx - dx * pmat->xy) / det; } return 0; }
/* Transform a point with a fixed-point result. */ int gs_point_transform2fixed(const gs_matrix_fixed * pmat, floatp x, floatp y, gs_fixed_point * ppt) { fixed px, py, t; double xtemp, ytemp; int code; if (!pmat->txy_fixed_valid) { /* The translation is out of range. Do the */ /* computation in floating point, and convert to */ /* fixed at the end. */ gs_point fpt; gs_point_transform(x, y, (const gs_matrix *)pmat, &fpt); if (!(f_fits_in_fixed(fpt.x) && f_fits_in_fixed(fpt.y))) return_error(gs_error_limitcheck); ppt->x = float2fixed(fpt.x); ppt->y = float2fixed(fpt.y); return 0; } if (!is_fzero(pmat->xy)) { /* Hope for 90 degree rotation */ if ((code = CHECK_DFMUL2FIXED_VARS(px, y, pmat->yx, xtemp)) < 0 || (code = CHECK_DFMUL2FIXED_VARS(py, x, pmat->xy, ytemp)) < 0 ) return code; FINISH_DFMUL2FIXED_VARS(px, xtemp); FINISH_DFMUL2FIXED_VARS(py, ytemp); if (!is_fzero(pmat->xx)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, x, pmat->xx, xtemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, xtemp); if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0) return code; } if (!is_fzero(pmat->yy)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yy, ytemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, ytemp); if ((code = CHECK_SET_FIXED_SUM(py, py, t)) < 0) return code; } } else { if ((code = CHECK_DFMUL2FIXED_VARS(px, x, pmat->xx, xtemp)) < 0 || (code = CHECK_DFMUL2FIXED_VARS(py, y, pmat->yy, ytemp)) < 0 ) return code; FINISH_DFMUL2FIXED_VARS(px, xtemp); FINISH_DFMUL2FIXED_VARS(py, ytemp); if (!is_fzero(pmat->yx)) { if ((code = CHECK_DFMUL2FIXED_VARS(t, y, pmat->yx, ytemp)) < 0) return code; FINISH_DFMUL2FIXED_VARS(t, ytemp); if ((code = CHECK_SET_FIXED_SUM(px, px, t)) < 0) return code; } } if (((code = CHECK_SET_FIXED_SUM(ppt->x, px, pmat->tx_fixed)) < 0) || ((code = CHECK_SET_FIXED_SUM(ppt->y, py, pmat->ty_fixed)) < 0) ) return code; return 0; }
/* We should cache the coefficients with the ctm.... */ int gx_matrix_to_fixed_coeff(const gs_matrix * pmat, register fixed_coeff * pfc, int max_bits) { gs_matrix ctm; int scale = -10000; int expt, shift; ctm = *pmat; pfc->skewed = 0; if (!is_fzero(ctm.xx)) { discard(frexp(ctm.xx, &scale)); } if (!is_fzero(ctm.xy)) { discard(frexp(ctm.xy, &expt)); if (expt > scale) scale = expt; pfc->skewed = 1; } if (!is_fzero(ctm.yx)) { discard(frexp(ctm.yx, &expt)); if (expt > scale) scale = expt; pfc->skewed = 1; } if (!is_fzero(ctm.yy)) { discard(frexp(ctm.yy, &expt)); if (expt > scale) scale = expt; } /* * There are two multiplications in fixed_coeff_mult: one involves a * factor that may have max_bits significant bits, the other may have * fixed_fraction_bits (_fixed_shift) bits. Ensure that neither one * will overflow. */ if (max_bits < fixed_fraction_bits) max_bits = fixed_fraction_bits; scale = sizeof(long) * 8 - 1 - max_bits - scale; shift = scale - _fixed_shift; if (shift > 0) { pfc->shift = shift; pfc->round = (fixed) 1 << (shift - 1); } else { pfc->shift = 0; pfc->round = 0; scale -= shift; } #define SET_C(c)\ if ( is_fzero(ctm.c) ) pfc->c = 0;\ else pfc->c = (long)ldexp(ctm.c, scale) SET_C(xx); SET_C(xy); SET_C(yx); SET_C(yy); #undef SET_C #ifdef DEBUG if (gs_debug_c('x')) { dlprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n", ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty); dlprintf6(" scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n", scale, pfc->xx, pfc->xy, pfc->yx, pfc->yy, pfc->shift); } #endif pfc->max_bits = max_bits; return 0; }