home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / GSCOORD.C < prev    next >
C/C++ Source or Header  |  1994-07-31  |  11KB  |  398 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gscoord.c */
  20. /* Coordinate system operators for Ghostscript library */
  21. #include "math_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsccode.h"            /* for gxfont.h */
  25. #include "gxfarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"
  28. #include "gxfont.h"            /* for char_tm */
  29. #include "gxpath.h"            /* for gx_path_translate */
  30. #include "gzstate.h"
  31. #include "gxcoord.h"            /* requires gsmatrix, gsstate */
  32.  
  33. /* Choose whether to enable the rounding code in update_ctm_fixed. */
  34. #define ROUND_CTM_FIXED 1
  35.  
  36. /* Forward declarations */
  37. #ifdef DEBUG
  38. #define trace_ctm(pgs) trace_matrix_fixed(&(pgs)->ctm)
  39. private void near trace_matrix_fixed(P1(const gs_matrix_fixed *));
  40. private void near trace_matrix(P1(const gs_matrix *));
  41. #endif
  42.  
  43. /* Macro for ensuring ctm_inverse is valid */
  44. #ifdef DEBUG
  45. #define print_inverse(pgs)\
  46. if ( gs_debug_c('x') )\
  47.     dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
  48. #else
  49. #define print_inverse(pgs) DO_NOTHING
  50. #endif
  51. #define ensure_inverse_valid(pgs)\
  52.     if ( !pgs->inverse_valid )\
  53.        {    int code = ctm_set_inverse(pgs);\
  54.         if ( code < 0 ) return code;\
  55.        }
  56.  
  57. private int
  58. ctm_set_inverse(gs_state *pgs)
  59. {    int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
  60.     print_inverse(pgs);
  61.     if ( code < 0 ) return code;
  62.     pgs->inverse_valid = 1;
  63.     return 0;
  64. }
  65.  
  66. /* Machinery for updating fixed version of ctm. */
  67. /*
  68.  * We (conditionally) adjust the floating point translation
  69.  * so that it exactly matches the (rounded) fixed translation.
  70.  * This avoids certain unpleasant rounding anomalies, such as
  71.  * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
  72.  * not returning 0 0.
  73.  */
  74. #if ROUND_CTM_FIXED
  75. #  define update_t_fixed(mat, t, t_fixed)\
  76.     (mat).t = fixed2float((mat).t_fixed = float2fixed((mat).t))
  77. #else                    /* !ROUND_CTM_FIXED */
  78. #  define update_t_fixed(mat, t, t_fixed)\
  79.     (mat).t_fixed = float2fixed((mat).t)
  80. #endif                    /* (!)ROUND_CTM_FIXED */
  81. #define update_matrix_fixed(mat)\
  82.   update_t_fixed(mat, tx, tx_fixed),\
  83.   update_t_fixed(mat, ty, ty_fixed)
  84. #define update_ctm(pgs)\
  85.   update_matrix_fixed(pgs->ctm),\
  86.   pgs->inverse_valid = 0,\
  87.   pgs->char_tm_valid = 0
  88.  
  89. void
  90. gs_update_matrix_fixed(gs_matrix_fixed *pmat)
  91. {    update_matrix_fixed(*pmat);
  92. }
  93.  
  94. /* ------ Coordinate system definition ------ */
  95.  
  96. int
  97. gs_initmatrix(gs_state *pgs)
  98. {    gs_defaultmatrix(pgs, &ctm_only(pgs));
  99.     update_ctm(pgs);
  100. #ifdef DEBUG
  101. if ( gs_debug_c('x') )
  102.     dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
  103. #endif
  104.     return 0;
  105. }
  106.  
  107. int
  108. gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
  109. {    gx_device *dev = gs_currentdevice_inline(pgs);
  110.     (*dev_proc(dev, get_initial_matrix))(dev, pmat);
  111.     return 0;
  112. }
  113.  
  114. int
  115. gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
  116. {    *pmat = ctm_only(pgs);
  117.     return 0;
  118. }
  119.  
  120. /* Set the current transformation matrix for rendering text. */
  121. /* Note that this may be based on a font other than the current font. */
  122. int
  123. gs_setcharmatrix(gs_state *pgs, const gs_matrix *pmat)
  124. {    int code = gs_matrix_multiply(pmat, &ctm_only(pgs),
  125.                       &char_tm_only(pgs));
  126.     if ( code < 0 )
  127.         return code;
  128.     gs_update_matrix_fixed(&pgs->char_tm);
  129. #ifdef DEBUG
  130. if ( gs_debug_c('x') )
  131.     dprintf("[x]setting char_tm:"), trace_matrix_fixed(&pgs->char_tm);
  132. #endif
  133.     pgs->char_tm_valid = 1;
  134.     return 0;
  135. }
  136.  
  137. /* Read (after possibly computing) the current transformation matrix */
  138. /* for rendering text.  If force=1, update char_tm if it is invalid; */
  139. /* if force=0, don't update char_tm, and return an error code. */
  140. int
  141. gs_currentcharmatrix(gs_state *pgs, gs_matrix *ptm, int force)
  142. {    if ( !pgs->char_tm_valid )
  143.     {    int code;
  144.         if ( !force )
  145.             return_error(gs_error_undefinedresult);
  146.         code = gs_setcharmatrix(pgs, &pgs->font->FontMatrix);
  147.         if ( code < 0 )
  148.             return code;
  149.     }
  150.     if ( ptm != NULL )
  151.         *ptm = char_tm_only(pgs);
  152.     return 0;
  153. }
  154.  
  155. int
  156. gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
  157. {    ctm_only(pgs) = *pmat;
  158.     update_ctm(pgs);
  159. #ifdef DEBUG
  160. if ( gs_debug_c('x') )
  161.     dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
  162. #endif
  163.     return 0;
  164. }
  165.  
  166. int
  167. gs_settocharmatrix(gs_state *pgs)
  168. {    if ( pgs->char_tm_valid )
  169.     {    pgs->ctm = pgs->char_tm;
  170.         pgs->inverse_valid = 0;
  171.         return 0;
  172.     }
  173.     else
  174.         return_error(gs_error_undefinedresult);
  175. }
  176.  
  177. int
  178. gs_translate(gs_state *pgs, floatp dx, floatp dy)
  179. {    gs_point pt;
  180.     int code;
  181.     if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
  182.         return code;
  183.     pgs->ctm.tx += pt.x;
  184.     pgs->ctm.ty += pt.y;
  185.     update_ctm(pgs);
  186. #ifdef DEBUG
  187. if ( gs_debug_c('x') )
  188.     dprintf4("[x]translate: %f %f -> %f %f\n",
  189.          dx, dy, pt.x, pt.y),
  190.     trace_ctm(pgs);
  191. #endif
  192.     return 0;
  193. }
  194.  
  195. int
  196. gs_scale(gs_state *pgs, floatp sx, floatp sy)
  197. {    pgs->ctm.xx *= sx;
  198.     pgs->ctm.xy *= sx;
  199.     pgs->ctm.yx *= sy;
  200.     pgs->ctm.yy *= sy;
  201.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  202. #ifdef DEBUG
  203. if ( gs_debug_c('x') )
  204.     dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
  205. #endif
  206.     return 0;
  207. }
  208.  
  209. int
  210. gs_rotate(gs_state *pgs, floatp ang)
  211. {    int code = gs_matrix_rotate(&ctm_only(pgs), ang, &ctm_only(pgs));
  212.     pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
  213. #ifdef DEBUG
  214. if ( gs_debug_c('x') )
  215.     dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
  216. #endif
  217.     return code;
  218. }
  219.  
  220. int
  221. gs_concat(gs_state *pgs, const gs_matrix *pmat)
  222. {    int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &ctm_only(pgs));
  223.     update_ctm(pgs);
  224. #ifdef DEBUG
  225. if ( gs_debug_c('x') )
  226.     dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
  227. #endif
  228.     return code;
  229. }
  230.  
  231. /* ------ Coordinate transformation ------ */
  232.  
  233. int
  234. gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  235. {    return gs_point_transform(x, y, &ctm_only(pgs), pt);
  236. }
  237.  
  238. int
  239. gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  240. {    return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
  241. }
  242.  
  243. int
  244. gs_itransform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
  245. {    /* If the matrix isn't skewed, we get more accurate results */
  246.     /* by using transform_inverse than by using the inverse matrix. */
  247.     if ( !is_skewed(&pgs->ctm) )
  248.        {    return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
  249.        }
  250.     else
  251.        {    ensure_inverse_valid(pgs);
  252.         return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
  253.        }
  254. }
  255.  
  256. int
  257. gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
  258. {    /* If the matrix isn't skewed, we get more accurate results */
  259.     /* by using transform_inverse than by using the inverse matrix. */
  260.     if ( !is_skewed(&pgs->ctm) )
  261.        {    return gs_distance_transform_inverse(dx, dy,
  262.                              &ctm_only(pgs), pt);
  263.        }
  264.     else
  265.        {    ensure_inverse_valid(pgs);
  266.         return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
  267.        }
  268. }
  269.  
  270. /* ------ For internal use only ------ */
  271.  
  272. /* Set the translation to a fixed value, and translate any existing path. */
  273. /* Used by gschar.c to prepare for a BuildChar or BuildGlyph procedure. */
  274. int
  275. gx_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
  276. {    fixed dx = px - pgs->ctm.tx_fixed;
  277.     fixed dy = py - pgs->ctm.ty_fixed;
  278.     int result = gx_path_translate(pgs->path, dx, dy);
  279.     pgs->ctm.tx = fixed2float(pgs->ctm.tx_fixed = px);
  280.     pgs->ctm.ty = fixed2float(pgs->ctm.ty_fixed = py);
  281.     pgs->inverse_valid = 0;
  282.     if ( pgs->char_tm_valid )
  283.     {    /* Update char_tm now, leaving it valid. */
  284.         pgs->char_tm.tx += fixed2float(dx);
  285.         pgs->char_tm.ty += fixed2float(dy);
  286.         pgs->char_tm.tx_fixed += dx;
  287.         pgs->char_tm.ty_fixed += dy;
  288.     }
  289. #ifdef DEBUG
  290. if ( gs_debug_c('x') )
  291.     dprintf2("[x]translate_to_fixed %g, %g:\n",
  292.          fixed2float(px), fixed2float(py)),
  293.     trace_ctm(pgs),
  294.     dprintf("[x]   char_tm:\n"),
  295.     trace_matrix_fixed(&pgs->char_tm);
  296. #endif
  297.     return result;
  298. }
  299.  
  300. /* Scale the CTM and character matrix for oversampling. */
  301. int
  302. gx_scale_char_matrix(register gs_state *pgs, int sx, int sy)
  303. {
  304. #define scale_cxy(s, vx, vy)\
  305.   if ( s != 1 )\
  306.    {    pgs->ctm.vx *= s;\
  307.     pgs->ctm.vy *= s;\
  308.     pgs->inverse_valid = 0;\
  309.     if ( pgs->char_tm_valid )\
  310.     {    pgs->char_tm.vx *= s;\
  311.         pgs->char_tm.vy *= s;\
  312.     }\
  313.    }
  314.     scale_cxy(sx, xx, yx);
  315.     scale_cxy(sy, xy, yy);
  316. #undef scale_cxy
  317.     if_debug2('x', "[x]char scale: %d %d\n", sx, sy);
  318.     return 0;
  319. }
  320.  
  321. /* Compute the coefficients for fast fixed-point distance transformations */
  322. /* from a transformation matrix. */
  323. /* We should cache the coefficients with the ctm.... */
  324. int
  325. gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
  326.   int max_bits)
  327. {    gs_matrix ctm;
  328.     int scale = -10000;
  329.     int expt, shift;
  330.     ctm = *pmat;
  331.     pfc->skewed = 0;
  332.     if ( !is_fzero(ctm.xx) )
  333.        {    (void)frexp(ctm.xx, &scale);
  334.        }
  335.     if ( !is_fzero(ctm.xy) )
  336.        {    (void)frexp(ctm.xy, &expt);
  337.         if ( expt > scale ) scale = expt;
  338.         pfc->skewed = 1;
  339.        }
  340.     if ( !is_fzero(ctm.yx) )
  341.        {    (void)frexp(ctm.yx, &expt);
  342.         if ( expt > scale ) scale = expt;
  343.         pfc->skewed = 1;
  344.        }
  345.     if ( !is_fzero(ctm.yy) )
  346.        {    (void)frexp(ctm.yy, &expt);
  347.         if ( expt > scale ) scale = expt;
  348.        }
  349.     scale = sizeof(long) * 8 - 1 - max_bits - scale;
  350.     shift = scale - _fixed_shift;
  351.     if ( shift > 0 )
  352.        {    pfc->shift = shift;
  353.         pfc->round = (fixed)1 << (shift - 1);
  354.        }
  355.     else
  356.        {    pfc->shift = 0;
  357.         pfc->round = 0;
  358.         scale -= shift;
  359.        }
  360. #define set_c(c)\
  361.   if ( is_fzero(ctm.c) ) pfc->c.f = 0, pfc->c.l = 0;\
  362.   else pfc->c.f = ldexp(ctm.c, _fixed_shift), pfc->c.l = (long)ldexp(ctm.c, scale)
  363.     set_c(xx);
  364.     set_c(xy);
  365.     set_c(yx);
  366.     set_c(yy);
  367. #ifdef DEBUG
  368. if ( gs_debug_c('x') )
  369.    {    dprintf6("[x]ctm: [%6g %6g %6g %6g %6g %6g]\n",
  370.          ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty);
  371.     dprintf6("   scale=%d fc: [0x%lx 0x%lx 0x%lx 0x%lx] shift=%d\n",
  372.          scale, pfc->xx.l, pfc->xy.l, pfc->yx.l, pfc->yy.l,
  373.          pfc->shift);
  374.    }
  375. #endif
  376.     pfc->max_bits = max_bits;
  377.     return 0;
  378. }
  379.  
  380. /* ------ Debugging printout ------ */
  381.  
  382. #ifdef DEBUG
  383.  
  384. /* Print a matrix */
  385. private void near
  386. trace_matrix_fixed(const gs_matrix_fixed *pmat)
  387. {    trace_matrix((const gs_matrix *)pmat);
  388.     dprintf2("\t\tt_fixed: [%6g %6g]\n",
  389.          fixed2float(pmat->tx_fixed), fixed2float(pmat->ty_fixed));
  390. }
  391. private void near
  392. trace_matrix(register const gs_matrix *pmat)
  393. {    dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
  394.          pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
  395. }
  396.  
  397. #endif
  398.