home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / AppKit / Lines / UserPath.m < prev   
Text File  |  1992-02-09  |  10KB  |  380 lines

  1. /* 
  2.  * UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
  3.  *
  4.  * You may freely copy,distribute and re-use the code in this example. NeXT
  5.  * disclaims any warranty of any kind, expressed or implied, as to its fitness
  6.  * for any particular purpose
  7.  *
  8.  */
  9.  
  10. #import "UserPath.h"
  11. #import <mach/mach_init.h>
  12. #import <appkit/graphics.h>
  13. #import <appkit/errors.h>
  14. #import <math.h>
  15. #import <libc.h>
  16.  
  17. static NXZone      *upZone = NULL;
  18.  
  19. NXZone *userPathZone()
  20. /* Creates a unique zone for use by all user paths */
  21. {
  22.     if (!upZone) {
  23.     upZone = NXCreateZone(vm_page_size, vm_page_size, 1);
  24.     }
  25.     
  26.     return upZone;
  27. }
  28.  
  29. UserPath *newUserPath()
  30. /* Creates a new User Path in the zone returned by userPathZone */
  31. {
  32.     UserPath    *up;
  33.  
  34.     up = (UserPath *)NXZoneMalloc(userPathZone(), sizeof(UserPath));
  35.     up->max = 32;
  36.     up->points = (float *)NXZoneMalloc(userPathZone(),
  37.                            sizeof(float) * up->max);
  38.     up->ops = !0Cr *)NXZoneMalloc(userPathZone(),
  39.                        (2 + (up->max / 2)) * sizeof(char));
  40.     up->ping = NO;
  41.     
  42.     return up;
  43. }
  44.  
  45. void freeUserPath(UserPath *up)
  46. /* Frees User Path and its associated buffers */
  47. {
  48.     free(up->points);
  49.     free(up->ops);
  50.     free(up);
  51.     
  52.     return;
  53. }
  54.  
  55. void growUserPath(UserPath *up)
  56. /*
  57.  * grows the  associated buffers as necessary. buffer size doubles on each
  58.  * call. You never need to call grow directly as it is called as needed by the
  59.  * methods and functions which add elements into the buffer
  60.  */
  61. {
  62.  /* double the size of the internal buffers */
  63.     up->max *= 2;
  64.     up->points = (float *)NXZoneRealloc(userPathZone(), up->points,
  65.                     sizeof(float) * up->max);
  66.     up->ops = (char *)NXZoneRealloc(userPathZone(), up->ops,
  67.                         (2 + (up->max / 2)) * sizeof(char));
  68.  
  69.     return;
  70. }
  71.  
  72. void beginUserPath(UserPath *up, BOOL cache)
  73. /*
  74.  * Call this to start generating a user path. The cache argument specifies if
  75.  * you want the user path cached at the server (i.e. dps_ucache). In either
  76.  * case, the UserPath object will automatically calculate the bounding box for
  77.  * the path and add the dps_setbbox operator.
  78.  */
  79. {
  80.     up->numberOfPoints = up->numberOfOps = 0;
  81.     up->cp.x = up->cp.y = 0;
  82.     up->bbox[0] = up->bbox[1] = 1.0e6;
  83.     up->bbox[2] = up->bbox[3] = -1.0e6;
  84.     if (cache) {
  85.     up->ops[up->numberOfOps++] = dps_ucache;
  86.     }
  87.     up->ops[up->numberOfOps++] = dps_setbbox;
  88.     up->opForUserPath = 0;
  89.     
  90.     return;
  91. }
  92.  
  93. void endUserPath(UserPath *up, int op)
  94. /*
  95.  * Call this to stop filling the path. Note this does not send the userpath to
  96.  * the server -- use sendUserPath. The op argument should be one of the
  97.  * following:
  98.  *    dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
  99.  *    dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
  100.  * These are defined in <dpsclient/dpsNext.h.  
  101.  */
  102. {
  103.     up->opForUserPath = op;
  104.     
  105.     return;
  106. }
  107.  
  108.  
  109. void UPdebug(UserPath *up, BOOL shouldPing)
  110. /*
  111.  * Sets ping to YES so that after each time a user path is sent down to the
  112.  * window server, an NXPing() is sent after. The purpose is to catch PostScript
  113.  * errors that may be generated by the user path. sendUserPath brackets the
  114.  * download and the NXPing() in an NX_DURING... NX_HANDLER construct. Normally
  115.  * ping is NO. 
  116.  */
  117. {
  118.     up->ping = shouldPing;
  119.     
  120.     return;
  121. }
  122.  
  123. int se!0DerPath(UserPath *up)
  124. /*
  125.  * Call this to send the path down to the server. If ping==YES (set via
  126.  * debug:), the function will send an NXPing() after the Path. In any event,
  127.  * code is bracketed by a NX_DURING ... NX_HANDLER construct which will try to
  128.  * catch postscript errors.  If ping==NO (the default) it is unlikely to catch
  129.  * errors, with ping==YES it will. Whether you can recover or not is another
  130.  * matter. sendUserPath returns 0 on success and -1 on failure. If no previous
  131.  * endUserPath: has been sent, will return -2 and will not send the path to the
  132.  * server.
  133.  */
  134. {
  135.     NXHandler           exception;
  136.  
  137.     exception.code = 0;
  138.     if (up->opForUserPath != 0) {
  139.       NX_DURING
  140.     DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops,
  141.               up->numberOfOps, up->bbox, up->opForUserPath);
  142.     if (up->ping) {
  143.         NXPing();
  144.     }
  145.     
  146.       NX_HANDLER
  147.     exception = NXLocalHandler;
  148.       NX_ENDHANDLER
  149.     if (exception.code) {
  150.         NXReportError(&exception);
  151.         if (exception.code == dps_err_ps) {
  152.         return -1;
  153.         }
  154.     } else {
  155.         return 0;
  156.     }
  157.     }
  158.     
  159.     return -1;
  160. }
  161.  
  162. void checkBoundingBox(UserPath *up, float x, float y)
  163. /* Checks if bounding box needs to be enlarged based on x and y */
  164. {
  165.     if (x < up->bbox[0]) {
  166.     up->bbox[0] = x;
  167.     }
  168.     if (y < up->bbox[1]) {
  169.     up->bbox[1] = y;
  170.     }
  171.     if (x > up->bbox[2]) {
  172.     up->bbox[2] = x;
  173.     }
  174.     if (y > up->bbox[3]) {
  175.     up->bbox[3] = y;
  176.     }
  177.     
  178.     return;
  179. }
  180.  
  181. void addPts(UserPath *up, float x, float y)
  182. /* adds x and y to user path. Updates bounding box as necessary */
  183. {
  184.     if (!((up->numberOfPoints + 2) < up->max)) {
  185.     growUserPath(up);
  186.     }
  187.     
  188.     up->points[up->numberOfPoints++] = x;
  189.     up->points[up->numberOfPoints++] = y;
  190.     checkBoundingBox(up, x, y);
  191.     
  192.     return;
  193. }
  194.  
  195. void addOp(UserPath *up, int op)
  196. /*
  197.  * adds operator to user path.  Operator should be one of the following:
  198.  *     dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
  199.  *    dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
  200.  */
  201. {
  202.     up->ops[up->numberOfOps++] = op;
  203.     
  204.     return;
  205. }
  206.  
  207. void add(UserPath *up, int op, float x, float y)
  208. /*
  209.  * adds operator and x and y to user path. Operator should be one of the
  210.  * operators above
  211.  */
  212. {
  213.     if (!((up->numberOfPoints + 2) < up->max)) {
  214.     growUserPath(up);
  215.     }
  216.     
  217.     up->ops[up->numberOfOps++] = op;
  218.     up->points[!0EnumberOfPoints++] = x;
  219.     up->points[up->numberOfPoints++] = y;
  220.     checkBoundingBox(up, x, y);
  221.     
  222.     return;
  223. }
  224.  
  225. void UPmoveto(UserPath *up, float x, float y)
  226. /* adds <x y moveto> to user path and updates bounding box */
  227. {
  228.     add(up, dps_moveto, x, y);
  229.     up->cp.x = x;
  230.     up->cp.y = y;
  231.     
  232.     return;
  233. }
  234.  
  235. void UPrmoveto(UserPath *up, float x, float y)
  236. /* adds <x y rmoveto> to user path and updates bounding box */
  237. {
  238.     if (!((up->numberOfPoints + 2) < up->max)) {
  239.     growUserPath(up);
  240.     }
  241.     up->ops[up->numberOfOps++] = dps_rmoveto;
  242.     up->points[up->numberOfPoints++] = x;
  243.     up->points[up->numberOfPoints++] = y;
  244.     up->cp.x += x;
  245.     up->cp.y += y;
  246.     checkBoundingBox(up, up->cp.x, up->cp.y);
  247.     
  248.     return;
  249. }
  250.  
  251. void UPlineto(UserPath *up, float x, float y)
  252. /* adds <x y lineto> to user path and updates bounding box */
  253. {
  254.     add(up, dps_lineto, x, y);
  255.     up->cp.x = x;
  256.     up->cp.y = y;
  257.     
  258.     return;
  259. }
  260.  
  261. void UPrlineto(UserPath *up, float x, float y)
  262. /* adds <x y rlineto> to user path and updates bounding box */
  263. {
  264.     if (!((up->numberOfPoints + 2) < up->max)) {
  265.     growUserPath(up);
  266.     }
  267.     up->ops[up->numberOfOps++] = dps_rlineto;
  268.     up->points[up->numberOfPoints++] = x;
  269.     up->points[up->numberOfPoints++] = y;
  270.     up->cp.x += x;
  271.     up->cp.y += y;
  272.     checkBoundingBox(up, up->cp.x, up->cp.y);
  273.     
  274.     return;
  275. }
  276.  
  277. void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3,
  278.            float y3)
  279. /* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box */
  280. {
  281.     addPts(up, x1, y1);
  282.     addPts(up, x2, y2);
  283.     add(up, dps_curveto, x3, y3);
  284.     up->cp.x = x3;
  285.     up->cp.y = y3;
  286.     
  287.     return;
  288. }
  289.  
  290. void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2,
  291.         float dx3, float dy3)
  292. /* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box */
  293. {
  294.     if (!((up->numberOfPoints + 6) < up->max)) {
  295.     growUserPath(up);
  296.     }
  297.     up->ops[up->numberOfOps++] = dps_rcurveto;
  298.     up->points[up->numberOfPoints++] = dx1;
  299.     up->points[up->numberOfPoints++] = dy1;
  300.     up->points[up->numberOfPoints++] = dx2;
  301.     up->points[up->numberOfPoints++] = dy2;
  302.     up->points[up->numberOfPoints++] = dx3;
  303.     up->points[up->numberOfPoints++] = dy3;
  304.     checkBoundingBox(up, up->cp.x + dx1, up->cp.y + dy1);
  305.     checkBoundingBox(up, up->cp.x + dx2, up->cp.y + dy2);
  306.     checkBound!0Fox(up, up->cp.x + dx3, up->cp.y + dy3);
  307.     up->cp.x = dx3;
  308.     up->cp.y = dy3;
  309.  
  310.     return;
  311. }
  312.  
  313. void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2)
  314. /* adds <x y r ang1 ang2 arc> to user path and updates bounding box */
  315. {
  316.     if (!((up->numberOfPoints + 5) < up->max)) {
  317.     growUserPath(up);
  318.     }
  319.     up->ops[up->numberOfOps++] = dps_arc;
  320.     up->points[up->numberOfPoints++] = x;
  321.     up->points[up->numberOfPoints++] = y;
  322.     up->points[up->numberOfPoints++] = r;
  323.     up->points[up->numberOfPoints++] = ang1;
  324.     up->points[up->numberOfPoints++] = ang2;
  325.     checkBoundingBox(up, x + r, y + r);
  326.     checkBoundingBox(up, x - r, y - r);
  327.     up->cp.x = x + cos(ang2 / 57.3) * r;
  328.     up->cp.y = y + sin(ang2 / 57.3) * r;
  329.     
  330.     return;
  331. }
  332.  
  333. void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2)
  334. /* adds <x y r ang1 ang2 arcn> to user path and updates bounding box */
  335. {
  336.     if (!((up->numberOfPoints + 5) < up->max)) {
  337.     growUserPath(up);
  338.     }
  339.     up->ops[up->numberOfOps++] = dps_arcn;
  340.     up->points[up->numberOfPoints++] = x;
  341.     up->points[up->numberOfPoints++] = y;
  342.     up->points[up->numberOfPoints++] = r;
  343.     up->points[up->numberOfPoints++] = ang1;
  344.     up->points[up->numberOfPoints++] = ang2;
  345.     checkBoundingBox(up, x + r, y + r);
  346.     checkBoundingBox(up, x - r, y - r);
  347.     up->cp.x = x + cos(ang2 / 57.3) * r;
  348.     up->cp.y = y + sin(ang2 / 57.3) * r;
  349.     
  350.     return;
  351. }
  352.  
  353. void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r)
  354. /* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box */
  355. {
  356.     if (!((up->numberOfPoints + 5) < up->max)) {
  357.     growUserPath(up);
  358.     }
  359.     up->ops[up->numberOfOps++] = dps_arcn;
  360.     up->points[up->numberOfPoints++] = x1;
  361.     up->points[up->numberOfPoints++] = y1;
  362.     up->points[up->numberOfPoints++] = x2;
  363.     up->points[up->numberOfPoints++] = y2;
  364.     up->points[up->numberOfPoints++] = r;
  365.     checkBoundingBox(up, x1, y1);
  366.     checkBoundingBox(up, x2, y2);
  367.     up->cp.x = x2;
  368.     up->cp.y = y2;
  369.     
  370.     return;
  371. }
  372.  
  373. void closePath(UserPath *up)
  374. /* adds <closepath> to user path and updates bounding box */
  375. {
  376.     up->ops[up->numberOfOps++] = dps_closepath;
  377.     
  378.     return;
  379. }
  380.