home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p024 / 16.img / AME3.LIB / OFFSOL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-17  |  56.1 KB  |  2,337 lines

  1. /* Next available MSG number is 65 */
  2.  
  3. /*************************************************************************
  4. Name: offsol.c.  AME2_APLIB_SAMP_offsol.c
  5.  
  6. Description: AME/API sample program for region-based offsetting 
  7.  
  8. Author: Japan/Eagle Group
  9.         Autodesk, Inc.
  10.  
  11.  
  12.  
  13.  
  14. Copyright (C) 1992 by Autodesk, Inc.
  15. /*************************************************************************
  16. *  
  17. *    Permission to use, copy, modify, and distribute this software
  18. *    for any purpose and without fee is hereby granted, provided
  19. *    that the above copyright notice appears in all copies and that
  20. *    both that copyright notice and this permission notice appear in
  21. *    all supporting documentation.
  22. *    THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
  23. *    WARRANTY.  ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR
  24. *    PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
  25. *
  26. *                                                                        *
  27. *    Offsetting is the heart of machining/milling. The OFFSET command in *
  28. *    AutoCAD is unpredictable for regions with concavities and for large * 
  29. *    shrink distances This program allows the user to take advantage of  *
  30. *    the region modeler in AME2.0 to solve these problems and offer a    *
  31. *    better machining environment. This sample program only deals with   *
  32. *    polylines with out arcs but can be extended to address them. Since  *
  33. *    the objective of the routine is also to demonstrate the power of    *
  34. *    region modeler the intermediate region operations are left visible. *
  35. *    If desired, the region processes can be made transparent by a ghost *
  36. *    script.                                 *
  37. *                                      *
  38. *    Two commands "SOLOFF" and "SOLMAC"                     *
  39. *    are available in this implementation.                               *
  40. *                                                                        *
  41. *    The command syntax for "SOLOFF" is shown as follows:                *
  42. *                                                                        *
  43. *          Command: soloff                                               *
  44. *          Offset distance <0.1000000>: Enter a value or RETURN          *
  45. *          Shrink/Expand<s>: Enter 'e' for expand or RETURN foe shrink   *
  46. *          Select a closed polyline of lines (only) to offset:           * 
  47. *            Pick a non self-intersecting closed polyline consisting     *
  48. *                                                      of lines only     *
  49. *                                                                        *
  50. *    The selected entity has to be closed polyline. This command         * 
  51. *    disallows large shrink distances resulting in NULL objects.         *
  52. *                                                                        *
  53. *    OFFSOL command lets you offset a closed polyline with a given       * 
  54. *    distance. This command is mainly implemented for NC tool path       * 
  55. *    generation. Shrinking is the main consideration but expansion also  * 
  56. *    should work. The polyline is decomposed into a region CSG (with     * 
  57. *    convex hulls) as primitives. Each primitive is then offset and      * 
  58. *    combined through the tree to give consistent                 * 
  59. *    offsetting. The resulting region is converted to a polyline and     * 
  60. *    displayed. The software can be modified for specific requirements   * 
  61. *    and other applications.                         *
  62. *                                                                        *
  63. *    The command syntax for "SOLMAC" is shown as follows:                *
  64. *                                                                        *
  65. *          Command: solmac                                               *
  66. *          Enter the diameter of tool <0.100000>: Enter a value          *
  67. *          Select a closed polyline of lines (only) to offset:           * 
  68. *            Pick a non self-intersecting closed polyline consisting     *
  69. *                                                      of lines only     *
  70. *                                                                        *
  71. *    For very large tool diameters which need only one pass to machine   * 
  72. *    the polyline, a message appears and no offsets are generated.       *
  73. *                                                                        *
  74. *    SOLMAC command lets you create tool paths recursively till the      * 
  75. *    whole 2d - solid is milled off. It uses the above offsol command    * 
  76. *    recursively with the shrink option and offset distance equal to the * 
  77. *    tool diameter. A circle representing the tool is created and        * 
  78. *    traversed over the current polyline. The final offset distance is   * 
  79. *    reduced, if needed, from tool diameter to tool radius to accomplish *
  80. *    complete machining. If multiple loops result in the offsetting,     * 
  81. *    each loop is machined fully before the next loop is machined, for   * 
  82. *    maximum efficiency.                                                 *
  83. *                                                                        *
  84. *    The offset distance, tool diameter and the shrink or expansion     * 
  85. *    option mentioned for the above commands use the previous selection  * 
  86. *    values as current defaualt values.                                  * 
  87. *    Since the above commands use AutoCAD's offset command on convex     *
  88. *    hulls and entity selection through points the program centers the   *
  89. *    object and sets proper zoom and limits. The current view and confi- *
  90. *    guration is saved   and restored at the end of offsetting.          *
  91. *                                                                        *
  92. *    It must be kept in mind that the program gives unexpected results   *
  93. *    for such cases when the entity is not parallel to UCS.              * 
  94. *                                                                        *
  95. *    You may want to take a look at code around *FHACK* for more         *
  96. *    robustness.                                                         *
  97. *                                                                        *
  98. *                                                                        *
  99. **************************************************************************
  100.  
  101. Modification history:
  102.     Refer to the RCS section at the end of this file.
  103.  
  104. Bugs and restrictions on use:
  105.  
  106. Notes:
  107.  
  108. **************************************************************************/
  109.  
  110.  
  111. /*************************************************************************/
  112. /* Includes */
  113. /*************************************************************************/
  114.  
  115. #include <stdio.h>
  116. #include <string.h>
  117. #include <math.h>
  118. #include <adslib.h>
  119. #include <aplib.h>
  120.  
  121. /*************************************************************************/
  122. /* Defines */
  123. /*************************************************************************/
  124.  
  125. #define PI 3.1415926
  126. #define ASPI 3.14159265358979323846
  127. #define AS2PI 2.0*3.14159265358979323846
  128. #define ASPI_2 3.14159265358979323846/2.0
  129. #define OP_DIF -1
  130. #define OP_UN 1
  131. #define ueps1 0.0008 /* different epsilons used throught the code */
  132. #define nueps 1.3258789e-4
  133. #define TRUNC_EPS 0.000001
  134. #define EXT_EPS 0.00001
  135. #define f_abs(a) ((a) >= 0.0 ? (a) : -(a))
  136. #define c_reqa(x, y, z) (f_abs(*(x) - *(y)) < *(z))
  137. #define NELEM(a)        (sizeof a  / sizeof a[0])
  138. #define Cpoint(ptd, pts)  ptd[X] = pts[X]; ptd[Y] = pts[Y]; ptd[Z] = pts[Z]
  139.  
  140. #ifndef ELEMENTS
  141. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  142. #endif
  143.  
  144. /*************************************************************************/
  145. /* Typedefs */
  146. /*************************************************************************/
  147.  
  148. typedef struct plypts           /* polyline points */
  149. {
  150.         double x;               /* x - cord */
  151.         double y;               /* y - cord */
  152.         double bg;              /* bulge for arc */
  153. } Ppts, *ppts;
  154.  
  155. typedef struct vertex           /* vertex info. */
  156. {
  157.     double  x;                  /* x-cord */
  158.     double  y;                  /* y-cord */
  159.     double bg;                  /* bulge for arc */
  160.     short flag;         /* additional info about line from this vtx to next */
  161.     struct vertex  *nxt;        /* ptr to next vertex */
  162. }                       Vertex, *Vptr;/* vertex pointer */
  163.  
  164. typedef struct
  165. {
  166.         double x;
  167.         double y;
  168. } Point;
  169.  
  170. typedef struct trenod           /* treenode info. */
  171. {
  172.     short     op;                       /* operation code (-1=>dif, 1=>un) */
  173.     struct trenod  *rht;        /* ptr to right son */
  174.     struct trenod  *lft;        /* ptr to left  son */
  175.                     Vptr vtx;   /* ptr to vertex data */
  176.     long   idx;         /* index to be transferred */
  177.     long  id;           /* solid id */
  178. }   Trenod, *Tnptr;/* treenod pointer */
  179.  
  180. typedef struct store            /* to store processing info. */
  181. {
  182.     Trenod * ptr;               /* Treenod pointer to be processed */
  183.     Trenod * pid;               /* Usually left son */
  184.     struct store   *nxt;        /* ptr to next stored data */
  185. }   Store, *Stptr;/* storage ptr */
  186.  
  187. typedef struct line
  188. {
  189.         double x1, y1;         /* first point */
  190.         double x2, y2;         /* second point */
  191.         double a, b, c;        /* coefficients of equation */
  192.         double len;             /* length */
  193.         struct line *li_next;
  194.         struct line *li_prev;
  195. } Line;
  196.  
  197. typedef struct ents
  198. {
  199.     ads_name ename;        /* entity name */
  200.     struct ents *nxt;      /* next one */ 
  201. } Ents, *Entsp;
  202.  
  203. /*************************************************************************/
  204. /* Global variables */
  205. /*************************************************************************/
  206.  
  207. char name[32];                        /* current layer name */
  208. ads_point vec;                  /* 210 vec for ECS */
  209. ads_real off_dist = 0.1;          /* default offset distance */
  210. short is_exp = -1;              /* default shrink option */ 
  211. ads_name tool_name;              /* entity name for tool */
  212. struct resbuf *tool_buf;          /* resbuf for tool ent. */
  213. int is_tool = 0;
  214. static ads_real cen[2], plim[2], fsp[2], snd[2]; /* XXXX */
  215. static Stptr sb, scur;                /* ptrs to base and current storage */
  216. static Tnptr root;                    /* ptr to root */
  217. static double z1,z2,theta;            /* bounding faces for ext. & rev. ang */
  218. static Vptr vi;                       /* ptr to initial vertex */
  219. static short dirn, i2, quat;
  220. long totpts;                          /* total number of points */
  221. static long glob;                    /* do boolean */
  222.  
  223. /* Function type declaration */
  224.  
  225. void off_sol();
  226. void mac_sol();
  227. short requal();
  228. long mknbl();
  229. /*
  230.  *  Define forward references for HighC compiler
  231.  */
  232. Tnptr treealloc();
  233. #if HIGHC386 || sun4 || __ZTC__
  234. void *malloc();
  235. #else
  236. char *malloc();
  237. #endif
  238. static int funcload();
  239. static  void print_new_command_set();
  240.  
  241. /* Command definition and dispatch table.  */
  242.  
  243. struct ads_comm {
  244.     char   *cmdname;
  245.     void   (*cmdfunc) ();
  246. };
  247.  
  248. struct ads_comm cmdtab[] = {
  249.         {/*MSG1*/"C:SOLMAC", mac_sol},
  250.         {/*MSG2*/"C:SOLOFF", off_sol},
  251.     };
  252.  
  253. /*************************************************************************/
  254. /* .doc main() */
  255. /*+
  256. -*/
  257. /*************************************************************************/
  258.  
  259. void
  260. /*FCN*/main(argc, argv)
  261.   int             argc;
  262.   char           *argv[];
  263. {
  264.     int             stat, cindex;
  265.     short           scode = 1;
  266.  
  267.     ads_init(argc, argv);
  268.  
  269.     while (TRUE) {
  270.         if ((stat = ads_link(scode)) < 0) {
  271.             printf(/*MSG3*/"OFFSOL: bad status from ads_link() = %d\n",stat);
  272.             fflush(stdout);
  273.             ads_exit(1);
  274.         }
  275.         scode = -RSRSLT;
  276.  
  277.         switch (stat) {
  278.         case RQXLOAD:                 /* Load & register functions */
  279.             scode = -(funcload() ? RSRSLT : RSERR);
  280.             scode = -RSRSLT;
  281.             print_new_command_set();
  282.             break;
  283.  
  284.         case RQXUNLD:                 /* Unloading */
  285.             scode = (funcunload ()  ? RSRSLT : RSERR);
  286.             ads_printf (/*MSG4*/"Unloading: ");
  287.             break;
  288.  
  289.         case RQSUBR:                  /* Evaluate external lisp function */
  290.             cindex = ads_getfuncode();
  291.             (*cmdtab[cindex].cmdfunc) ();
  292.             break;
  293.  
  294.         default:
  295.             break;
  296.  
  297.         }
  298.     }
  299. }
  300.  
  301. /*************************************************************************/
  302. /* .doc funcload() */
  303. /*+
  304.    Load external functions into AutoCAD system
  305. -*/
  306. /*************************************************************************/
  307.  
  308. static ap_Bool
  309. /*FCN*/funcload()
  310.  
  311. {
  312.     int             i;
  313.  
  314.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  315.         if(! ads_defun (cmdtab[i].cmdname , i))
  316.             return  RTERROR;
  317.     }
  318.     return RTNORM;
  319. }
  320.  
  321. /*************************************************************************/
  322. /* .doc funcunload() */
  323. /*+
  324.    Unload registered functions from AutoCAD system
  325. -*/
  326. /*************************************************************************/
  327.  
  328. static ap_Bool
  329. /*FCN*/funcunload()
  330.  
  331. {
  332.     int             i;
  333.  
  334.     for (i = 0; i < ELEMENTS(cmdtab); i++)
  335.         ads_undef(cmdtab[i].cmdname, i);
  336.  
  337.     return RTNORM;
  338. }                                     /* funcunload */
  339.  
  340. /*************************************************************************/
  341. /* .doc print_new_command_set() */
  342. /*+
  343. -*/
  344. /*************************************************************************/
  345.  
  346. static  void
  347. /*FCN*/print_new_command_set()
  348. {
  349.     ads_printf(/*MSG5*/"\nNew loaded commands: SOLOFF, SOLMAC\n");
  350. }
  351.  
  352. /*  
  353.  *    Print out the entity data similar to dxf format
  354.  */
  355.  
  356. void off_sol()
  357. {
  358.     ads_name e1;
  359.     ads_point pt;
  360.     char cmd[8], prompt[64];
  361.     int result;
  362.     Entsp done, do_proc();
  363.     
  364.  
  365.     if (ap_init() != AP_NORMAL)
  366.         return;
  367.     is_tool = 0;
  368.     sprintf (prompt, /*MSG6*/"Offset distance <%f>:", off_dist);
  369.     ads_initget (2+4, NULL); /* allow only positive values */
  370.     if (ads_getdist (NULL, prompt, &off_dist) == RTCAN)
  371.         return;
  372.     if (is_exp == 1)
  373.         sprintf (prompt, /*MSG7*/"Shrink/Expand<e>:");
  374.     else
  375.         sprintf (prompt, /*MSG8*/"Shrink/Expand<s>:");
  376.     ads_initget(0, /*MSG9*/"Shrink Expand");
  377.     result = ads_getkword(prompt, cmd);
  378.     if (result < 0)
  379.         return;
  380.     if (strcmp(cmd, /*MSG10*/"Shrink") == 0)  
  381.         is_exp = -1;
  382.     if (strcmp(cmd, /*MSG11*/"Expand") == 0)  
  383.         is_exp = 1;
  384.     /* default is_exp = 1 */
  385.     ads_entsel(/*MSG12*/"Select closed polyline of lines (only) to offset:", e1, pt);
  386.     /*
  387.     ads_entsel("Select closed polyline to offset:", e1, pt);
  388.     */
  389.     done = do_proc(e1);
  390.     return;
  391. }
  392.  
  393. /*
  394.  *  Search a result buffer chain and return an item
  395.  *  associated with the specified group code.
  396.  */
  397.  
  398. struct resbuf
  399. /*FCN*/*assoc_rb(rb, grp)
  400.   struct resbuf *rb;
  401.   int grp;
  402. {
  403.     while ((rb != NULL) && (rb->restype != grp))
  404.         rb = rb->rbnext;
  405.     return rb;
  406. }
  407.  
  408. off_err()
  409. {
  410.     ;
  411.     /*
  412.     ads_printf ("Error in off_setting\n");
  413.     */
  414. }
  415.  
  416. /* prepare data for main offsetting routine */
  417.  
  418. Entsp 
  419. do_proc(e1)
  420. ads_name e1;
  421. {
  422.      struct resbuf *ebuf, *eb, *eb2, *assoc_rb(), cb, rb, lb1, lb2;
  423.         ads_name  e2;
  424.         ads_point pt;
  425.         char cmd[8], prompt[64];
  426.         int result;
  427.         int cntr = 0, numvert = 0; /* count the number of verts */
  428.         int cmdecho;
  429.     Entsp  done, e_proces();
  430.         Ppts *ed;
  431.     ap_Objid obj;
  432.     Entsp cde, obj2ply();
  433.     ads_point lmn, lmx, p, pl;
  434.     short closed = FALSE, frst = TRUE;
  435.     ads_real eps = (ads_real)TRUNC_EPS;
  436.  
  437.     p[2] = lmn[2] = lmx[2] = 0.0;
  438.     ebuf = ads_entget(e1);
  439.     if (!ebuf)
  440.         return (Entsp)NULL;
  441.     eb = assoc_rb(ebuf, 0);
  442.     if (strcmp(eb->resval.rstring, /*MSG0*/"POLYLINE") != 0)
  443.     {
  444.         ads_printf(/*MSG13*/"The entity has to be a polyline\n");
  445.         return (Entsp)NULL;
  446.     }
  447.     eb = assoc_rb(eb, 8);  /* get the layer name */
  448.     sprintf (name, eb->resval.rstring);
  449.     eb = assoc_rb(eb, 210); /* get the ECS vec */
  450.     Cpoint (vec, eb->resval.rpoint);
  451.     eb = assoc_rb(ebuf, 70);
  452.     if (eb->resval.rint & 8)
  453.     {
  454.         ads_printf
  455.         ("\nNot a polyline. 3D polyline can not be offset\n");
  456.         return (Entsp)NULL;
  457.     }
  458.     else if (eb->resval.rint & 16)
  459.     {
  460.         ads_printf
  461.         ("\nNot a polyline. 3D mesh can not be offset\n");
  462.         return (Entsp)NULL;
  463.     }
  464.     else if (eb->resval.rint > 1)
  465.     {
  466.         ads_printf
  467.         (/*MSG14*/"\nNot a closed polyline of lines. Entity can not be offset\n");
  468.         return (Entsp)NULL;
  469.     }
  470.     else if (eb->resval.rint == 1)
  471.         closed = TRUE;
  472.     eb = assoc_rb(ebuf, 75);
  473.     if (eb && eb->resval.rint > 0)
  474.     {
  475.         ads_printf(/*MSG15*/"Not a polyline of lines. Entity can not be offset\n");
  476.         return (Entsp)NULL;
  477.     }
  478.     ads_relrb(ebuf);
  479.     if (is_tool) /* machine outer boundary */
  480.     {
  481.         if (ap_solidify(e1, &obj) != AP_NORMAL)
  482.             off_err();
  483.         cde = obj2ply(e1, obj, FALSE);
  484.         dump_ent(cde);
  485.     }
  486.  
  487.     ads_getvar(/*MSG0*/"CMDECHO", &cb);
  488.     cmdecho = cb.resval.rint;
  489.     cb.resval.rint = 0; /* turn the commands off */
  490.     ads_setvar(/*MSG0*/"CMDECHO", &cb);
  491.     ads_command (RTSTR, /*MSG16*/"_.VIEW", RTSTR, /*MSG17*/"_S", RTSTR,
  492.     /*MSG18*/"off_set", NULL);
  493.     ads_command (RTSTR, /*MSG20*/"_.PLAN", RTSTR, "", NULL);
  494.  
  495.     e2[0] = e1[0]; e2[1] = e1[1];
  496.     while (ads_entnext(e2, e2) == RTNORM)
  497.     {
  498.         ebuf = ads_entget(e2);
  499.         eb = assoc_rb(ebuf, 0);
  500.         if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
  501.         {
  502.             cntr++;
  503.             eb = assoc_rb(eb, 42);
  504.             if (eb && eb->resval.rreal)  /* arc or circle */
  505.             {
  506.                 ads_printf
  507.                 (/*MSG20*/"\nArcs and circles are not supported in this version\n");
  508.                 return (Entsp)NULL;
  509.             }
  510.             pl[0] = eb->resval.rpoint[X];
  511.             pl[1] = eb->resval.rpoint[Y];
  512.             if (!closed && frst)
  513.             {
  514.                 p[0] = pl[0];
  515.                 p[1] = pl[1];
  516.                 frst = FALSE;
  517.             }    
  518.         }
  519.         else /* SEQEND */
  520.         {
  521.             ads_relrb(ebuf);
  522.             if (!closed)
  523.             {
  524.                 if ((c_reqa(&pl[0], &p[0], &eps)) && (c_reqa(&pl[1], &p[1], &eps)))     
  525.                 {
  526.                     closed = 2;    
  527.                     cntr--;
  528.                 }
  529.                 else
  530.                 {
  531.                     ads_printf
  532.                     (/*MSG14*/"\nNot a closed polyline. Entity can not be offset\n");
  533.                     return (Entsp)NULL;
  534.                 }
  535.                 
  536.             }
  537.             break;
  538.         }
  539.     } 
  540.  
  541.     if((ed = (Ppts *)malloc(sizeof(struct plypts) * cntr)) == NULL)
  542.                 off_err();
  543.     
  544.     frst = TRUE; numvert = cntr;
  545.     cntr = 0;
  546.     e2[0] = e1[0]; e2[1] = e1[1];
  547.     while (ads_entnext(e2, e2) == RTNORM)
  548.     {
  549.         ebuf = ads_entget(e2);
  550.         eb = assoc_rb(ebuf, 0);
  551.         if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
  552.         {
  553.             if (closed == 2 && cntr == numvert) /* last vert is a repeat */
  554.             {
  555.                 closed = TRUE;
  556.                 continue;
  557.             }
  558.             eb = assoc_rb(eb, 10);
  559.             trans_euwpt(eb->resval.rpoint, 1, TRUE);
  560.             ed[cntr].x = p[0] = eb->resval.rpoint[X];
  561.             ed[cntr].y = p[1] = eb->resval.rpoint[Y];
  562.             if (frst)
  563.             {
  564.                 frst = FALSE;
  565.                 lmn[X] = lmx[X] = p[X]; 
  566.                 lmn[Y] = lmx[Y] = p[Y]; 
  567.             }
  568.             else
  569.             {
  570.                 if (p[X] < lmn[X]) 
  571.                         lmn[X] = p[X];
  572.                 if (p[X] > lmx[X])
  573.                         lmx[X] = p[X];
  574.                 if (p[Y] < lmn[Y]) 
  575.                         lmn[Y] = p[Y];
  576.                 if (p[Y] > lmx[Y]) 
  577.                         lmx[Y] = p[Y];
  578.             }
  579.             eb = assoc_rb(eb, 42);
  580.             ed[cntr].bg = eb->resval.rreal; 
  581.             cntr++;
  582.             ads_relrb(ebuf);
  583.             
  584.         }
  585.         else
  586.         {
  587.             ads_relrb(ebuf);
  588.             break;
  589.             }    
  590.     } 
  591.     /* let us zoom in on the entity and position at center */
  592.     ads_command(RTSTR, /*MSG21*/"_.zoom", RTSTR, /*MSG22*/"_w", RT3DPOINT, lmn,
  593.     RT3DPOINT, lmx, NULL);
  594.     ads_command(RTSTR, /*MSG23*/"_.zoom", RTSTR, /*MSG24*/"0.3x", NULL);
  595.  
  596.     /* get the limits and store */
  597.       if (ads_getvar(/*MSG0*/"LIMMIN", &lb1) < 0) 
  598.         off_err();
  599.       if (ads_getvar(/*MSG0*/"LIMMAX", &lb2) < 0)
  600.         off_err();
  601.  
  602.     /* get the view limits and set as new limits */
  603.       if (ads_getvar(/*MSG0*/"VSMIN", &rb) < 0) 
  604.         off_err();
  605.     ads_command (RTSTR, /*MSG25*/"_.LIMMIN", RT3DPOINT, rb.resval.rpoint, NULL);
  606.  
  607.       if (ads_getvar(/*MSG0*/"VSMAX", &rb) < 0) 
  608.         off_err();
  609.     ads_command (RTSTR, /*MSG26*/"_.LIMMAX", RT3DPOINT, rb.resval.rpoint, NULL);
  610.  
  611.     done = e_proces(e1, ed, cntr); /* process edges */
  612.     clean_up();           /* clean up the stuff */
  613.     free(ed);           /* free the array of points */
  614.     ads_command (RTSTR, /*MSG27*/"_.REGEN", NULL);
  615.     
  616.     cb.resval.rint = cmdecho; /* put back the original value */
  617.     ads_command (RTSTR, /*MSG28*/"_.LIMMIN", RT3DPOINT, lb1.resval.rpoint, NULL);
  618.     ads_command (RTSTR, /*MSG29*/"_.LIMMAX", RT3DPOINT, lb2.resval.rpoint, NULL);
  619.     ads_command (RTSTR, /*MSG30*/"_.ZOOM", RTSTR, /*MSG31*/"_E", NULL);
  620.     ads_command (RTSTR, /*MSG32*/"_.VIEW", RTSTR, /*MSG33*/"_R", RTSTR, 
  621.     /*MSG34*/"off_set", NULL);
  622.     ads_setvar(/*MSG0*/"CMDECHO", &cb);
  623.  
  624.     return (done);
  625. }
  626.  
  627. /* transform the point from one coord system to another */
  628. trans_euwpt (pt, idx, e2u)
  629. ads_point pt;
  630. int idx; 
  631. short e2u;
  632. {
  633.     ads_point result;
  634.     struct resbuf fromrb, torb;
  635.  
  636.     if (e2u) /* ECS to U/WCS */
  637.     {
  638.         fromrb.restype = RT3DPOINT;
  639.         Cpoint (fromrb.resval.rpoint, vec);
  640.         torb.restype = RTSHORT;
  641.         torb.resval.rint = idx; /* U/WCS */
  642.     }    
  643.     else /* U/WCS to ECS */
  644.     {
  645.         fromrb.restype = RTSHORT;
  646.         fromrb.resval.rint = (short)idx; /* U/WCS */
  647.         torb.restype = RT3DPOINT;
  648.         Cpoint (torb.resval.rpoint, vec);
  649.     }
  650.     if ((ads_trans (pt, &fromrb, &torb, 0, result)) != RTNORM)
  651.         off_err();
  652.     Cpoint (pt, result);
  653. }
  654.  
  655. /*  
  656.  *    Machine solid along the offset distance
  657.  */
  658.  
  659. void mac_sol()
  660. {
  661.     ads_name e1, e2;
  662.     ads_point pt;
  663.     char cmd[8], prompt[64];
  664.     Entsp ent, do_proc();
  665.     int result, cmdecho;
  666.     ads_real toff;
  667.     struct resbuf  cb;
  668.     
  669.  
  670.     if (ap_init() != AP_NORMAL)
  671.         return;
  672.     is_tool = 1;
  673.     sprintf (prompt, /*MSG35*/"Enter  the diameter of tool <%f>:", off_dist);
  674.     ads_initget (2+4, NULL); /* allow only positive values */
  675.     if (ads_getdist (NULL, prompt, &off_dist) == RTCAN)
  676.         return;
  677.     /* We are always shrinking */
  678.     is_exp = -1;
  679.  
  680.     /*
  681.      * Suppress AutoCAD command echo 
  682.     */
  683.  
  684.     ads_getvar(/*MSG0*/"CMDECHO", &cb);
  685.     cmdecho = cb.resval.rint;
  686.     cb.resval.rint = 0; /* turn the commands off */
  687.     ads_setvar(/*MSG0*/"CMDECHO", &cb);
  688.  
  689.     ads_command(RTSTR, /*MSG36*/"_.CIRCLE", RTSTR, "0, 0", RTREAL, off_dist/2.0, NULL);
  690.  
  691.     /*
  692.      * Resume AutoCAD command echo 
  693.     */
  694.  
  695.     cb.resval.rint = cmdecho;
  696.     ads_setvar(/*MSG0*/"CMDECHO", &cb);
  697.  
  698.     ads_entlast(tool_name);
  699.     tool_buf = ads_entget(tool_name);
  700.     ads_entsel(/*MSG37*/"Select closed polyline of lines (only) to machine:", e1, pt);
  701.     ent = do_proc(e1);
  702.     if (!ent)
  703.         return;
  704.     toff = off_dist;
  705.     is_tool = 2;
  706.     
  707.     sprintf(prompt, /*MSG38*/"\nContinue machining <Yes>/No: ");
  708.     /* create the offsets till we are done */
  709.     do_end(ent, toff);
  710.     off_dist = toff;
  711.     ads_relrb(tool_buf);
  712.     return;
  713. }
  714.   
  715. /* recursive routine to machine till end */
  716.  
  717. do_end(ent, toff)
  718. Entsp ent;
  719. ads_real toff;
  720. {
  721.     Entsp tmp, t2, do_proc();
  722.  
  723.     for (tmp = ent; tmp != (Entsp)NULL; tmp = tmp->nxt)
  724.     {
  725.         ent = do_proc(tmp->ename);
  726.         if (!ent)
  727.         {
  728.             is_tool = 2;
  729.             off_dist = toff;
  730.             if (!tmp->nxt)
  731.                 break;
  732.         }
  733.         else
  734.             do_end(ent, toff);
  735.     }
  736.     dump_ent(ent);
  737. }
  738.  
  739. /* free up ent */
  740.  
  741. dump_ent(ent)
  742. Entsp ent;
  743. {
  744.     Entsp tmp, t2;
  745.  
  746.     tmp = ent;           /* Free */
  747.     while (tmp != NULL)
  748.     {
  749.         t2 = tmp->nxt;
  750.         free (tmp);
  751.         tmp = t2;
  752.     }
  753. }
  754.  
  755. /*  main offsetting control routine */
  756.  
  757. Entsp
  758. e_proces(enm, edata, n)
  759. ads_name enm;
  760. Ppts edata[];
  761. short n;
  762. {
  763.     char *yy;
  764.     static char *fname = /*MSG39*/"e_process";
  765.     Entsp obj2ply();
  766.     short frmary(), treeprint();
  767.  
  768.     totpts = n;
  769.     n = n - 1;
  770.     if (frmary(edata, (long)n))
  771.         return (Entsp)NULL; /* done */
  772.     root = (Tnptr)NULL;
  773.     if (vi)
  774.     {
  775.         inidata();        /* initialization */
  776.         traverse();        /* traverse and process stored data */
  777.         if (treeprint(root, (int)-1)) /* prepare a file */
  778.             return (Entsp)NULL; /* done */
  779.         glob = root->id;
  780.     }
  781.     return (obj2ply(enm, glob, TRUE));
  782. }
  783.  
  784. /* clean up and free the data structures */
  785.  
  786. clean_up()
  787. {
  788.     Stptr stmp,stmp1;
  789.     
  790.     treedump(root);
  791.     stmp = sb;
  792.     while(stmp)
  793.     {
  794.         stmp1 = stmp->nxt;
  795.         free(stmp);
  796.         stmp = stmp1;
  797.     }
  798. }
  799.  
  800. treedump(pt)
  801. Tnptr pt;
  802. {
  803.     Vptr tmp1,tmp;
  804.     
  805.     if(pt)
  806.     {
  807.         if(pt->rht)
  808.             treedump(pt->rht);
  809.         if(pt->lft)
  810.             treedump(pt->lft);
  811.         tmp = pt->vtx;
  812.         while(tmp)
  813.         {
  814.             tmp1 = tmp;
  815.             tmp = tmp->nxt;
  816.             free(tmp1);
  817.             tmp1 = NULL;
  818.         }
  819.         free(pt);
  820.         pt = NULL;
  821.     }
  822. }
  823.  
  824. /* routine to determine direction clw or cclw and get the left bottom point */
  825.  
  826. static void
  827. detdir(xx, num, trk)
  828. Ppts xx[];
  829. long num, *trk;
  830. {
  831. #ifdef __WATCOMC__
  832.     double minx, miny, leastx, leasty, maxx, maxy;
  833. #else
  834.     double minx, miny, leastx, leasty, maxx, maxy, cos(), sin(), sqrt();
  835. #endif /* WATCOMC */
  836.     double x, y, a1, b1, a2, b2, eps, x1, y1, x2, y2, val, zero, smalleps;
  837.     float maxdim;
  838.     long prev, nxt, i;
  839.     short arc;
  840.     
  841.     x = xx[0].x;
  842.     y = xx[0].y;
  843.     minx = x;
  844.     miny = y;
  845.     maxx = leastx = x;
  846.     maxy = leasty = y;
  847.     *trk = 0;
  848.     dirn = -1;
  849.     zero = 0.0;
  850.     eps = nueps;
  851.  
  852.     for(i = 1; i <= num; i++)
  853.     {
  854.         x = xx[i].x;
  855.         y = xx[i].y;
  856.         if(x < minx && !requal(minx, x, TRUNC_EPS))
  857.         {
  858.             minx = x;
  859.             miny = y;
  860.             *trk = i;
  861.         }
  862.         else 
  863.         {
  864.             if (requal(minx, x, TRUNC_EPS))
  865.             {
  866.                 if(y < miny)
  867.                 {
  868.                     miny = y;
  869.                     *trk = i;
  870.                 }
  871.             }
  872.         }
  873.         if(x < leastx)
  874.             leastx = x;
  875.         if(y <leasty)
  876.             leasty = y;
  877.         if(x > maxx)
  878.             maxx = x;
  879.         if(y > maxy)
  880.             maxy = y;
  881.     }
  882.     if(*trk == num)
  883.         nxt =  0;
  884.     else
  885.         nxt = *trk + 1;
  886.     if(*trk == 0)
  887.         prev = num;
  888.     else 
  889.         prev = *trk - 1;
  890.     x1 = xx[prev].x;
  891.     y1 = xx[prev].y;
  892.     x2 = xx[nxt].x;
  893.     y2 = xx[nxt].y;
  894.     a1 = x2 - minx;
  895.     b1 = y2 - miny;
  896.     a2 = minx - x1;
  897.     b2 = miny - y1;
  898.     val = a1 * b2 - b1 * a2;
  899.     smalleps = eps * sqrt(a1 * a1 + b1 * b1);
  900.     if(c_reqa(&val, &zero, &smalleps))
  901.         ;
  902.     else
  903.         if(val > 0.0)
  904.             dirn = 1; /* clw */
  905. }
  906.  
  907. /* set up the data structures */
  908.  
  909. short
  910. frmary(xx, num)
  911. Ppts xx[];
  912. long num;
  913. {
  914.     long i;
  915.     Vptr vb, vutmp, tb, tmp;
  916.     long trk;
  917.     double  x, y;
  918.     
  919.     detdir(xx, num, &trk);
  920.     tb = NULL;
  921.     vb  = NULL;
  922.     root = NULL;
  923.     sb = NULL;
  924.     i = trk;
  925.     for(i = trk; i <= num; i++)
  926.     {
  927.         x = xx[i].x;
  928.         y = xx[i].y;
  929.         if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
  930.         {
  931.             off_err();
  932.             return TRUE;
  933.         }
  934.         vi->x = x;
  935.         vi->y = y;
  936.         vi->flag = (short)i;
  937.         vi->bg = xx[i].bg;
  938.         vi -> nxt = vb;
  939.         vb = vi;
  940.     }
  941.     if(trk != 0)
  942.     {
  943.         for(i = 0; i <= trk - 1; i++)
  944.         {
  945.             x = xx[i].x;
  946.             y = xx[i].y;
  947.             if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
  948.             {
  949.                 off_err();
  950.                 return TRUE;
  951.             }
  952.             vi->x = x;
  953.             vi->y = y;
  954.             vi->flag = (short)i;
  955.             vi -> nxt = vb;
  956.             vb = vi;
  957.         }  /* if */
  958.     } /* for */
  959.     x = xx[trk].x;
  960.     y = xx[trk].y;
  961.     if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
  962.     {
  963.         off_err();
  964.         return TRUE;
  965.     }
  966.     vi->x = x;
  967.     vi->y = y;
  968.     vi->flag = (short)trk;
  969.     vi->nxt = vb;
  970.     vb = vi;
  971.     /* this is the time to eliminate any introduced co-linear pts. 
  972.         and avoid redundancies */
  973.     if(vi->nxt->nxt->nxt == NULL)
  974.         vi = NULL;
  975.     else
  976.     {
  977.         vutmp = vi;
  978.         rmcolin(&vutmp);
  979.         vi = vutmp;
  980.         vb = vi;
  981.         if(dirn == 1) /* user draws clw. but pts stored cclw. rev the stuff */
  982.         {
  983.             tmp = vb;
  984.             while(tmp)
  985.             {
  986.                 vi = (Vptr)malloc(sizeof(Vertex));
  987.                 if (vi == (Vptr)NULL)
  988.                 {
  989.                     off_err();
  990.                     return TRUE;
  991.                 }
  992.                 vi->x = tmp->x;
  993.                 vi->y = tmp->y;
  994.                 vi->flag = tmp->flag;
  995.                 vi->nxt = tb;
  996.                 tb = vi;
  997.                 tmp = tmp->nxt;
  998.             }
  999.             vdump(vb);
  1000.         }   /* if dirn */
  1001.         tmp = vi;
  1002.         /*
  1003.             while(tmp)
  1004.             {
  1005.                 printf("vi x y %f %f\n", tmp->x, tmp->y); 
  1006.                 tmp = tmp->nxt;
  1007.             } 
  1008.         */
  1009.     }
  1010.     return FALSE;
  1011. }
  1012.  
  1013. /* remove colinear points */
  1014.  
  1015. rmcolin(curpt)
  1016. Vptr *curpt;
  1017. {
  1018.     Vptr sto, ntmp, tmp;
  1019.     short cur_code, loop, mcode;
  1020.     double  eps, x, y, cur_m, cur_c, m, c, x_dif, y_dif;
  1021.     
  1022.     eps = nueps;
  1023.     tmp = *curpt;
  1024.     if(!tmp)
  1025.         return;
  1026.     if(tmp->nxt)
  1027.     {
  1028.         y_dif = tmp->nxt->y - tmp->y;
  1029.         x_dif = tmp->nxt->x - tmp->x;
  1030.         if(f_abs(x_dif) < ueps1)
  1031.             cur_code = 1;
  1032.         else
  1033.         {
  1034.             cur_code = 0;
  1035.             cur_m = y_dif / x_dif;
  1036.             cur_c = tmp->y - cur_m * tmp->x;
  1037.         }
  1038.     }
  1039.     while(tmp->nxt && tmp->nxt->nxt)
  1040.     {
  1041.         do
  1042.         {
  1043.             loop = 0;
  1044.             y_dif = tmp->nxt->nxt->y - tmp->nxt->y;
  1045.             x_dif = tmp->nxt->nxt->x - tmp->nxt->x;
  1046.             if(f_abs(x_dif) < ueps1)
  1047.                 mcode = 1;
  1048.             else 
  1049.             {
  1050.                 mcode = 0;
  1051.                 m = y_dif / x_dif;
  1052.                 c = tmp->nxt->y - m * tmp->nxt->x;
  1053.             }
  1054.             if(cur_code == 1 && mcode == 1)
  1055.             {
  1056.                 sto = tmp->nxt;
  1057.                 tmp->nxt = sto->nxt;
  1058.                 free(sto);
  1059.                 sto = NULL;
  1060.                 loop = 1;
  1061.             }
  1062.             else 
  1063.             {
  1064.                 if(cur_code == 0 && mcode == 0)
  1065.                 {
  1066.                     if(c_reqa(&cur_c, &c, &eps) && c_reqa(&cur_m, &m, &eps))
  1067.                     {
  1068.                         sto = tmp->nxt;
  1069.                         tmp->nxt = sto->nxt;
  1070.                         free(sto);
  1071.                         sto = NULL;
  1072.                         loop = 1;
  1073.                     }
  1074.                 }
  1075.             }
  1076.         } 
  1077.         while(loop == 1 && tmp->nxt->nxt);
  1078.         cur_code = mcode;
  1079.         cur_m = m;
  1080.         cur_c = c;
  1081.         tmp = tmp->nxt;
  1082.     }  /* while ends */
  1083.     /* we need to perform one last step to homogenize the data 
  1084.         namely check the last two points with the last but one point */
  1085.     tmp = *curpt;
  1086.     if(tmp->nxt)
  1087.     {
  1088.         while(tmp->nxt->nxt)
  1089.             tmp = tmp->nxt;
  1090.         y_dif = tmp->nxt->y - tmp->y;
  1091.         x_dif = tmp->nxt->x - tmp->x;
  1092.         if(f_abs(x_dif) < ueps1)
  1093.             cur_code = 1;
  1094.         else
  1095.         {
  1096.             cur_code = 0;
  1097.             cur_m = y_dif / x_dif;
  1098.             cur_c = tmp->y - cur_m * tmp->x;
  1099.         }
  1100.         ntmp = *curpt;
  1101.         y_dif = ntmp->nxt->y - ntmp->y;
  1102.         x_dif = ntmp->nxt->x - ntmp->x;
  1103.         if(f_abs(x_dif) < ueps1)
  1104.             mcode = 1;
  1105.         else 
  1106.         {
  1107.             mcode = 0;
  1108.             m = y_dif / x_dif;
  1109.             c = ntmp->y - m * ntmp->x;
  1110.         }
  1111.         if(cur_code == 1 && mcode == 1)
  1112.         {
  1113.             sto = ntmp->nxt;
  1114.             free(*curpt);
  1115.             *curpt = sto;
  1116.             tmp->nxt->x = sto->x;
  1117.             tmp->nxt->y = sto->y;
  1118.         }
  1119.         else 
  1120.         {
  1121.             if(cur_code == 0 && mcode == 0)
  1122.             {
  1123.                 if(c_reqa(&cur_c, &c, &eps) && c_reqa(&cur_m, &m, &eps))
  1124.                 {
  1125.                     sto = ntmp->nxt;
  1126.                     free(*curpt);
  1127.                     *curpt = sto;
  1128.                     tmp->nxt->x = sto->x;
  1129.                     tmp->nxt->y = sto->y;
  1130.                 }
  1131.             }
  1132.         }
  1133.     } 
  1134. }
  1135.  
  1136. /* free the vertices (list) */
  1137.  
  1138. vdump(vb)
  1139. Vptr vb;
  1140. {
  1141.     if(vb)
  1142.     {
  1143.         vdump(vb->nxt);
  1144.         free(vb);
  1145.         vb = NULL;
  1146.     }
  1147. }
  1148.  
  1149.  
  1150. /* initialize the data */
  1151.  
  1152. inidata()
  1153. {
  1154.     i2 = 1;
  1155.     if ((root = treealloc(0l)) == NULL)
  1156.         return;
  1157.     if ((sb = (Stptr) malloc(sizeof (Store))) == (Stptr)NULL)
  1158.     {
  1159.         off_err();
  1160.         return;
  1161.     }
  1162.     sb -> ptr = root;
  1163.     sb -> pid = root;
  1164.     sb -> nxt = NULL;
  1165.     root -> vtx = vi;
  1166.     scur = sb;
  1167. }
  1168.  
  1169.  
  1170. /* 
  1171.  * u - given pt: v - nxt pt:w - index thru remaining pts. 
  1172.  * algorithm -> if cross product of vec[u, v] and vec [u, w] pts. out 
  1173.  * v forms a dip 
  1174.  */
  1175.  
  1176. Vptr lmost(u)    /* function which dets. the next leftmost value */
  1177. Vptr u;
  1178. {
  1179.     double  a1, a2, b1, b2;    /* i,j components of the vectors */
  1180.     Vptr v, w;
  1181.  
  1182.     if(u -> nxt -> nxt == 0)
  1183.         v = u -> nxt;
  1184.     else
  1185.     {
  1186.         v = u -> nxt;
  1187.         a1 = v -> x - u -> x;
  1188.         a2 = v -> y - u -> y;
  1189.         w = v -> nxt;
  1190.         do
  1191.         {
  1192.             b1 = w -> x - u -> x;
  1193.             b2 = w -> y - u -> y;
  1194.             if(a1 * b2 - a2 * b1 > 0.0)
  1195.             {
  1196.                 v = w;
  1197.                 a1 = b1;
  1198.                 a2 = b2;
  1199.             }
  1200.             w = w -> nxt;
  1201.         } 
  1202.         while(w);
  1203.     }
  1204.     return(v);
  1205. }
  1206.  
  1207. /* main recursive function which runs thru stored data */
  1208.  
  1209. traverse()
  1210. {
  1211.     Stptr r;
  1212.     
  1213.     do
  1214.     {
  1215.         r = sb;
  1216.         process(r);
  1217.         sb = sb -> nxt;
  1218.         free(r);
  1219.         r = NULL;
  1220.     } 
  1221.     while(sb);
  1222. }
  1223.  
  1224. Tnptr maketree(u, v, ptr, cod)            /* makes tree */
  1225. long cod;                    /* code for un or dif */
  1226. Tnptr ptr;                    /* present tree pointer */
  1227. Vptr u, v;                    /* ptrs to rel. vtx info. */
  1228. {
  1229.     Tnptr q, r;
  1230.     Stptr s;
  1231.     Vptr ncopy();
  1232.  
  1233.     if ((q = treealloc(cod)) == (Tnptr)NULL)
  1234.         return (Tnptr)NULL;
  1235.     if ((r = treealloc(cod)) == (Tnptr)NULL)
  1236.         return (Tnptr)NULL;
  1237.     if(scur -> ptr == root)
  1238.     {
  1239.         q -> lft = root;
  1240.         root = q;
  1241.         root -> idx = -1L; /* Sub */
  1242.         q -> lft -> lft = NULL;
  1243.         q -> lft -> rht = NULL;
  1244.         root->vtx = NULL;
  1245.     }
  1246.     else
  1247.     {
  1248.         if(cod == 1)
  1249.         {
  1250.             q -> lft = r;
  1251.             ptr -> rht = q;
  1252.             r -> vtx = ncopy(u, v);
  1253.             r -> op = 0L; /* prim */
  1254.             if ((s = (Stptr) malloc(sizeof (Store))) == (Stptr)NULL)
  1255.             {
  1256.                 off_err();
  1257.                 return (Tnptr)NULL;
  1258.             }
  1259.             s -> ptr = q;
  1260.             s -> pid = r;
  1261.             s -> nxt = NULL;
  1262.             scur -> nxt = s;
  1263.             scur = scur -> nxt;
  1264.         }
  1265.         else
  1266.         {
  1267.             q -> lft = ptr -> lft;
  1268.             ptr -> lft = q;
  1269.         }
  1270.     }
  1271.     return(q);
  1272. }
  1273.  
  1274. static Tnptr                 /* allocate the tree node */
  1275. treealloc(cod)
  1276. long cod;
  1277. {
  1278.     Tnptr t;
  1279.     static char *fname = /*MSG40*/"treealloc";
  1280.  
  1281.     if((t = (Tnptr)malloc(sizeof(Trenod))) == NULL)
  1282.     {
  1283.         off_err();
  1284.         return(NULL);
  1285.     }
  1286.     t -> vtx = NULL;
  1287.     t -> lft = NULL;
  1288.     t -> rht = NULL;
  1289.     t -> op = cod;
  1290.     t -> idx = -1l;
  1291.     t -> id = 0L;
  1292.     return(t);
  1293. }
  1294.  
  1295. process(cur) /* process current storage data ptr for convex hull */
  1296. Stptr cur;
  1297. {
  1298.     Tnptr r, t, maketree();
  1299.     Vptr u, v, w, p, lmost();    /* vertex data ptrs */
  1300.     double fact = 1.5;
  1301.     double pt1[2], pt2[2];
  1302.     short chk_mor(), l;
  1303.  
  1304.     if ((t = maketree(0L, 0L, cur -> ptr, -1L)) == (Tnptr)NULL)
  1305.         return;
  1306.     u = cur -> pid -> vtx;
  1307.     if(u)
  1308.     {
  1309.         while(u -> nxt)
  1310.         {
  1311.             v = lmost(u);
  1312.             if(u -> nxt != v)    /* concavity found */
  1313.             {
  1314.                 r = maketree(u, v, t, 1L);
  1315.                 /* fix u and v points */
  1316.                 w = v->nxt;
  1317.                 if (!w)
  1318.                     w = cur->pid->vtx->nxt;
  1319.                 p = w;
  1320.                 get_opnt(w->x, w->y, v->x, v->y, pt2, -fact);
  1321.                 if (u == cur->pid->vtx)
  1322.                     for (w = u; w->nxt->nxt != (Vptr)NULL; w = w->nxt);
  1323.                 else
  1324.                     for (w = cur->pid->vtx; w->nxt != u; w = w->nxt);
  1325.                 get_opnt(w->x, w->y, u->x, u->y, pt1, -fact);
  1326.                 l = chk_mor (p, v, w, u, pt1, pt2, fact);
  1327.                 v->x = pt2[0]; v->y = pt2[1];
  1328.                 if (!(v->nxt)) /* update 1st pt also */
  1329.                 {
  1330.                     cur->pid->vtx->x = v->x;
  1331.                     cur->pid->vtx->y = v->y;
  1332.                 }
  1333.                 u->x = pt1[0]; u->y = pt1[1];
  1334.                 if (u == cur->pid->vtx) /* update last pt also*/
  1335.                 {
  1336.                     w->nxt->x = u->x;
  1337.                     w->nxt->y = u->y;
  1338.                     if (l)
  1339.                     {
  1340.                         cur->pid->vtx = u->nxt;
  1341.                         free (u);
  1342.                         p = w->nxt;
  1343.                         w->nxt = (Vptr)NULL;
  1344.                         free (p);
  1345.                     }
  1346.                 }
  1347.                 else if (l)
  1348.                 {
  1349.                     w->nxt = v;
  1350.                     free (u);
  1351.                 }
  1352.                 if (r == (Tnptr)NULL)
  1353.                     return;
  1354.                 t = r;
  1355.             }
  1356.             u = v;
  1357.         } 
  1358.     }
  1359. }
  1360.  
  1361. /*
  1362.  * Find the intersection point. If this is at a smaller distance than
  1363.  * p1 or p2. Equate p1 and p2 to this point.
  1364.  */
  1365.  
  1366. short
  1367. chk_mor(p, v, w, u, pt1, pt2, fact)
  1368. Vptr p, v, w, u;
  1369. ads_real fact, pt1[2], pt2[2];
  1370. {
  1371.     Point p1, p2; 
  1372.     Line l1, l2;
  1373. #ifdef __WATCOMC__
  1374.     ads_real dist;
  1375. #else
  1376.     ads_real dist, sqrt();
  1377. #endif /* WATCOMC */
  1378.     short st_line();
  1379.     extern ads_real off_dist;
  1380.     
  1381.     p1.x = p->x; p1.y = p->y;
  1382.     p2.x = v->x; p2.y = v->y;
  1383.     if (!st_line(p1, p2, &l1))
  1384.         return 0;
  1385.     p1.x = w->x; p1.y = w->y;
  1386.     p2.x = u->x; p2.y = u->y;
  1387.     if (!st_line(p1, p2, &l2))
  1388.         return 0;
  1389.  
  1390.     if(requal(l1.a * l2.b, l1.b * l2.a, EXT_EPS))
  1391.         return 0; /* parallel lines */ 
  1392.     /* intersection point now */
  1393.         p1.x = (l2.c * l1.b - l1.c * l2.b) / (l1.a * l2.b - l2.a * l1.b) ;      
  1394.         p1.y = (l1.c * l2.a - l2.c * l1.a) / (l1.a * l2.b - l2.a * l1.b) ;   
  1395.     fact = off_dist*f_abs(fact);
  1396.     p2.x = p1.x - v->x; p2.y = p1.y - v->y;
  1397.     dist = sqrt((p2.x*p2.x) + (p2.y*p2.y));
  1398.     if (dist < fact)
  1399.     {
  1400.         pt1[0] = p1.x; pt1[1] = p1.y; 
  1401.         pt2[0] = p1.x; pt2[1] = p1.y; 
  1402.         return 1;
  1403.     } 
  1404.     p2.x = p1.x - u->x; p2.y = p1.y - u->y;
  1405.     dist = sqrt((p2.x*p2.x) + (p2.y*p2.y));
  1406.     if (dist < fact)
  1407.     {
  1408.         pt1[0] = p1.x; pt1[1] = p1.y; 
  1409.         pt2[0] = p1.x; pt2[1] = p1.y; 
  1410.         return 1;
  1411.     } 
  1412.     return 0;
  1413. }
  1414.  
  1415. Vptr ncopy(u, v)    /* copies the list from u, v in reverse order */
  1416. Vptr u, v;
  1417. {
  1418.     Vptr temp, t, tb;
  1419.     double pt1[2], pt2[2];
  1420.     double fact = 100.0; /* *FHACK* */
  1421.     
  1422.     /* 
  1423.          * Instead of this hard coded number it is probably better to tie
  1424.      * this to the largest dimension of the box. You have to tweak this
  1425.          * number for drawing with big dimensions.
  1426.      */
  1427.     tb = NULL;
  1428.     t = u;
  1429.     get_opnt(u->nxt->x, u->nxt->y, u->x, u->y, pt1, fact);
  1430.     do
  1431.     {
  1432.         if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
  1433.         {
  1434.             off_err();
  1435.             return (Vptr)NULL;
  1436.         }
  1437.         if (t != u)
  1438.         {
  1439.             temp -> x = t -> x;
  1440.             temp -> y = t -> y;
  1441.         }
  1442.         else
  1443.         {
  1444.             temp -> x = pt1[0];
  1445.             temp->  y = pt1[1]; 
  1446.         }
  1447.         temp -> nxt = tb;
  1448.         tb = temp;
  1449.         t = t -> nxt;
  1450.     } 
  1451.     while(t->nxt != v);
  1452.     if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
  1453.     {
  1454.         off_err();
  1455.         return (Vptr)NULL;
  1456.     }
  1457.     temp -> x = t -> x;
  1458.     temp -> y = t -> y;
  1459.     temp -> nxt = tb;
  1460.     tb = temp;
  1461.     get_opnt(t->x, t->y, v->x, v->y, pt2, fact);
  1462.     if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
  1463.     {
  1464.         off_err();
  1465.         return (Vptr)NULL;
  1466.     }
  1467.     temp -> x = pt2[0];
  1468.     temp -> y = pt2[1];
  1469.     temp -> nxt = tb;
  1470.     tb = temp;
  1471.     if ((t = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
  1472.     {
  1473.         off_err();
  1474.         return (Vptr)NULL;
  1475.     }
  1476.     t -> x = pt1[0];
  1477.     t -> y = pt1[1];
  1478.     t -> nxt = tb;
  1479.     tb = t;
  1480.     /* all the values are copied now : modify original list */
  1481.     temp = u -> nxt;
  1482.     u -> nxt = v;
  1483.     ndump(temp, v);
  1484.     return(t);
  1485. }
  1486.  
  1487. /* offset the lines by the given factor and compute the intersection pt. */
  1488.  
  1489. get_opnt(x1, y1, x2, y2, pt, fact)
  1490. double x1, y1, x2, y2;
  1491. double pt[2];
  1492. double fact;
  1493. {
  1494.     extern ads_real off_dist;
  1495. #ifdef __WATCOMC__
  1496.     double u[2], v[2], dist;
  1497. #else
  1498.     double u[2], v[2], dist, sqrt();
  1499. #endif /* WATCOMC */
  1500.     int i1 = 0, i2 = 1;
  1501.  
  1502.     fact *= off_dist;
  1503.     v[0] = x2 - x1;
  1504.     v[1] = y2 - y1;
  1505.     dist =  sqrt(v[0] * v[0] + v[1] * v[1]);
  1506.     v[0] /= dist; v[1] /= dist;
  1507.     if (fact > 0)
  1508.     {
  1509.         ;
  1510.     }
  1511.     else
  1512.         fact = f_abs(fact);
  1513.     pt[0] = x2 +  (v[0]*fact);
  1514.     pt[1] = y2 +  (v[1]*fact);
  1515. }
  1516.  
  1517. ndump(a, b)            /* free storage from a to b */
  1518. Vptr a, b;
  1519. {
  1520.     Vptr temp;
  1521.  
  1522.     while(a != b)
  1523.     {
  1524.         temp = a -> nxt;
  1525.         free(a);
  1526.         a = temp;
  1527.     }
  1528. }
  1529.  
  1530. short
  1531. treeprint(pt, val) /* go through the tree and prepare a CSG file */
  1532. Tnptr pt;
  1533. int val;
  1534. {
  1535.     short outprim();
  1536.  
  1537.     if(pt)
  1538.     {
  1539.         if(pt -> op != 0)
  1540.         {
  1541.             val *= pt->op;
  1542.             if(pt -> rht)
  1543.             {
  1544.                 if (treeprint(pt -> rht, val))
  1545.                     return TRUE;
  1546.                 treeprint(pt -> lft, val);
  1547.                 if(pt->op == -1) /* diff */
  1548.                 {
  1549.                     if(pt->lft->id && pt->rht->id)
  1550.                         pt->id = mknbl((ap_Objid)pt->lft->id, (ap_Objid)pt->rht->id, OP_DIF);
  1551.                     else
  1552.                     {
  1553.                         pt->id = pt->lft->id;
  1554.                         if(!pt->id)
  1555.                             pt->id = pt->rht->id;
  1556.                     }
  1557.                 }
  1558.                 else /* Union */
  1559.                 {
  1560.                     if(pt->lft->id && pt->rht->id)
  1561.                         pt->id = mknbl((ap_Objid)pt->lft->id, (ap_Objid)pt->rht->id, OP_UN);
  1562.                     else
  1563.                     {
  1564.                         pt->id = pt->lft->id;
  1565.                         if(!pt->id)
  1566.                             pt->id = pt->rht->id;
  1567.                     }
  1568.                 }
  1569.             }
  1570.             else
  1571.             {
  1572.                 treeprint(pt -> lft, val);
  1573.                 pt->id = pt->lft->id;
  1574.             }
  1575.         }
  1576.         else
  1577.             if (outprim(pt, val))
  1578.                 return TRUE;
  1579.     }
  1580.     return FALSE;
  1581. }
  1582.  
  1583. short
  1584. outprim(pt, val) /* make edge polys and store ids -> no arcs */
  1585. Tnptr pt;
  1586. int val;  /* offset val */
  1587. {
  1588.  
  1589.     ads_name ename;
  1590.     long do_prim();
  1591.     Vptr u;
  1592.  
  1593.     u = pt -> vtx;
  1594.     rmcolin(&u); /* remove colinear points */
  1595.     if(u && u->nxt && u->nxt->nxt)
  1596.         pt->id = do_prim(u, val);
  1597.     else
  1598.         off_err();
  1599.     if (!pt->id)
  1600.         return TRUE;
  1601.     else
  1602.         return FALSE;
  1603. }
  1604.  
  1605.  
  1606. /* ==================== BUILD POLY ===================  */
  1607.  
  1608. /* build polygon from vertices data structs */
  1609.  
  1610. build_poly(u)
  1611. Vptr u;
  1612. {
  1613.     Vptr tmp;
  1614.      int cnt, i, poly_build(), seq_end(), status;
  1615.         struct resbuf *entlist, rb;
  1616.         ads_point pnt;
  1617.     ads_real lmin[2], lmax[2];
  1618.                 
  1619.     cen[0] = cen[1] = 0.0, cnt = 0;
  1620.  
  1621.       if (ads_getvar(/*MSG0*/"LIMMIN", &rb) < 0) 
  1622.         off_err();
  1623.     lmin[0] = rb.resval.rpoint[0]; lmin[1] = rb.resval.rpoint[1];
  1624.       if (ads_getvar(/*MSG0*/"LIMMAX", &rb) < 0) 
  1625.         off_err();
  1626.     lmax[0] = rb.resval.rpoint[0]; lmax[1] = rb.resval.rpoint[1];
  1627.  
  1628.         /* In this case we know how points are */
  1629.     if (!poly_build())
  1630.         return;
  1631.     fsp[0] = u->x; fsp[1] = u->y;
  1632.     snd[0] = u->nxt->x; snd[1] = u->nxt->y;
  1633.     plim[0] = 0.0; plim[1] = 0.0;
  1634.         for (tmp = u; tmp->nxt != (Vptr)NULL; tmp = tmp->nxt)
  1635.         {
  1636.         cnt++;
  1637.                 pnt[X] = tmp->x; pnt[Y] = tmp->y;
  1638.         pnt[Z] = 0.0;
  1639.         /*
  1640.          *  Since the offset command expects a point on the object
  1641.              *  well within limits for its selection. Make sure that we
  1642.          *  get such a point and store.
  1643.          */
  1644.         /*
  1645.          * Plim is really not needed anymore as the entity name
  1646.          * can be passed before any point for the offset command
  1647.          */
  1648.         if (pnt[0] > lmin[0] && pnt[1] > lmin[1] && pnt[0] < lmax[0]
  1649.             && pnt[1] < lmax[1])
  1650.         {
  1651.             plim[0] = pnt[0];
  1652.             plim[1] = pnt[1];
  1653.         }
  1654.         cen[X] += pnt[X]; cen[Y] += pnt[Y];
  1655.         tmp->bg = 0.0;
  1656.                 if ((vert_build(pnt, tmp->bg, 1))!= RTNORM)
  1657.                         return;
  1658.         }
  1659.     if (!seq_end())
  1660.         return;    
  1661.     cen[X] /= cnt; cen[Y] /= cnt;
  1662. }
  1663.  
  1664. /* build polyline entity */
  1665.  
  1666. int 
  1667. poly_build()
  1668. {
  1669.         int status;
  1670.         struct resbuf *entlist;
  1671.  
  1672.         entlist = ads_buildlist(RTDXF0, /*MSG0*/"POLYLINE",  /* Type of entity */
  1673.                                 8,  name,        /* layer name */
  1674.                   210,  vec,         /* entity vector */
  1675.                                66,  1,          /* vertices follow */
  1676.                                70,  1,          /* close polyline */
  1677.                                NULL );          /* end */
  1678.         if (entlist == NULL)
  1679.                 ads_fail(/*MSG41*/"Unable to create result buffer list.");
  1680.         status = ads_entmake(entlist);
  1681.         ads_relrb(entlist);       /* Rel. ads_entmake() buffer */
  1682.         if (status != RTNORM){
  1683.                 ads_fail (/*MSG42*/"Unable to make polyline entity.");
  1684.                 return 0;
  1685.         }
  1686.         return 1;
  1687. }
  1688.  
  1689. /* build vertex entities */
  1690.  
  1691. int 
  1692. vert_build(pnt, bg, idx)
  1693. ads_point pnt;
  1694. ads_real bg;
  1695. int idx;
  1696. {
  1697.         int status;
  1698.         struct resbuf *entlist;
  1699.  
  1700.     /*
  1701.     bg = 0.0;
  1702.     */
  1703.     trans_euwpt(pnt, idx, FALSE);
  1704.         entlist = ads_buildlist(RTDXF0, /*MSG0*/"VERTEX",    /* Type of entity */
  1705.                                 8, name,         /* layer name */
  1706.                                10,  pnt,        /* point */
  1707.                                42, bg,          /* bulge factor */
  1708.                                NULL );          /* end */
  1709.  
  1710.  
  1711.         if (entlist == NULL)
  1712.                 ads_fail(/*MSG43*/"Unable to create result buffer list.");
  1713.         status = ads_entmake(entlist);
  1714.         ads_relrb(entlist);                    /* Rel. ads_entmake() buffer */
  1715.         if (status != RTNORM){
  1716.                 ads_fail (/*MSG44*/"Unable to make vertex entity.");
  1717.                 return 0;
  1718.         }
  1719.         return status;
  1720. }
  1721.  
  1722. /* build seq_end part */
  1723.  
  1724. int
  1725. seq_end()
  1726. {
  1727.         int status;
  1728.         struct resbuf *entlist;
  1729.  
  1730.         /* We want to end the list now */
  1731.         entlist = ads_buildlist(RTDXF0, /*MSG0*/"SEQEND",  /* Type of entity */
  1732.                                 8, name,         /* layer name */
  1733.                                NULL );          /* end */
  1734.                                 
  1735.  
  1736.         if (entlist == NULL)
  1737.                 ads_fail(/*MSG45*/"Unable to create result buffer list.");
  1738.         status = ads_entmake(entlist);
  1739.         ads_relrb(entlist);                    /* Rel. ads_entmake() buffer */
  1740.         if (status != RTNORM){
  1741.                 ads_fail (/*MSG46*/"Unable to make SEQEND.");
  1742.                 return 0;
  1743.         }
  1744.     return 1;
  1745. }
  1746.  
  1747. short
  1748. off_set (ename, val) /* go through the tree and off_set */
  1749. ads_name ename;
  1750. int val;
  1751. {
  1752.     int i;
  1753.     ads_real avg[2];
  1754.     short off_debug = 1;
  1755.     short chk_shrink();
  1756.     ads_name e1;
  1757.     int test;
  1758.  
  1759.     val *= is_exp; 
  1760.     /* come up with the point */
  1761.     
  1762.     if (val == -1) /* shrink */
  1763.     {
  1764.        test = ads_command (RTSTR, /*MSG47*/"_.OFFSET", RTREAL, off_dist, RTENAME, ename, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
  1765.        if (test != RTNORM)
  1766.        {
  1767.         ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
  1768.         exit(1);    
  1769.        }
  1770.       /* we have to check if we got a proper offset or not */
  1771.        ads_entlast (e1);
  1772.        if (!chk_shrink(ename, e1))
  1773.        {
  1774.         ads_command (RTSTR, /*MSG48*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
  1775.         return FALSE; /* done */
  1776.        }
  1777.     }
  1778.     else /* expand */
  1779.     {
  1780.         avg[0] = (fsp[0]+snd[0])/2.0;
  1781.         avg[1] = (fsp[1]+snd[1])/2.0;
  1782.         cen[0] = 2*avg[0] - cen[0];
  1783.         cen[1] = 2*avg[1] - cen[1];
  1784.             test = ads_command (RTSTR, /*MSG49*/"_.offset", RTREAL, off_dist, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
  1785.             if (test != RTNORM)
  1786.             {
  1787.             ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
  1788.             exit(1);    
  1789.            }
  1790.     }
  1791.      if (off_debug)
  1792.     ads_command (RTSTR, /*MSG50*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
  1793.     return TRUE;
  1794. }
  1795.  
  1796. /* build the convex hull object */
  1797.  
  1798. long
  1799. do_prim(u, val)
  1800. Vptr u;
  1801. int val;
  1802. {
  1803.     ads_name ename;
  1804.     ap_Objid obj;
  1805.     short off_set(), cde;
  1806.  
  1807.     build_poly(u);
  1808.     ads_entlast(ename);
  1809.     cde = off_set(ename, val); /* no proper offset */
  1810.     if (!cde)
  1811.         return 0L;
  1812.     ads_entlast(ename);
  1813.     if (ap_solidify(ename, &obj) != AP_NORMAL)
  1814.         off_err();
  1815.     ads_command (RTSTR, /*MSG51*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
  1816.     return (long)obj;
  1817. }
  1818.  
  1819. /* create csg branch node with appropriate operator */
  1820.  
  1821. long
  1822. mknbl(ob1, ob2, op)
  1823. ap_Objid ob1, ob2;
  1824. short op;
  1825. {
  1826.     ap_Objid objs[3], obj;
  1827.     ads_name en1, en2;
  1828.     
  1829.     objs[0] = ob1;
  1830.     objs[1] = ob2;
  1831.     objs[2] = (ap_Objid)NULL;
  1832.     if (op == 1)
  1833.         ap_union(objs, &obj);
  1834.     else
  1835.         ap_subtract(ob1, ob2, &obj);    
  1836.         ap_post_obj(obj, AP_POSTWIRE);
  1837.     return (long)obj;
  1838. }
  1839.  
  1840. /* convert the object to poly */
  1841.  
  1842. Entsp 
  1843. obj2ply(enm, obj, flag)
  1844. ads_name enm;
  1845. ap_Objid obj;
  1846. short flag;
  1847. {
  1848.     ap_Edgelist *elist, *slist;
  1849.     ap_Objinfo info;
  1850.     ap_Featid *llist, *temp;
  1851.     int polt_build(), seq_end(), vert_build();
  1852.     ads_real bg, get_bg();
  1853.     extern int is_tool;
  1854.     ads_name e1;
  1855.     ap_Objid ob1, obs[3];
  1856.     Entsp eb = (Entsp)NULL, et, new_entsp();
  1857.     ads_real x1, y1, x2, y2, x3, y3;
  1858.  
  1859.     if (!obj || is_tool == -1)
  1860.         return NULL;
  1861.     obs[2] = (ap_Objid)NULL;
  1862.     if (ap_get_objinfo(obj, &info) < 0)
  1863.     {
  1864.         off_err();
  1865.         return NULL;
  1866.     }
  1867.     if (info.isnull)
  1868.     {
  1869.         if (!is_tool)
  1870.         {
  1871.             ads_printf
  1872.             (/*MSG52*/"Resultant offset is NULL. Try a smaller offset distance...\n");
  1873.             ads_command(RTSTR,"_.ERASE", RTSTR, "_l", RTSTR, "", NULL);/* erase null symbol */
  1874.             return (Entsp)NULL;
  1875.         }
  1876.         else
  1877.         {
  1878.             off_dist /= 2.0;
  1879.             ap_del_obj(obj);
  1880.             et = new_entsp();
  1881.             et->nxt = eb;
  1882.             eb = et;
  1883.             eb->ename[0] = enm[0]; /* send back orig ent */
  1884.             eb->ename[1] = enm[1];
  1885.             return eb; /* try with a smaller offset HACK */
  1886.         }
  1887.     } 
  1888.     if ((ap_obj2loops(obj, &llist) < 0))
  1889.     {
  1890.         off_err();
  1891.         return (Entsp)NULL;
  1892.     }
  1893.     for (temp = llist; *temp != (ap_Featid) NULL; temp++) 
  1894.     {
  1895.         if (ap_loop2edges(obj, *temp, TRUE, &elist) < 0)
  1896.         {
  1897.             off_err();
  1898.             return (Entsp)NULL;
  1899.         }
  1900.         /* HACK for Circle */
  1901.             
  1902.         if (flag && !poly_build())
  1903.             return (Entsp)NULL;    
  1904.         for (slist = elist; slist != NULL; slist = slist->edgenext)
  1905.         {
  1906.             /* assume object's edges are ordered */
  1907.             bg = 0.0;
  1908.             if (!bg && flag && !vert_build(slist->edge->s_pt, bg, 0))
  1909.                 return (Entsp)NULL;
  1910.         }
  1911.         if (!flag && is_tool)
  1912.             do_mac(elist);
  1913.         free(elist);
  1914.         if (flag && !seq_end())
  1915.             return (Entsp)NULL;
  1916.         if (flag)
  1917.         {
  1918.             et = new_entsp();
  1919.             et->nxt = eb;
  1920.             eb = et;
  1921.             ads_entlast(e1);
  1922.             eb->ename[0] = e1[0];
  1923.             eb->ename[1] = e1[1];
  1924.         }
  1925.     }
  1926.     free(llist);
  1927.     ap_del_obj(obj);
  1928.     if (is_tool == -2)
  1929.         return (Entsp)NULL;
  1930.     else
  1931.         return eb;
  1932. }
  1933.  
  1934. /* simulate machining */
  1935.  
  1936. do_mac(elist)
  1937. ap_Edgelist *elist;
  1938. {
  1939.     extern struct resbuf *tool_buf;
  1940.     struct resbuf *assoc_rb(), *trb;
  1941.     ap_Edgelist *slist;
  1942.     ads_point cen, fsp, pt;
  1943.     int i, j, cntr = 5;
  1944.     ads_real rad, theta, inc;
  1945.  
  1946.  
  1947.     ads_command(RTSTR, /*MSG53*/"_.REGEN", NULL);
  1948.     trb = assoc_rb(tool_buf, 10);
  1949.     for (i = 0; i < 3; i++)
  1950.         fsp[i] = trb->resval.rpoint[i] = elist->edge->s_pt[i];
  1951.     ads_entmod(tool_buf);
  1952.     for (slist = elist; slist != NULL; slist = slist->edgenext)
  1953.     {
  1954.         /* assume object's edges are ordered */
  1955.         for (i = 0; i < 3; i++)
  1956.         {
  1957.             if (slist->edgenext)
  1958.                 pt[i] = (-slist->edge->s_pt[i]+slist->edgenext->edge->s_pt[i])/cntr;
  1959.  
  1960.             else
  1961.                 pt[i] = (-slist->edge->s_pt[i]+fsp[i])/cntr;
  1962.         }
  1963.         for (i = 0; i < cntr; i++)
  1964.         {
  1965.             for (j = 0; j < 3; j++)
  1966.                 trb->resval.rpoint[j] += pt[j];    
  1967.             ads_entmod(tool_buf);
  1968.         }
  1969.     }
  1970. }
  1971.  
  1972. /* check if the offset is OK */
  1973.  
  1974. short
  1975. chk_off(e1, e2)
  1976. ads_name e1, e2;
  1977. {
  1978.     ads_name ename, e3;
  1979.     struct resbuf rb, *ebuf, *eb, *assoc_rb();
  1980.     ap_Class class;
  1981.     ap_Objid obj;
  1982.     ads_real zero = 0.0;
  1983.     ads_point p1, p2, p3;
  1984.     ap_Bool fpt = FALSE, spt = FALSE, tpt = FALSE, area = FALSE;
  1985.     short tri_test();
  1986.  
  1987.     /* check if e2 is proper
  1988.         1) if it is closed
  1989.         2) if the points are inside e1/ename or not */
  1990.         
  1991.     p1[2] = p2[2] = p3[2] = -1.0;
  1992.     ebuf = ads_entget(e2);
  1993.     if (!ebuf)
  1994.         return FALSE;
  1995.     eb = assoc_rb(ebuf, 0);
  1996.         if (strcmp(eb->resval.rstring, /*MSG0*/"POLYLINE") != 0)
  1997.                 return FALSE;
  1998.         eb = assoc_rb(ebuf, 70);
  1999.         if (eb->resval.rint == 0) /* not closed */
  2000.                 return FALSE;
  2001.     /* Make the outer one as an object */
  2002.     ads_command(RTSTR, /*MSG54*/"_.COPY", RTENAME, e1, RTSTR, "", RTSTR, "0, 0", RTSTR, "0, 0", NULL);
  2003.     ads_entlast(ename);
  2004.     if (ap_solidify(ename, &obj) != AP_NORMAL)
  2005.         return FALSE;
  2006. #ifdef OLD
  2007.     /* 
  2008.      * Check area now. Write a area computing routine to get rid of
  2009.      * command prompt messages from ACAD 
  2010.          */
  2011.     ads_command(RTSTR, "_.AREA", RTSTR, "_e", RTENAME, e2, NULL);
  2012.     ads_getvar(/*MSG0*/"AREA", &rb);
  2013.     if(c_reqa(&(rb.resval.rreal), &zero, &eps))
  2014.     {
  2015.         ads_command(RTSTR, /*MSG55*/"_.ERASE", RTSTR, "_l", RTSTR, "", NULL);
  2016.         return FALSE;
  2017.     }
  2018. #endif 
  2019.     e3[0] = e2[0]; e3[1] = e2[1];
  2020.     while (ads_entnext(e3, e3) == RTNORM)
  2021.         {
  2022.                 ebuf = ads_entget(e3);
  2023.                 eb = assoc_rb(ebuf, 0);
  2024.                 if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
  2025.                 {
  2026.                         eb = assoc_rb(eb, 10);
  2027.             if (!fpt) /* B.S. -> compute area */
  2028.             {
  2029.                 Cpoint (p1, eb->resval.rpoint);
  2030.                 fpt = TRUE;
  2031.             }
  2032.             else if (!spt)
  2033.             {
  2034.                 Cpoint (p2, eb->resval.rpoint);
  2035.                 spt = TRUE;
  2036.             }
  2037.             else if (!tpt) 
  2038.             {
  2039.                 Cpoint (p3, eb->resval.rpoint);
  2040.                 tpt = TRUE;
  2041.                 if (tri_test(p1, p2, p3))
  2042.                     area = TRUE;
  2043.             }
  2044.             else if (!area)
  2045.             {
  2046.                 Cpoint (p2, p3);
  2047.                 Cpoint (p3, eb->resval.rpoint);
  2048.                 if (tri_test(p1, p2, p3))
  2049.                     area = TRUE;
  2050.             }
  2051.             /* classify point */
  2052.             trans_euwpt(eb->resval.rpoint, 1, TRUE);
  2053.             if (ap_class_pt(obj, eb->resval.rpoint, &class) != AP_NORMAL)
  2054.             {
  2055.                 ap_del_obj(obj);
  2056.                             ads_relrb(ebuf);
  2057.                 return FALSE;
  2058.             }
  2059.             if (class != AP_INOBJECT)
  2060.             {
  2061.                 ap_del_obj(obj);
  2062.                             ads_relrb(ebuf);
  2063.                 return FALSE;
  2064.             }
  2065.                         
  2066.                 }       
  2067.         else
  2068.                 if (strcmp (eb->resval.rstring, /*MSG0*/"SEQEND") == 0)
  2069.             break;
  2070.         }
  2071.     ap_del_obj(obj);
  2072.     ads_command(RTSTR, /*MSG55*/"_.ERASE", RTENAME, ename, RTSTR, "", NULL);
  2073.         ads_relrb(ebuf);
  2074.     if (!area)
  2075.         return FALSE;
  2076.     return TRUE; 
  2077. }
  2078.  
  2079. /* CHK_SHRINK -- Check the shrink and see if it is valid
  2080.           -- If machined first time 
  2081. */
  2082.  
  2083. short
  2084. chk_shrink(e1, e2)
  2085. ads_name e1, e2;
  2086. {
  2087.    short chk_off(), val;
  2088.    ap_Objid obj;
  2089.    Entsp cde, obj2ply();
  2090.    int test;
  2091.  
  2092.    if (is_tool == -1)
  2093.    {    
  2094.     ads_command (RTSTR, /*MSG56*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
  2095.     ads_printf (/*MSG57*/"Done machining\n");
  2096.     return FALSE;
  2097.    }    
  2098.    val = chk_off(e1, e2);
  2099.    if (!val) /* bad offset */
  2100.    {
  2101.     ads_command (RTSTR, /*MSG58*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
  2102.     if (is_tool == 0) /* from offset command --> complain */ 
  2103.     {
  2104.         ads_printf
  2105.         (/*MSG59*/"\nBad offset. Try a smaller offset distance, parallel UCS, etc. ...\n");
  2106. #ifdef OLD
  2107.         (/*MSG59*/"\nResultant offset is NULL. Try a smaller offset distance...\n");
  2108. #endif
  2109.         is_tool = -1;
  2110.         return FALSE;
  2111.     }
  2112.     if (is_tool > 1)   /* cutting the latter parts recurs till done HACK */
  2113.     {
  2114.         off_dist /= 2.0;
  2115.         test = ads_command (RTSTR, /*MSG60*/"_.offset", RTREAL, off_dist, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
  2116.             if (test != RTNORM)
  2117.             {
  2118.             ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
  2119.             exit(1);    
  2120.         }
  2121.         ads_entlast(e2);
  2122.         /* do chk_off again */
  2123.            val = chk_off(e1, e2);
  2124.         if (!val)
  2125.         {
  2126.             ads_command (RTSTR, /*MSG61*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
  2127.             is_tool = -1;
  2128.             return FALSE;
  2129.         }
  2130.         /* do tool movement again */
  2131.         if (ap_solidify(e2, &obj) != AP_NORMAL)
  2132.         {
  2133.             off_err();
  2134.             return TRUE;
  2135.         }
  2136.         cde = obj2ply(e2, obj, FALSE); /* tool movement */ 
  2137.         dump_ent(cde);
  2138.         is_tool = -2;
  2139.         return TRUE;
  2140.     }
  2141.     else if (is_tool == 1) /* no need to machine further */
  2142.     {
  2143.         ads_printf
  2144.         (/*MSG62*/"\nObject machined in one pass. No offsetting required...\n");
  2145.         ;
  2146.         /* machine the outer one at least once */
  2147.         /* is_tool = -1; */
  2148.     }
  2149.     return FALSE;
  2150.    }
  2151.    return TRUE;
  2152. }
  2153.  
  2154. /* allocate new Ents */
  2155.  
  2156. Entsp
  2157. new_entsp()
  2158. {
  2159.     Entsp tmp;
  2160.     static char *fname = /*MSG63*/"new_entsp";
  2161.  
  2162.     if((tmp = (Entsp)malloc(sizeof(Ents))) == (Entsp)NULL)
  2163.     {
  2164.         ads_printf(/*MSG64*/"Out of memory...\n");
  2165.         return((Entsp)NULL) ;
  2166.     }
  2167.     tmp->ename[0] = 0L;
  2168.     tmp->ename[1] = 0L;
  2169.     tmp->nxt = (Entsp)NULL;
  2170.     return tmp;
  2171. }
  2172.  
  2173. /*
  2174.  *      Get the equation of a straight line
  2175.  *      passing through the given points.
  2176.  */
  2177.  
  2178. short st_line(pt1, pt2, line)
  2179. Point pt1, pt2;
  2180. Line *line;                            /* equation is ax + by + c = 0 */
  2181. {
  2182.  
  2183. #ifdef __WATCOMC__
  2184.     double xd, yd;
  2185. #else
  2186.     double sqrt(), xd, yd;
  2187. #endif /* WATCOMC */
  2188.  
  2189.         if(requal(pt1.x, pt2.x, EXT_EPS) && requal(pt1.y, pt2.y, EXT_EPS))
  2190.                 return(FALSE);
  2191.         line->x1 = pt1.x;
  2192.         line->y1 = pt1.y;
  2193.         line->x2 = pt2.x;
  2194.         line->y2 = pt2.y;
  2195.     xd = pt2.x - pt1.x;
  2196.     yd = pt2.y - pt1.y;
  2197.     line->len = sqrt((yd*yd) + (xd*xd));
  2198.         if(requal(pt1.x, pt2.x, EXT_EPS))
  2199.         {
  2200.                 line->a = 1.0;
  2201.                 line->b = 0.0;
  2202.                 line->c = - pt1.x;
  2203.                 return(TRUE);
  2204.         }
  2205.         if(requal(pt1.y, pt2.y, EXT_EPS))
  2206.         {
  2207.                 line->a = 0.0;
  2208.                 line->b = 1.0;
  2209.                 line->c = - pt1.y;
  2210.                 return(TRUE);
  2211.         }
  2212.         line->a = - (yd/xd);
  2213.         line->b = 1.0;
  2214.         line->c = - pt2.x * line->a - pt2.y;
  2215.         return(TRUE);
  2216. }
  2217.  
  2218. /*
  2219.  *      Does the point lie on the line segment ?
  2220.  */
  2221.  
  2222. short on_line(line, pt)
  2223. Line line;
  2224. Point pt;
  2225. {
  2226.         double slope1, slope2;
  2227.     short in_between();
  2228.  
  2229.         if(requal(line.x2, line.x1, EXT_EPS) || requal(pt.x, line.x1, EXT_EPS))
  2230.         {
  2231.                 if(requal(line.x2, line.x1, EXT_EPS) &&
  2232.                         requal(pt.x, line.x1, EXT_EPS))
  2233.                 {
  2234.                         if(in_between(line.y1, line.y2, pt.y, EXT_EPS))
  2235.                                 return(TRUE);
  2236.                         else
  2237.                                 return(FALSE);
  2238.                 }
  2239.                 else
  2240.                         return(FALSE);
  2241.         }
  2242.         else
  2243.         {
  2244.                 slope1 = (line.y2 - line.y1) / (line.x2 - line.x1);
  2245.                 slope2 = (pt.y - line.y1) / (pt.x - line.x1);
  2246.                 if(requal(slope1, slope2, EXT_EPS))
  2247.                         if(in_between(line.x1, line.x2, pt.x, EXT_EPS))
  2248.                                 return(TRUE);
  2249.                 return(FALSE);
  2250.         }
  2251. }
  2252.  
  2253. /*
  2254.  *      Check if a number is in between 2 others
  2255.  *      and not equal to either of them.
  2256.  *
  2257.  *      ****    Check if c is between a and b   ******
  2258.  */
  2259.  
  2260. short in_between(a, b, c, eps)
  2261. double a, b, c, eps;
  2262. {
  2263.         if (( c > a && c < b ) || ( c > b && c < a ))
  2264.                 if ( !requal( c, a, eps ) && !requal( c, b, eps ))
  2265.                         return TRUE;
  2266.         return FALSE;
  2267. }
  2268.  
  2269. /* utility function for tangent inverse to handle special cases */ 
  2270.  
  2271. double
  2272. asatan2(x, y)
  2273. double x, y;
  2274. {
  2275. #ifndef __WATCOMC__
  2276.         double atan2(), fabs();
  2277. #endif /* NOT WATCOMC */
  2278.  
  2279.         if ((fabs(x) < 1.0E-20) && (fabs(y) < 1.0E-20))
  2280.                 return ASPI_2;
  2281.         else
  2282.                 return atan2(x, y);
  2283. }
  2284.  
  2285. /* utility function for cosine inverse to handle special cases */ 
  2286.  
  2287. double
  2288. asacos(p)
  2289. double p;
  2290. {
  2291. #ifndef __WATCOMC__
  2292.         double acos();
  2293. #endif /* NOT WATCOMC */
  2294.  
  2295.         if (p > 1.0)
  2296.                 return 0.0;
  2297.         
  2298.         if (p < -1.0)
  2299.                 return ASPI;
  2300.  
  2301.         return acos(p);
  2302. }
  2303.  
  2304. /* utility function to compare two real numbers eqality within the epsilon */
  2305.  
  2306. short
  2307. requal(val1, val2, eps)
  2308. double val1, val2, eps;
  2309. {
  2310.   return (c_reqa(&val1, &val2, &eps));
  2311. }
  2312.  
  2313. /* tri_test() uses the signed_area of a triangle as a test whether
  2314.     three points in a plane are oriented in a CCW or CW direction   */
  2315.  
  2316. short
  2317. tri_test(p1, p2, p3)    /* 2D signed area: if > 0, then p1,p2 and p3 are CCW */
  2318. ads_real *p1, *p2, *p3;
  2319. {
  2320.         ads_real s_area;
  2321.         ads_real zero = 0.0;
  2322.         ads_real epsi;
  2323.         epsi = (ads_real)TRUNC_EPS;
  2324.  
  2325.         s_area = ((p3[0] - p1[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p3[1] - p1[1]));
  2326.           /* evaluate the determinant */
  2327.  
  2328.         if (c_reqa (&s_area, &zero, &epsi))
  2329.                 return 0;               /* straight line */
  2330.         if (s_area < 0)
  2331.                         return 1;       /* CCW  */
  2332.         return -1;
  2333. }
  2334.  
  2335. /* EOF */
  2336.