home *** CD-ROM | disk | FTP | other *** search
- /* Next available MSG number is 65 */
-
- /*************************************************************************
- Name: offsol.c. AME2_APLIB_SAMP_offsol.c
-
- Description: AME/API sample program for region-based offsetting
-
- Author: Japan/Eagle Group
- Autodesk, Inc.
-
-
-
-
- Copyright (C) 1992 by Autodesk, Inc.
- /*************************************************************************
- *
- * Permission to use, copy, modify, and distribute this software
- * for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appears in all copies and that
- * both that copyright notice and this permission notice appear in
- * all supporting documentation.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED
- * WARRANTY. ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR
- * PURPOSE AND OF MERCHANTABILITY ARE HEREBY DISCLAIMED.
- *
- * *
- * Offsetting is the heart of machining/milling. The OFFSET command in *
- * AutoCAD is unpredictable for regions with concavities and for large *
- * shrink distances This program allows the user to take advantage of *
- * the region modeler in AME2.0 to solve these problems and offer a *
- * better machining environment. This sample program only deals with *
- * polylines with out arcs but can be extended to address them. Since *
- * the objective of the routine is also to demonstrate the power of *
- * region modeler the intermediate region operations are left visible. *
- * If desired, the region processes can be made transparent by a ghost *
- * script. *
- * *
- * Two commands "SOLOFF" and "SOLMAC" *
- * are available in this implementation. *
- * *
- * The command syntax for "SOLOFF" is shown as follows: *
- * *
- * Command: soloff *
- * Offset distance <0.1000000>: Enter a value or RETURN *
- * Shrink/Expand<s>: Enter 'e' for expand or RETURN foe shrink *
- * Select a closed polyline of lines (only) to offset: *
- * Pick a non self-intersecting closed polyline consisting *
- * of lines only *
- * *
- * The selected entity has to be closed polyline. This command *
- * disallows large shrink distances resulting in NULL objects. *
- * *
- * OFFSOL command lets you offset a closed polyline with a given *
- * distance. This command is mainly implemented for NC tool path *
- * generation. Shrinking is the main consideration but expansion also *
- * should work. The polyline is decomposed into a region CSG (with *
- * convex hulls) as primitives. Each primitive is then offset and *
- * combined through the tree to give consistent *
- * offsetting. The resulting region is converted to a polyline and *
- * displayed. The software can be modified for specific requirements *
- * and other applications. *
- * *
- * The command syntax for "SOLMAC" is shown as follows: *
- * *
- * Command: solmac *
- * Enter the diameter of tool <0.100000>: Enter a value *
- * Select a closed polyline of lines (only) to offset: *
- * Pick a non self-intersecting closed polyline consisting *
- * of lines only *
- * *
- * For very large tool diameters which need only one pass to machine *
- * the polyline, a message appears and no offsets are generated. *
- * *
- * SOLMAC command lets you create tool paths recursively till the *
- * whole 2d - solid is milled off. It uses the above offsol command *
- * recursively with the shrink option and offset distance equal to the *
- * tool diameter. A circle representing the tool is created and *
- * traversed over the current polyline. The final offset distance is *
- * reduced, if needed, from tool diameter to tool radius to accomplish *
- * complete machining. If multiple loops result in the offsetting, *
- * each loop is machined fully before the next loop is machined, for *
- * maximum efficiency. *
- * *
- * The offset distance, tool diameter and the shrink or expansion *
- * option mentioned for the above commands use the previous selection *
- * values as current defaualt values. *
- * Since the above commands use AutoCAD's offset command on convex *
- * hulls and entity selection through points the program centers the *
- * object and sets proper zoom and limits. The current view and confi- *
- * guration is saved and restored at the end of offsetting. *
- * *
- * It must be kept in mind that the program gives unexpected results *
- * for such cases when the entity is not parallel to UCS. *
- * *
- * You may want to take a look at code around *FHACK* for more *
- * robustness. *
- * *
- * *
- **************************************************************************
-
- Modification history:
- Refer to the RCS section at the end of this file.
-
- Bugs and restrictions on use:
-
- Notes:
-
- **************************************************************************/
-
-
- /*************************************************************************/
- /* Includes */
- /*************************************************************************/
-
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include <adslib.h>
- #include <aplib.h>
-
- /*************************************************************************/
- /* Defines */
- /*************************************************************************/
-
- #define PI 3.1415926
- #define ASPI 3.14159265358979323846
- #define AS2PI 2.0*3.14159265358979323846
- #define ASPI_2 3.14159265358979323846/2.0
- #define OP_DIF -1
- #define OP_UN 1
- #define ueps1 0.0008 /* different epsilons used throught the code */
- #define nueps 1.3258789e-4
- #define TRUNC_EPS 0.000001
- #define EXT_EPS 0.00001
- #define f_abs(a) ((a) >= 0.0 ? (a) : -(a))
- #define c_reqa(x, y, z) (f_abs(*(x) - *(y)) < *(z))
- #define NELEM(a) (sizeof a / sizeof a[0])
- #define Cpoint(ptd, pts) ptd[X] = pts[X]; ptd[Y] = pts[Y]; ptd[Z] = pts[Z]
-
- #ifndef ELEMENTS
- #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
- #endif
-
- /*************************************************************************/
- /* Typedefs */
- /*************************************************************************/
-
- typedef struct plypts /* polyline points */
- {
- double x; /* x - cord */
- double y; /* y - cord */
- double bg; /* bulge for arc */
- } Ppts, *ppts;
-
- typedef struct vertex /* vertex info. */
- {
- double x; /* x-cord */
- double y; /* y-cord */
- double bg; /* bulge for arc */
- short flag; /* additional info about line from this vtx to next */
- struct vertex *nxt; /* ptr to next vertex */
- } Vertex, *Vptr;/* vertex pointer */
-
- typedef struct
- {
- double x;
- double y;
- } Point;
-
- typedef struct trenod /* treenode info. */
- {
- short op; /* operation code (-1=>dif, 1=>un) */
- struct trenod *rht; /* ptr to right son */
- struct trenod *lft; /* ptr to left son */
- Vptr vtx; /* ptr to vertex data */
- long idx; /* index to be transferred */
- long id; /* solid id */
- } Trenod, *Tnptr;/* treenod pointer */
-
- typedef struct store /* to store processing info. */
- {
- Trenod * ptr; /* Treenod pointer to be processed */
- Trenod * pid; /* Usually left son */
- struct store *nxt; /* ptr to next stored data */
- } Store, *Stptr;/* storage ptr */
-
- typedef struct line
- {
- double x1, y1; /* first point */
- double x2, y2; /* second point */
- double a, b, c; /* coefficients of equation */
- double len; /* length */
- struct line *li_next;
- struct line *li_prev;
- } Line;
-
- typedef struct ents
- {
- ads_name ename; /* entity name */
- struct ents *nxt; /* next one */
- } Ents, *Entsp;
-
- /*************************************************************************/
- /* Global variables */
- /*************************************************************************/
-
- char name[32]; /* current layer name */
- ads_point vec; /* 210 vec for ECS */
- ads_real off_dist = 0.1; /* default offset distance */
- short is_exp = -1; /* default shrink option */
- ads_name tool_name; /* entity name for tool */
- struct resbuf *tool_buf; /* resbuf for tool ent. */
- int is_tool = 0;
- static ads_real cen[2], plim[2], fsp[2], snd[2]; /* XXXX */
- static Stptr sb, scur; /* ptrs to base and current storage */
- static Tnptr root; /* ptr to root */
- static double z1,z2,theta; /* bounding faces for ext. & rev. ang */
- static Vptr vi; /* ptr to initial vertex */
- static short dirn, i2, quat;
- long totpts; /* total number of points */
- static long glob; /* do boolean */
-
- /* Function type declaration */
-
- void off_sol();
- void mac_sol();
- short requal();
- long mknbl();
- /*
- * Define forward references for HighC compiler
- */
- Tnptr treealloc();
- #if HIGHC386 || sun4 || __ZTC__
- void *malloc();
- #else
- char *malloc();
- #endif
- static int funcload();
- static void print_new_command_set();
-
- /* Command definition and dispatch table. */
-
- struct ads_comm {
- char *cmdname;
- void (*cmdfunc) ();
- };
-
- struct ads_comm cmdtab[] = {
- {/*MSG1*/"C:SOLMAC", mac_sol},
- {/*MSG2*/"C:SOLOFF", off_sol},
- };
-
- /*************************************************************************/
- /* .doc main() */
- /*+
- -*/
- /*************************************************************************/
-
- void
- /*FCN*/main(argc, argv)
- int argc;
- char *argv[];
- {
- int stat, cindex;
- short scode = 1;
-
- ads_init(argc, argv);
-
- while (TRUE) {
- if ((stat = ads_link(scode)) < 0) {
- printf(/*MSG3*/"OFFSOL: bad status from ads_link() = %d\n",stat);
- fflush(stdout);
- ads_exit(1);
- }
- scode = -RSRSLT;
-
- switch (stat) {
- case RQXLOAD: /* Load & register functions */
- scode = -(funcload() ? RSRSLT : RSERR);
- scode = -RSRSLT;
- print_new_command_set();
- break;
-
- case RQXUNLD: /* Unloading */
- scode = (funcunload () ? RSRSLT : RSERR);
- ads_printf (/*MSG4*/"Unloading: ");
- break;
-
- case RQSUBR: /* Evaluate external lisp function */
- cindex = ads_getfuncode();
- (*cmdtab[cindex].cmdfunc) ();
- break;
-
- default:
- break;
-
- }
- }
- }
-
- /*************************************************************************/
- /* .doc funcload() */
- /*+
- Load external functions into AutoCAD system
- -*/
- /*************************************************************************/
-
- static ap_Bool
- /*FCN*/funcload()
-
- {
- int i;
-
- for (i = 0; i < ELEMENTS(cmdtab); i++) {
- if(! ads_defun (cmdtab[i].cmdname , i))
- return RTERROR;
- }
- return RTNORM;
- }
-
- /*************************************************************************/
- /* .doc funcunload() */
- /*+
- Unload registered functions from AutoCAD system
- -*/
- /*************************************************************************/
-
- static ap_Bool
- /*FCN*/funcunload()
-
- {
- int i;
-
- for (i = 0; i < ELEMENTS(cmdtab); i++)
- ads_undef(cmdtab[i].cmdname, i);
-
- return RTNORM;
- } /* funcunload */
-
- /*************************************************************************/
- /* .doc print_new_command_set() */
- /*+
- -*/
- /*************************************************************************/
-
- static void
- /*FCN*/print_new_command_set()
- {
- ads_printf(/*MSG5*/"\nNew loaded commands: SOLOFF, SOLMAC\n");
- }
-
- /*
- * Print out the entity data similar to dxf format
- */
-
- void off_sol()
- {
- ads_name e1;
- ads_point pt;
- char cmd[8], prompt[64];
- int result;
- Entsp done, do_proc();
-
-
- if (ap_init() != AP_NORMAL)
- return;
- is_tool = 0;
- sprintf (prompt, /*MSG6*/"Offset distance <%f>:", off_dist);
- ads_initget (2+4, NULL); /* allow only positive values */
- if (ads_getdist (NULL, prompt, &off_dist) == RTCAN)
- return;
- if (is_exp == 1)
- sprintf (prompt, /*MSG7*/"Shrink/Expand<e>:");
- else
- sprintf (prompt, /*MSG8*/"Shrink/Expand<s>:");
- ads_initget(0, /*MSG9*/"Shrink Expand");
- result = ads_getkword(prompt, cmd);
- if (result < 0)
- return;
- if (strcmp(cmd, /*MSG10*/"Shrink") == 0)
- is_exp = -1;
- if (strcmp(cmd, /*MSG11*/"Expand") == 0)
- is_exp = 1;
- /* default is_exp = 1 */
- ads_entsel(/*MSG12*/"Select closed polyline of lines (only) to offset:", e1, pt);
- /*
- ads_entsel("Select closed polyline to offset:", e1, pt);
- */
- done = do_proc(e1);
- return;
- }
-
- /*
- * Search a result buffer chain and return an item
- * associated with the specified group code.
- */
-
- struct resbuf
- /*FCN*/*assoc_rb(rb, grp)
- struct resbuf *rb;
- int grp;
- {
- while ((rb != NULL) && (rb->restype != grp))
- rb = rb->rbnext;
- return rb;
- }
-
- off_err()
- {
- ;
- /*
- ads_printf ("Error in off_setting\n");
- */
- }
-
- /* prepare data for main offsetting routine */
-
- Entsp
- do_proc(e1)
- ads_name e1;
- {
- struct resbuf *ebuf, *eb, *eb2, *assoc_rb(), cb, rb, lb1, lb2;
- ads_name e2;
- ads_point pt;
- char cmd[8], prompt[64];
- int result;
- int cntr = 0, numvert = 0; /* count the number of verts */
- int cmdecho;
- Entsp done, e_proces();
- Ppts *ed;
- ap_Objid obj;
- Entsp cde, obj2ply();
- ads_point lmn, lmx, p, pl;
- short closed = FALSE, frst = TRUE;
- ads_real eps = (ads_real)TRUNC_EPS;
-
- p[2] = lmn[2] = lmx[2] = 0.0;
- ebuf = ads_entget(e1);
- if (!ebuf)
- return (Entsp)NULL;
- eb = assoc_rb(ebuf, 0);
- if (strcmp(eb->resval.rstring, /*MSG0*/"POLYLINE") != 0)
- {
- ads_printf(/*MSG13*/"The entity has to be a polyline\n");
- return (Entsp)NULL;
- }
- eb = assoc_rb(eb, 8); /* get the layer name */
- sprintf (name, eb->resval.rstring);
- eb = assoc_rb(eb, 210); /* get the ECS vec */
- Cpoint (vec, eb->resval.rpoint);
- eb = assoc_rb(ebuf, 70);
- if (eb->resval.rint & 8)
- {
- ads_printf
- ("\nNot a polyline. 3D polyline can not be offset\n");
- return (Entsp)NULL;
- }
- else if (eb->resval.rint & 16)
- {
- ads_printf
- ("\nNot a polyline. 3D mesh can not be offset\n");
- return (Entsp)NULL;
- }
- else if (eb->resval.rint > 1)
- {
- ads_printf
- (/*MSG14*/"\nNot a closed polyline of lines. Entity can not be offset\n");
- return (Entsp)NULL;
- }
- else if (eb->resval.rint == 1)
- closed = TRUE;
- eb = assoc_rb(ebuf, 75);
- if (eb && eb->resval.rint > 0)
- {
- ads_printf(/*MSG15*/"Not a polyline of lines. Entity can not be offset\n");
- return (Entsp)NULL;
- }
- ads_relrb(ebuf);
- if (is_tool) /* machine outer boundary */
- {
- if (ap_solidify(e1, &obj) != AP_NORMAL)
- off_err();
- cde = obj2ply(e1, obj, FALSE);
- dump_ent(cde);
- }
-
- ads_getvar(/*MSG0*/"CMDECHO", &cb);
- cmdecho = cb.resval.rint;
- cb.resval.rint = 0; /* turn the commands off */
- ads_setvar(/*MSG0*/"CMDECHO", &cb);
- ads_command (RTSTR, /*MSG16*/"_.VIEW", RTSTR, /*MSG17*/"_S", RTSTR,
- /*MSG18*/"off_set", NULL);
- ads_command (RTSTR, /*MSG20*/"_.PLAN", RTSTR, "", NULL);
-
- e2[0] = e1[0]; e2[1] = e1[1];
- while (ads_entnext(e2, e2) == RTNORM)
- {
- ebuf = ads_entget(e2);
- eb = assoc_rb(ebuf, 0);
- if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
- {
- cntr++;
- eb = assoc_rb(eb, 42);
- if (eb && eb->resval.rreal) /* arc or circle */
- {
- ads_printf
- (/*MSG20*/"\nArcs and circles are not supported in this version\n");
- return (Entsp)NULL;
- }
- pl[0] = eb->resval.rpoint[X];
- pl[1] = eb->resval.rpoint[Y];
- if (!closed && frst)
- {
- p[0] = pl[0];
- p[1] = pl[1];
- frst = FALSE;
- }
- }
- else /* SEQEND */
- {
- ads_relrb(ebuf);
- if (!closed)
- {
- if ((c_reqa(&pl[0], &p[0], &eps)) && (c_reqa(&pl[1], &p[1], &eps)))
- {
- closed = 2;
- cntr--;
- }
- else
- {
- ads_printf
- (/*MSG14*/"\nNot a closed polyline. Entity can not be offset\n");
- return (Entsp)NULL;
- }
-
- }
- break;
- }
- }
-
- if((ed = (Ppts *)malloc(sizeof(struct plypts) * cntr)) == NULL)
- off_err();
-
- frst = TRUE; numvert = cntr;
- cntr = 0;
- e2[0] = e1[0]; e2[1] = e1[1];
- while (ads_entnext(e2, e2) == RTNORM)
- {
- ebuf = ads_entget(e2);
- eb = assoc_rb(ebuf, 0);
- if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
- {
- if (closed == 2 && cntr == numvert) /* last vert is a repeat */
- {
- closed = TRUE;
- continue;
- }
- eb = assoc_rb(eb, 10);
- trans_euwpt(eb->resval.rpoint, 1, TRUE);
- ed[cntr].x = p[0] = eb->resval.rpoint[X];
- ed[cntr].y = p[1] = eb->resval.rpoint[Y];
- if (frst)
- {
- frst = FALSE;
- lmn[X] = lmx[X] = p[X];
- lmn[Y] = lmx[Y] = p[Y];
- }
- else
- {
- if (p[X] < lmn[X])
- lmn[X] = p[X];
- if (p[X] > lmx[X])
- lmx[X] = p[X];
- if (p[Y] < lmn[Y])
- lmn[Y] = p[Y];
- if (p[Y] > lmx[Y])
- lmx[Y] = p[Y];
- }
- eb = assoc_rb(eb, 42);
- ed[cntr].bg = eb->resval.rreal;
- cntr++;
- ads_relrb(ebuf);
-
- }
- else
- {
- ads_relrb(ebuf);
- break;
- }
- }
- /* let us zoom in on the entity and position at center */
- ads_command(RTSTR, /*MSG21*/"_.zoom", RTSTR, /*MSG22*/"_w", RT3DPOINT, lmn,
- RT3DPOINT, lmx, NULL);
- ads_command(RTSTR, /*MSG23*/"_.zoom", RTSTR, /*MSG24*/"0.3x", NULL);
-
- /* get the limits and store */
- if (ads_getvar(/*MSG0*/"LIMMIN", &lb1) < 0)
- off_err();
- if (ads_getvar(/*MSG0*/"LIMMAX", &lb2) < 0)
- off_err();
-
- /* get the view limits and set as new limits */
- if (ads_getvar(/*MSG0*/"VSMIN", &rb) < 0)
- off_err();
- ads_command (RTSTR, /*MSG25*/"_.LIMMIN", RT3DPOINT, rb.resval.rpoint, NULL);
-
- if (ads_getvar(/*MSG0*/"VSMAX", &rb) < 0)
- off_err();
- ads_command (RTSTR, /*MSG26*/"_.LIMMAX", RT3DPOINT, rb.resval.rpoint, NULL);
-
- done = e_proces(e1, ed, cntr); /* process edges */
- clean_up(); /* clean up the stuff */
- free(ed); /* free the array of points */
- ads_command (RTSTR, /*MSG27*/"_.REGEN", NULL);
-
- cb.resval.rint = cmdecho; /* put back the original value */
- ads_command (RTSTR, /*MSG28*/"_.LIMMIN", RT3DPOINT, lb1.resval.rpoint, NULL);
- ads_command (RTSTR, /*MSG29*/"_.LIMMAX", RT3DPOINT, lb2.resval.rpoint, NULL);
- ads_command (RTSTR, /*MSG30*/"_.ZOOM", RTSTR, /*MSG31*/"_E", NULL);
- ads_command (RTSTR, /*MSG32*/"_.VIEW", RTSTR, /*MSG33*/"_R", RTSTR,
- /*MSG34*/"off_set", NULL);
- ads_setvar(/*MSG0*/"CMDECHO", &cb);
-
- return (done);
- }
-
- /* transform the point from one coord system to another */
- trans_euwpt (pt, idx, e2u)
- ads_point pt;
- int idx;
- short e2u;
- {
- ads_point result;
- struct resbuf fromrb, torb;
-
- if (e2u) /* ECS to U/WCS */
- {
- fromrb.restype = RT3DPOINT;
- Cpoint (fromrb.resval.rpoint, vec);
- torb.restype = RTSHORT;
- torb.resval.rint = idx; /* U/WCS */
- }
- else /* U/WCS to ECS */
- {
- fromrb.restype = RTSHORT;
- fromrb.resval.rint = (short)idx; /* U/WCS */
- torb.restype = RT3DPOINT;
- Cpoint (torb.resval.rpoint, vec);
- }
- if ((ads_trans (pt, &fromrb, &torb, 0, result)) != RTNORM)
- off_err();
- Cpoint (pt, result);
- }
-
- /*
- * Machine solid along the offset distance
- */
-
- void mac_sol()
- {
- ads_name e1, e2;
- ads_point pt;
- char cmd[8], prompt[64];
- Entsp ent, do_proc();
- int result, cmdecho;
- ads_real toff;
- struct resbuf cb;
-
-
- if (ap_init() != AP_NORMAL)
- return;
- is_tool = 1;
- sprintf (prompt, /*MSG35*/"Enter the diameter of tool <%f>:", off_dist);
- ads_initget (2+4, NULL); /* allow only positive values */
- if (ads_getdist (NULL, prompt, &off_dist) == RTCAN)
- return;
- /* We are always shrinking */
- is_exp = -1;
-
- /*
- * Suppress AutoCAD command echo
- */
-
- ads_getvar(/*MSG0*/"CMDECHO", &cb);
- cmdecho = cb.resval.rint;
- cb.resval.rint = 0; /* turn the commands off */
- ads_setvar(/*MSG0*/"CMDECHO", &cb);
-
- ads_command(RTSTR, /*MSG36*/"_.CIRCLE", RTSTR, "0, 0", RTREAL, off_dist/2.0, NULL);
-
- /*
- * Resume AutoCAD command echo
- */
-
- cb.resval.rint = cmdecho;
- ads_setvar(/*MSG0*/"CMDECHO", &cb);
-
- ads_entlast(tool_name);
- tool_buf = ads_entget(tool_name);
- ads_entsel(/*MSG37*/"Select closed polyline of lines (only) to machine:", e1, pt);
- ent = do_proc(e1);
- if (!ent)
- return;
- toff = off_dist;
- is_tool = 2;
-
- sprintf(prompt, /*MSG38*/"\nContinue machining <Yes>/No: ");
- /* create the offsets till we are done */
- do_end(ent, toff);
- off_dist = toff;
- ads_relrb(tool_buf);
- return;
- }
-
- /* recursive routine to machine till end */
-
- do_end(ent, toff)
- Entsp ent;
- ads_real toff;
- {
- Entsp tmp, t2, do_proc();
-
- for (tmp = ent; tmp != (Entsp)NULL; tmp = tmp->nxt)
- {
- ent = do_proc(tmp->ename);
- if (!ent)
- {
- is_tool = 2;
- off_dist = toff;
- if (!tmp->nxt)
- break;
- }
- else
- do_end(ent, toff);
- }
- dump_ent(ent);
- }
-
- /* free up ent */
-
- dump_ent(ent)
- Entsp ent;
- {
- Entsp tmp, t2;
-
- tmp = ent; /* Free */
- while (tmp != NULL)
- {
- t2 = tmp->nxt;
- free (tmp);
- tmp = t2;
- }
- }
-
- /* main offsetting control routine */
-
- Entsp
- e_proces(enm, edata, n)
- ads_name enm;
- Ppts edata[];
- short n;
- {
- char *yy;
- static char *fname = /*MSG39*/"e_process";
- Entsp obj2ply();
- short frmary(), treeprint();
-
- totpts = n;
- n = n - 1;
- if (frmary(edata, (long)n))
- return (Entsp)NULL; /* done */
- root = (Tnptr)NULL;
- if (vi)
- {
- inidata(); /* initialization */
- traverse(); /* traverse and process stored data */
- if (treeprint(root, (int)-1)) /* prepare a file */
- return (Entsp)NULL; /* done */
- glob = root->id;
- }
- return (obj2ply(enm, glob, TRUE));
- }
-
- /* clean up and free the data structures */
-
- clean_up()
- {
- Stptr stmp,stmp1;
-
- treedump(root);
- stmp = sb;
- while(stmp)
- {
- stmp1 = stmp->nxt;
- free(stmp);
- stmp = stmp1;
- }
- }
-
- treedump(pt)
- Tnptr pt;
- {
- Vptr tmp1,tmp;
-
- if(pt)
- {
- if(pt->rht)
- treedump(pt->rht);
- if(pt->lft)
- treedump(pt->lft);
- tmp = pt->vtx;
- while(tmp)
- {
- tmp1 = tmp;
- tmp = tmp->nxt;
- free(tmp1);
- tmp1 = NULL;
- }
- free(pt);
- pt = NULL;
- }
- }
-
- /* routine to determine direction clw or cclw and get the left bottom point */
-
- static void
- detdir(xx, num, trk)
- Ppts xx[];
- long num, *trk;
- {
- #ifdef __WATCOMC__
- double minx, miny, leastx, leasty, maxx, maxy;
- #else
- double minx, miny, leastx, leasty, maxx, maxy, cos(), sin(), sqrt();
- #endif /* WATCOMC */
- double x, y, a1, b1, a2, b2, eps, x1, y1, x2, y2, val, zero, smalleps;
- float maxdim;
- long prev, nxt, i;
- short arc;
-
- x = xx[0].x;
- y = xx[0].y;
- minx = x;
- miny = y;
- maxx = leastx = x;
- maxy = leasty = y;
- *trk = 0;
- dirn = -1;
- zero = 0.0;
- eps = nueps;
-
- for(i = 1; i <= num; i++)
- {
- x = xx[i].x;
- y = xx[i].y;
- if(x < minx && !requal(minx, x, TRUNC_EPS))
- {
- minx = x;
- miny = y;
- *trk = i;
- }
- else
- {
- if (requal(minx, x, TRUNC_EPS))
- {
- if(y < miny)
- {
- miny = y;
- *trk = i;
- }
- }
- }
- if(x < leastx)
- leastx = x;
- if(y <leasty)
- leasty = y;
- if(x > maxx)
- maxx = x;
- if(y > maxy)
- maxy = y;
- }
- if(*trk == num)
- nxt = 0;
- else
- nxt = *trk + 1;
- if(*trk == 0)
- prev = num;
- else
- prev = *trk - 1;
- x1 = xx[prev].x;
- y1 = xx[prev].y;
- x2 = xx[nxt].x;
- y2 = xx[nxt].y;
- a1 = x2 - minx;
- b1 = y2 - miny;
- a2 = minx - x1;
- b2 = miny - y1;
- val = a1 * b2 - b1 * a2;
- smalleps = eps * sqrt(a1 * a1 + b1 * b1);
- if(c_reqa(&val, &zero, &smalleps))
- ;
- else
- if(val > 0.0)
- dirn = 1; /* clw */
- }
-
- /* set up the data structures */
-
- short
- frmary(xx, num)
- Ppts xx[];
- long num;
- {
- long i;
- Vptr vb, vutmp, tb, tmp;
- long trk;
- double x, y;
-
- detdir(xx, num, &trk);
- tb = NULL;
- vb = NULL;
- root = NULL;
- sb = NULL;
- i = trk;
- for(i = trk; i <= num; i++)
- {
- x = xx[i].x;
- y = xx[i].y;
- if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
- {
- off_err();
- return TRUE;
- }
- vi->x = x;
- vi->y = y;
- vi->flag = (short)i;
- vi->bg = xx[i].bg;
- vi -> nxt = vb;
- vb = vi;
- }
- if(trk != 0)
- {
- for(i = 0; i <= trk - 1; i++)
- {
- x = xx[i].x;
- y = xx[i].y;
- if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
- {
- off_err();
- return TRUE;
- }
- vi->x = x;
- vi->y = y;
- vi->flag = (short)i;
- vi -> nxt = vb;
- vb = vi;
- } /* if */
- } /* for */
- x = xx[trk].x;
- y = xx[trk].y;
- if ((vi = (Vptr)malloc(sizeof(Vertex))) == (Vptr)NULL)
- {
- off_err();
- return TRUE;
- }
- vi->x = x;
- vi->y = y;
- vi->flag = (short)trk;
- vi->nxt = vb;
- vb = vi;
- /* this is the time to eliminate any introduced co-linear pts.
- and avoid redundancies */
- if(vi->nxt->nxt->nxt == NULL)
- vi = NULL;
- else
- {
- vutmp = vi;
- rmcolin(&vutmp);
- vi = vutmp;
- vb = vi;
- if(dirn == 1) /* user draws clw. but pts stored cclw. rev the stuff */
- {
- tmp = vb;
- while(tmp)
- {
- vi = (Vptr)malloc(sizeof(Vertex));
- if (vi == (Vptr)NULL)
- {
- off_err();
- return TRUE;
- }
- vi->x = tmp->x;
- vi->y = tmp->y;
- vi->flag = tmp->flag;
- vi->nxt = tb;
- tb = vi;
- tmp = tmp->nxt;
- }
- vdump(vb);
- } /* if dirn */
- tmp = vi;
- /*
- while(tmp)
- {
- printf("vi x y %f %f\n", tmp->x, tmp->y);
- tmp = tmp->nxt;
- }
- */
- }
- return FALSE;
- }
-
- /* remove colinear points */
-
- rmcolin(curpt)
- Vptr *curpt;
- {
- Vptr sto, ntmp, tmp;
- short cur_code, loop, mcode;
- double eps, x, y, cur_m, cur_c, m, c, x_dif, y_dif;
-
- eps = nueps;
- tmp = *curpt;
- if(!tmp)
- return;
- if(tmp->nxt)
- {
- y_dif = tmp->nxt->y - tmp->y;
- x_dif = tmp->nxt->x - tmp->x;
- if(f_abs(x_dif) < ueps1)
- cur_code = 1;
- else
- {
- cur_code = 0;
- cur_m = y_dif / x_dif;
- cur_c = tmp->y - cur_m * tmp->x;
- }
- }
- while(tmp->nxt && tmp->nxt->nxt)
- {
- do
- {
- loop = 0;
- y_dif = tmp->nxt->nxt->y - tmp->nxt->y;
- x_dif = tmp->nxt->nxt->x - tmp->nxt->x;
- if(f_abs(x_dif) < ueps1)
- mcode = 1;
- else
- {
- mcode = 0;
- m = y_dif / x_dif;
- c = tmp->nxt->y - m * tmp->nxt->x;
- }
- if(cur_code == 1 && mcode == 1)
- {
- sto = tmp->nxt;
- tmp->nxt = sto->nxt;
- free(sto);
- sto = NULL;
- loop = 1;
- }
- else
- {
- if(cur_code == 0 && mcode == 0)
- {
- if(c_reqa(&cur_c, &c, &eps) && c_reqa(&cur_m, &m, &eps))
- {
- sto = tmp->nxt;
- tmp->nxt = sto->nxt;
- free(sto);
- sto = NULL;
- loop = 1;
- }
- }
- }
- }
- while(loop == 1 && tmp->nxt->nxt);
- cur_code = mcode;
- cur_m = m;
- cur_c = c;
- tmp = tmp->nxt;
- } /* while ends */
- /* we need to perform one last step to homogenize the data
- namely check the last two points with the last but one point */
- tmp = *curpt;
- if(tmp->nxt)
- {
- while(tmp->nxt->nxt)
- tmp = tmp->nxt;
- y_dif = tmp->nxt->y - tmp->y;
- x_dif = tmp->nxt->x - tmp->x;
- if(f_abs(x_dif) < ueps1)
- cur_code = 1;
- else
- {
- cur_code = 0;
- cur_m = y_dif / x_dif;
- cur_c = tmp->y - cur_m * tmp->x;
- }
- ntmp = *curpt;
- y_dif = ntmp->nxt->y - ntmp->y;
- x_dif = ntmp->nxt->x - ntmp->x;
- if(f_abs(x_dif) < ueps1)
- mcode = 1;
- else
- {
- mcode = 0;
- m = y_dif / x_dif;
- c = ntmp->y - m * ntmp->x;
- }
- if(cur_code == 1 && mcode == 1)
- {
- sto = ntmp->nxt;
- free(*curpt);
- *curpt = sto;
- tmp->nxt->x = sto->x;
- tmp->nxt->y = sto->y;
- }
- else
- {
- if(cur_code == 0 && mcode == 0)
- {
- if(c_reqa(&cur_c, &c, &eps) && c_reqa(&cur_m, &m, &eps))
- {
- sto = ntmp->nxt;
- free(*curpt);
- *curpt = sto;
- tmp->nxt->x = sto->x;
- tmp->nxt->y = sto->y;
- }
- }
- }
- }
- }
-
- /* free the vertices (list) */
-
- vdump(vb)
- Vptr vb;
- {
- if(vb)
- {
- vdump(vb->nxt);
- free(vb);
- vb = NULL;
- }
- }
-
-
- /* initialize the data */
-
- inidata()
- {
- i2 = 1;
- if ((root = treealloc(0l)) == NULL)
- return;
- if ((sb = (Stptr) malloc(sizeof (Store))) == (Stptr)NULL)
- {
- off_err();
- return;
- }
- sb -> ptr = root;
- sb -> pid = root;
- sb -> nxt = NULL;
- root -> vtx = vi;
- scur = sb;
- }
-
-
- /*
- * u - given pt: v - nxt pt:w - index thru remaining pts.
- * algorithm -> if cross product of vec[u, v] and vec [u, w] pts. out
- * v forms a dip
- */
-
- Vptr lmost(u) /* function which dets. the next leftmost value */
- Vptr u;
- {
- double a1, a2, b1, b2; /* i,j components of the vectors */
- Vptr v, w;
-
- if(u -> nxt -> nxt == 0)
- v = u -> nxt;
- else
- {
- v = u -> nxt;
- a1 = v -> x - u -> x;
- a2 = v -> y - u -> y;
- w = v -> nxt;
- do
- {
- b1 = w -> x - u -> x;
- b2 = w -> y - u -> y;
- if(a1 * b2 - a2 * b1 > 0.0)
- {
- v = w;
- a1 = b1;
- a2 = b2;
- }
- w = w -> nxt;
- }
- while(w);
- }
- return(v);
- }
-
- /* main recursive function which runs thru stored data */
-
- traverse()
- {
- Stptr r;
-
- do
- {
- r = sb;
- process(r);
- sb = sb -> nxt;
- free(r);
- r = NULL;
- }
- while(sb);
- }
-
- Tnptr maketree(u, v, ptr, cod) /* makes tree */
- long cod; /* code for un or dif */
- Tnptr ptr; /* present tree pointer */
- Vptr u, v; /* ptrs to rel. vtx info. */
- {
- Tnptr q, r;
- Stptr s;
- Vptr ncopy();
-
- if ((q = treealloc(cod)) == (Tnptr)NULL)
- return (Tnptr)NULL;
- if ((r = treealloc(cod)) == (Tnptr)NULL)
- return (Tnptr)NULL;
- if(scur -> ptr == root)
- {
- q -> lft = root;
- root = q;
- root -> idx = -1L; /* Sub */
- q -> lft -> lft = NULL;
- q -> lft -> rht = NULL;
- root->vtx = NULL;
- }
- else
- {
- if(cod == 1)
- {
- q -> lft = r;
- ptr -> rht = q;
- r -> vtx = ncopy(u, v);
- r -> op = 0L; /* prim */
- if ((s = (Stptr) malloc(sizeof (Store))) == (Stptr)NULL)
- {
- off_err();
- return (Tnptr)NULL;
- }
- s -> ptr = q;
- s -> pid = r;
- s -> nxt = NULL;
- scur -> nxt = s;
- scur = scur -> nxt;
- }
- else
- {
- q -> lft = ptr -> lft;
- ptr -> lft = q;
- }
- }
- return(q);
- }
-
- static Tnptr /* allocate the tree node */
- treealloc(cod)
- long cod;
- {
- Tnptr t;
- static char *fname = /*MSG40*/"treealloc";
-
- if((t = (Tnptr)malloc(sizeof(Trenod))) == NULL)
- {
- off_err();
- return(NULL);
- }
- t -> vtx = NULL;
- t -> lft = NULL;
- t -> rht = NULL;
- t -> op = cod;
- t -> idx = -1l;
- t -> id = 0L;
- return(t);
- }
-
- process(cur) /* process current storage data ptr for convex hull */
- Stptr cur;
- {
- Tnptr r, t, maketree();
- Vptr u, v, w, p, lmost(); /* vertex data ptrs */
- double fact = 1.5;
- double pt1[2], pt2[2];
- short chk_mor(), l;
-
- if ((t = maketree(0L, 0L, cur -> ptr, -1L)) == (Tnptr)NULL)
- return;
- u = cur -> pid -> vtx;
- if(u)
- {
- while(u -> nxt)
- {
- v = lmost(u);
- if(u -> nxt != v) /* concavity found */
- {
- r = maketree(u, v, t, 1L);
- /* fix u and v points */
- w = v->nxt;
- if (!w)
- w = cur->pid->vtx->nxt;
- p = w;
- get_opnt(w->x, w->y, v->x, v->y, pt2, -fact);
- if (u == cur->pid->vtx)
- for (w = u; w->nxt->nxt != (Vptr)NULL; w = w->nxt);
- else
- for (w = cur->pid->vtx; w->nxt != u; w = w->nxt);
- get_opnt(w->x, w->y, u->x, u->y, pt1, -fact);
- l = chk_mor (p, v, w, u, pt1, pt2, fact);
- v->x = pt2[0]; v->y = pt2[1];
- if (!(v->nxt)) /* update 1st pt also */
- {
- cur->pid->vtx->x = v->x;
- cur->pid->vtx->y = v->y;
- }
- u->x = pt1[0]; u->y = pt1[1];
- if (u == cur->pid->vtx) /* update last pt also*/
- {
- w->nxt->x = u->x;
- w->nxt->y = u->y;
- if (l)
- {
- cur->pid->vtx = u->nxt;
- free (u);
- p = w->nxt;
- w->nxt = (Vptr)NULL;
- free (p);
- }
- }
- else if (l)
- {
- w->nxt = v;
- free (u);
- }
- if (r == (Tnptr)NULL)
- return;
- t = r;
- }
- u = v;
- }
- }
- }
-
- /*
- * Find the intersection point. If this is at a smaller distance than
- * p1 or p2. Equate p1 and p2 to this point.
- */
-
- short
- chk_mor(p, v, w, u, pt1, pt2, fact)
- Vptr p, v, w, u;
- ads_real fact, pt1[2], pt2[2];
- {
- Point p1, p2;
- Line l1, l2;
- #ifdef __WATCOMC__
- ads_real dist;
- #else
- ads_real dist, sqrt();
- #endif /* WATCOMC */
- short st_line();
- extern ads_real off_dist;
-
- p1.x = p->x; p1.y = p->y;
- p2.x = v->x; p2.y = v->y;
- if (!st_line(p1, p2, &l1))
- return 0;
- p1.x = w->x; p1.y = w->y;
- p2.x = u->x; p2.y = u->y;
- if (!st_line(p1, p2, &l2))
- return 0;
-
- if(requal(l1.a * l2.b, l1.b * l2.a, EXT_EPS))
- return 0; /* parallel lines */
- /* intersection point now */
- p1.x = (l2.c * l1.b - l1.c * l2.b) / (l1.a * l2.b - l2.a * l1.b) ;
- p1.y = (l1.c * l2.a - l2.c * l1.a) / (l1.a * l2.b - l2.a * l1.b) ;
- fact = off_dist*f_abs(fact);
- p2.x = p1.x - v->x; p2.y = p1.y - v->y;
- dist = sqrt((p2.x*p2.x) + (p2.y*p2.y));
- if (dist < fact)
- {
- pt1[0] = p1.x; pt1[1] = p1.y;
- pt2[0] = p1.x; pt2[1] = p1.y;
- return 1;
- }
- p2.x = p1.x - u->x; p2.y = p1.y - u->y;
- dist = sqrt((p2.x*p2.x) + (p2.y*p2.y));
- if (dist < fact)
- {
- pt1[0] = p1.x; pt1[1] = p1.y;
- pt2[0] = p1.x; pt2[1] = p1.y;
- return 1;
- }
- return 0;
- }
-
- Vptr ncopy(u, v) /* copies the list from u, v in reverse order */
- Vptr u, v;
- {
- Vptr temp, t, tb;
- double pt1[2], pt2[2];
- double fact = 100.0; /* *FHACK* */
-
- /*
- * Instead of this hard coded number it is probably better to tie
- * this to the largest dimension of the box. You have to tweak this
- * number for drawing with big dimensions.
- */
- tb = NULL;
- t = u;
- get_opnt(u->nxt->x, u->nxt->y, u->x, u->y, pt1, fact);
- do
- {
- if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
- {
- off_err();
- return (Vptr)NULL;
- }
- if (t != u)
- {
- temp -> x = t -> x;
- temp -> y = t -> y;
- }
- else
- {
- temp -> x = pt1[0];
- temp-> y = pt1[1];
- }
- temp -> nxt = tb;
- tb = temp;
- t = t -> nxt;
- }
- while(t->nxt != v);
- if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
- {
- off_err();
- return (Vptr)NULL;
- }
- temp -> x = t -> x;
- temp -> y = t -> y;
- temp -> nxt = tb;
- tb = temp;
- get_opnt(t->x, t->y, v->x, v->y, pt2, fact);
- if ((temp = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
- {
- off_err();
- return (Vptr)NULL;
- }
- temp -> x = pt2[0];
- temp -> y = pt2[1];
- temp -> nxt = tb;
- tb = temp;
- if ((t = (Vptr) malloc(sizeof (Vertex))) == (Vptr)NULL)
- {
- off_err();
- return (Vptr)NULL;
- }
- t -> x = pt1[0];
- t -> y = pt1[1];
- t -> nxt = tb;
- tb = t;
- /* all the values are copied now : modify original list */
- temp = u -> nxt;
- u -> nxt = v;
- ndump(temp, v);
- return(t);
- }
-
- /* offset the lines by the given factor and compute the intersection pt. */
-
- get_opnt(x1, y1, x2, y2, pt, fact)
- double x1, y1, x2, y2;
- double pt[2];
- double fact;
- {
- extern ads_real off_dist;
- #ifdef __WATCOMC__
- double u[2], v[2], dist;
- #else
- double u[2], v[2], dist, sqrt();
- #endif /* WATCOMC */
- int i1 = 0, i2 = 1;
-
- fact *= off_dist;
- v[0] = x2 - x1;
- v[1] = y2 - y1;
- dist = sqrt(v[0] * v[0] + v[1] * v[1]);
- v[0] /= dist; v[1] /= dist;
- if (fact > 0)
- {
- ;
- }
- else
- fact = f_abs(fact);
- pt[0] = x2 + (v[0]*fact);
- pt[1] = y2 + (v[1]*fact);
- }
-
- ndump(a, b) /* free storage from a to b */
- Vptr a, b;
- {
- Vptr temp;
-
- while(a != b)
- {
- temp = a -> nxt;
- free(a);
- a = temp;
- }
- }
-
- short
- treeprint(pt, val) /* go through the tree and prepare a CSG file */
- Tnptr pt;
- int val;
- {
- short outprim();
-
- if(pt)
- {
- if(pt -> op != 0)
- {
- val *= pt->op;
- if(pt -> rht)
- {
- if (treeprint(pt -> rht, val))
- return TRUE;
- treeprint(pt -> lft, val);
- if(pt->op == -1) /* diff */
- {
- if(pt->lft->id && pt->rht->id)
- pt->id = mknbl((ap_Objid)pt->lft->id, (ap_Objid)pt->rht->id, OP_DIF);
- else
- {
- pt->id = pt->lft->id;
- if(!pt->id)
- pt->id = pt->rht->id;
- }
- }
- else /* Union */
- {
- if(pt->lft->id && pt->rht->id)
- pt->id = mknbl((ap_Objid)pt->lft->id, (ap_Objid)pt->rht->id, OP_UN);
- else
- {
- pt->id = pt->lft->id;
- if(!pt->id)
- pt->id = pt->rht->id;
- }
- }
- }
- else
- {
- treeprint(pt -> lft, val);
- pt->id = pt->lft->id;
- }
- }
- else
- if (outprim(pt, val))
- return TRUE;
- }
- return FALSE;
- }
-
- short
- outprim(pt, val) /* make edge polys and store ids -> no arcs */
- Tnptr pt;
- int val; /* offset val */
- {
-
- ads_name ename;
- long do_prim();
- Vptr u;
-
- u = pt -> vtx;
- rmcolin(&u); /* remove colinear points */
- if(u && u->nxt && u->nxt->nxt)
- pt->id = do_prim(u, val);
- else
- off_err();
- if (!pt->id)
- return TRUE;
- else
- return FALSE;
- }
-
-
- /* ==================== BUILD POLY =================== */
-
- /* build polygon from vertices data structs */
-
- build_poly(u)
- Vptr u;
- {
- Vptr tmp;
- int cnt, i, poly_build(), seq_end(), status;
- struct resbuf *entlist, rb;
- ads_point pnt;
- ads_real lmin[2], lmax[2];
-
- cen[0] = cen[1] = 0.0, cnt = 0;
-
- if (ads_getvar(/*MSG0*/"LIMMIN", &rb) < 0)
- off_err();
- lmin[0] = rb.resval.rpoint[0]; lmin[1] = rb.resval.rpoint[1];
- if (ads_getvar(/*MSG0*/"LIMMAX", &rb) < 0)
- off_err();
- lmax[0] = rb.resval.rpoint[0]; lmax[1] = rb.resval.rpoint[1];
-
- /* In this case we know how points are */
- if (!poly_build())
- return;
- fsp[0] = u->x; fsp[1] = u->y;
- snd[0] = u->nxt->x; snd[1] = u->nxt->y;
- plim[0] = 0.0; plim[1] = 0.0;
- for (tmp = u; tmp->nxt != (Vptr)NULL; tmp = tmp->nxt)
- {
- cnt++;
- pnt[X] = tmp->x; pnt[Y] = tmp->y;
- pnt[Z] = 0.0;
- /*
- * Since the offset command expects a point on the object
- * well within limits for its selection. Make sure that we
- * get such a point and store.
- */
- /*
- * Plim is really not needed anymore as the entity name
- * can be passed before any point for the offset command
- */
- if (pnt[0] > lmin[0] && pnt[1] > lmin[1] && pnt[0] < lmax[0]
- && pnt[1] < lmax[1])
- {
- plim[0] = pnt[0];
- plim[1] = pnt[1];
- }
- cen[X] += pnt[X]; cen[Y] += pnt[Y];
- tmp->bg = 0.0;
- if ((vert_build(pnt, tmp->bg, 1))!= RTNORM)
- return;
- }
- if (!seq_end())
- return;
- cen[X] /= cnt; cen[Y] /= cnt;
- }
-
- /* build polyline entity */
-
- int
- poly_build()
- {
- int status;
- struct resbuf *entlist;
-
- entlist = ads_buildlist(RTDXF0, /*MSG0*/"POLYLINE", /* Type of entity */
- 8, name, /* layer name */
- 210, vec, /* entity vector */
- 66, 1, /* vertices follow */
- 70, 1, /* close polyline */
- NULL ); /* end */
- if (entlist == NULL)
- ads_fail(/*MSG41*/"Unable to create result buffer list.");
- status = ads_entmake(entlist);
- ads_relrb(entlist); /* Rel. ads_entmake() buffer */
- if (status != RTNORM){
- ads_fail (/*MSG42*/"Unable to make polyline entity.");
- return 0;
- }
- return 1;
- }
-
- /* build vertex entities */
-
- int
- vert_build(pnt, bg, idx)
- ads_point pnt;
- ads_real bg;
- int idx;
- {
- int status;
- struct resbuf *entlist;
-
- /*
- bg = 0.0;
- */
- trans_euwpt(pnt, idx, FALSE);
- entlist = ads_buildlist(RTDXF0, /*MSG0*/"VERTEX", /* Type of entity */
- 8, name, /* layer name */
- 10, pnt, /* point */
- 42, bg, /* bulge factor */
- NULL ); /* end */
-
-
- if (entlist == NULL)
- ads_fail(/*MSG43*/"Unable to create result buffer list.");
- status = ads_entmake(entlist);
- ads_relrb(entlist); /* Rel. ads_entmake() buffer */
- if (status != RTNORM){
- ads_fail (/*MSG44*/"Unable to make vertex entity.");
- return 0;
- }
- return status;
- }
-
- /* build seq_end part */
-
- int
- seq_end()
- {
- int status;
- struct resbuf *entlist;
-
- /* We want to end the list now */
- entlist = ads_buildlist(RTDXF0, /*MSG0*/"SEQEND", /* Type of entity */
- 8, name, /* layer name */
- NULL ); /* end */
-
-
- if (entlist == NULL)
- ads_fail(/*MSG45*/"Unable to create result buffer list.");
- status = ads_entmake(entlist);
- ads_relrb(entlist); /* Rel. ads_entmake() buffer */
- if (status != RTNORM){
- ads_fail (/*MSG46*/"Unable to make SEQEND.");
- return 0;
- }
- return 1;
- }
-
- short
- off_set (ename, val) /* go through the tree and off_set */
- ads_name ename;
- int val;
- {
- int i;
- ads_real avg[2];
- short off_debug = 1;
- short chk_shrink();
- ads_name e1;
- int test;
-
- val *= is_exp;
- /* come up with the point */
-
- if (val == -1) /* shrink */
- {
- test = ads_command (RTSTR, /*MSG47*/"_.OFFSET", RTREAL, off_dist, RTENAME, ename, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
- if (test != RTNORM)
- {
- ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
- exit(1);
- }
- /* we have to check if we got a proper offset or not */
- ads_entlast (e1);
- if (!chk_shrink(ename, e1))
- {
- ads_command (RTSTR, /*MSG48*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
- return FALSE; /* done */
- }
- }
- else /* expand */
- {
- avg[0] = (fsp[0]+snd[0])/2.0;
- avg[1] = (fsp[1]+snd[1])/2.0;
- cen[0] = 2*avg[0] - cen[0];
- cen[1] = 2*avg[1] - cen[1];
- test = ads_command (RTSTR, /*MSG49*/"_.offset", RTREAL, off_dist, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
- if (test != RTNORM)
- {
- ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
- exit(1);
- }
- }
- if (off_debug)
- ads_command (RTSTR, /*MSG50*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
- return TRUE;
- }
-
- /* build the convex hull object */
-
- long
- do_prim(u, val)
- Vptr u;
- int val;
- {
- ads_name ename;
- ap_Objid obj;
- short off_set(), cde;
-
- build_poly(u);
- ads_entlast(ename);
- cde = off_set(ename, val); /* no proper offset */
- if (!cde)
- return 0L;
- ads_entlast(ename);
- if (ap_solidify(ename, &obj) != AP_NORMAL)
- off_err();
- ads_command (RTSTR, /*MSG51*/"_.erase", RTENAME, ename, RTSTR, "", NULL);
- return (long)obj;
- }
-
- /* create csg branch node with appropriate operator */
-
- long
- mknbl(ob1, ob2, op)
- ap_Objid ob1, ob2;
- short op;
- {
- ap_Objid objs[3], obj;
- ads_name en1, en2;
-
- objs[0] = ob1;
- objs[1] = ob2;
- objs[2] = (ap_Objid)NULL;
- if (op == 1)
- ap_union(objs, &obj);
- else
- ap_subtract(ob1, ob2, &obj);
- ap_post_obj(obj, AP_POSTWIRE);
- return (long)obj;
- }
-
- /* convert the object to poly */
-
- Entsp
- obj2ply(enm, obj, flag)
- ads_name enm;
- ap_Objid obj;
- short flag;
- {
- ap_Edgelist *elist, *slist;
- ap_Objinfo info;
- ap_Featid *llist, *temp;
- int polt_build(), seq_end(), vert_build();
- ads_real bg, get_bg();
- extern int is_tool;
- ads_name e1;
- ap_Objid ob1, obs[3];
- Entsp eb = (Entsp)NULL, et, new_entsp();
- ads_real x1, y1, x2, y2, x3, y3;
-
- if (!obj || is_tool == -1)
- return NULL;
- obs[2] = (ap_Objid)NULL;
- if (ap_get_objinfo(obj, &info) < 0)
- {
- off_err();
- return NULL;
- }
- if (info.isnull)
- {
- if (!is_tool)
- {
- ads_printf
- (/*MSG52*/"Resultant offset is NULL. Try a smaller offset distance...\n");
- ads_command(RTSTR,"_.ERASE", RTSTR, "_l", RTSTR, "", NULL);/* erase null symbol */
- return (Entsp)NULL;
- }
- else
- {
- off_dist /= 2.0;
- ap_del_obj(obj);
- et = new_entsp();
- et->nxt = eb;
- eb = et;
- eb->ename[0] = enm[0]; /* send back orig ent */
- eb->ename[1] = enm[1];
- return eb; /* try with a smaller offset HACK */
- }
- }
- if ((ap_obj2loops(obj, &llist) < 0))
- {
- off_err();
- return (Entsp)NULL;
- }
- for (temp = llist; *temp != (ap_Featid) NULL; temp++)
- {
- if (ap_loop2edges(obj, *temp, TRUE, &elist) < 0)
- {
- off_err();
- return (Entsp)NULL;
- }
- /* HACK for Circle */
-
- if (flag && !poly_build())
- return (Entsp)NULL;
- for (slist = elist; slist != NULL; slist = slist->edgenext)
- {
- /* assume object's edges are ordered */
- bg = 0.0;
- if (!bg && flag && !vert_build(slist->edge->s_pt, bg, 0))
- return (Entsp)NULL;
- }
- if (!flag && is_tool)
- do_mac(elist);
- free(elist);
- if (flag && !seq_end())
- return (Entsp)NULL;
- if (flag)
- {
- et = new_entsp();
- et->nxt = eb;
- eb = et;
- ads_entlast(e1);
- eb->ename[0] = e1[0];
- eb->ename[1] = e1[1];
- }
- }
- free(llist);
- ap_del_obj(obj);
- if (is_tool == -2)
- return (Entsp)NULL;
- else
- return eb;
- }
-
- /* simulate machining */
-
- do_mac(elist)
- ap_Edgelist *elist;
- {
- extern struct resbuf *tool_buf;
- struct resbuf *assoc_rb(), *trb;
- ap_Edgelist *slist;
- ads_point cen, fsp, pt;
- int i, j, cntr = 5;
- ads_real rad, theta, inc;
-
-
- ads_command(RTSTR, /*MSG53*/"_.REGEN", NULL);
- trb = assoc_rb(tool_buf, 10);
- for (i = 0; i < 3; i++)
- fsp[i] = trb->resval.rpoint[i] = elist->edge->s_pt[i];
- ads_entmod(tool_buf);
- for (slist = elist; slist != NULL; slist = slist->edgenext)
- {
- /* assume object's edges are ordered */
- for (i = 0; i < 3; i++)
- {
- if (slist->edgenext)
- pt[i] = (-slist->edge->s_pt[i]+slist->edgenext->edge->s_pt[i])/cntr;
-
- else
- pt[i] = (-slist->edge->s_pt[i]+fsp[i])/cntr;
- }
- for (i = 0; i < cntr; i++)
- {
- for (j = 0; j < 3; j++)
- trb->resval.rpoint[j] += pt[j];
- ads_entmod(tool_buf);
- }
- }
- }
-
- /* check if the offset is OK */
-
- short
- chk_off(e1, e2)
- ads_name e1, e2;
- {
- ads_name ename, e3;
- struct resbuf rb, *ebuf, *eb, *assoc_rb();
- ap_Class class;
- ap_Objid obj;
- ads_real zero = 0.0;
- ads_point p1, p2, p3;
- ap_Bool fpt = FALSE, spt = FALSE, tpt = FALSE, area = FALSE;
- short tri_test();
-
- /* check if e2 is proper
- 1) if it is closed
- 2) if the points are inside e1/ename or not */
-
- p1[2] = p2[2] = p3[2] = -1.0;
- ebuf = ads_entget(e2);
- if (!ebuf)
- return FALSE;
- eb = assoc_rb(ebuf, 0);
- if (strcmp(eb->resval.rstring, /*MSG0*/"POLYLINE") != 0)
- return FALSE;
- eb = assoc_rb(ebuf, 70);
- if (eb->resval.rint == 0) /* not closed */
- return FALSE;
- /* Make the outer one as an object */
- ads_command(RTSTR, /*MSG54*/"_.COPY", RTENAME, e1, RTSTR, "", RTSTR, "0, 0", RTSTR, "0, 0", NULL);
- ads_entlast(ename);
- if (ap_solidify(ename, &obj) != AP_NORMAL)
- return FALSE;
- #ifdef OLD
- /*
- * Check area now. Write a area computing routine to get rid of
- * command prompt messages from ACAD
- */
- ads_command(RTSTR, "_.AREA", RTSTR, "_e", RTENAME, e2, NULL);
- ads_getvar(/*MSG0*/"AREA", &rb);
- if(c_reqa(&(rb.resval.rreal), &zero, &eps))
- {
- ads_command(RTSTR, /*MSG55*/"_.ERASE", RTSTR, "_l", RTSTR, "", NULL);
- return FALSE;
- }
- #endif
- e3[0] = e2[0]; e3[1] = e2[1];
- while (ads_entnext(e3, e3) == RTNORM)
- {
- ebuf = ads_entget(e3);
- eb = assoc_rb(ebuf, 0);
- if (strcmp (eb->resval.rstring, /*MSG0*/"VERTEX") == 0)
- {
- eb = assoc_rb(eb, 10);
- if (!fpt) /* B.S. -> compute area */
- {
- Cpoint (p1, eb->resval.rpoint);
- fpt = TRUE;
- }
- else if (!spt)
- {
- Cpoint (p2, eb->resval.rpoint);
- spt = TRUE;
- }
- else if (!tpt)
- {
- Cpoint (p3, eb->resval.rpoint);
- tpt = TRUE;
- if (tri_test(p1, p2, p3))
- area = TRUE;
- }
- else if (!area)
- {
- Cpoint (p2, p3);
- Cpoint (p3, eb->resval.rpoint);
- if (tri_test(p1, p2, p3))
- area = TRUE;
- }
- /* classify point */
- trans_euwpt(eb->resval.rpoint, 1, TRUE);
- if (ap_class_pt(obj, eb->resval.rpoint, &class) != AP_NORMAL)
- {
- ap_del_obj(obj);
- ads_relrb(ebuf);
- return FALSE;
- }
- if (class != AP_INOBJECT)
- {
- ap_del_obj(obj);
- ads_relrb(ebuf);
- return FALSE;
- }
-
- }
- else
- if (strcmp (eb->resval.rstring, /*MSG0*/"SEQEND") == 0)
- break;
- }
- ap_del_obj(obj);
- ads_command(RTSTR, /*MSG55*/"_.ERASE", RTENAME, ename, RTSTR, "", NULL);
- ads_relrb(ebuf);
- if (!area)
- return FALSE;
- return TRUE;
- }
-
- /* CHK_SHRINK -- Check the shrink and see if it is valid
- -- If machined first time
- */
-
- short
- chk_shrink(e1, e2)
- ads_name e1, e2;
- {
- short chk_off(), val;
- ap_Objid obj;
- Entsp cde, obj2ply();
- int test;
-
- if (is_tool == -1)
- {
- ads_command (RTSTR, /*MSG56*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
- ads_printf (/*MSG57*/"Done machining\n");
- return FALSE;
- }
- val = chk_off(e1, e2);
- if (!val) /* bad offset */
- {
- ads_command (RTSTR, /*MSG58*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
- if (is_tool == 0) /* from offset command --> complain */
- {
- ads_printf
- (/*MSG59*/"\nBad offset. Try a smaller offset distance, parallel UCS, etc. ...\n");
- #ifdef OLD
- (/*MSG59*/"\nResultant offset is NULL. Try a smaller offset distance...\n");
- #endif
- is_tool = -1;
- return FALSE;
- }
- if (is_tool > 1) /* cutting the latter parts recurs till done HACK */
- {
- off_dist /= 2.0;
- test = ads_command (RTSTR, /*MSG60*/"_.offset", RTREAL, off_dist, RTPOINT, plim, RTPOINT, cen, RTSTR, "", NULL);
- if (test != RTNORM)
- {
- ads_printf ("Error in AutoCAD offsetting. Exiting...\n");
- exit(1);
- }
- ads_entlast(e2);
- /* do chk_off again */
- val = chk_off(e1, e2);
- if (!val)
- {
- ads_command (RTSTR, /*MSG61*/"_.erase", RTENAME, e2, RTSTR, "", NULL);
- is_tool = -1;
- return FALSE;
- }
- /* do tool movement again */
- if (ap_solidify(e2, &obj) != AP_NORMAL)
- {
- off_err();
- return TRUE;
- }
- cde = obj2ply(e2, obj, FALSE); /* tool movement */
- dump_ent(cde);
- is_tool = -2;
- return TRUE;
- }
- else if (is_tool == 1) /* no need to machine further */
- {
- ads_printf
- (/*MSG62*/"\nObject machined in one pass. No offsetting required...\n");
- ;
- /* machine the outer one at least once */
- /* is_tool = -1; */
- }
- return FALSE;
- }
- return TRUE;
- }
-
- /* allocate new Ents */
-
- Entsp
- new_entsp()
- {
- Entsp tmp;
- static char *fname = /*MSG63*/"new_entsp";
-
- if((tmp = (Entsp)malloc(sizeof(Ents))) == (Entsp)NULL)
- {
- ads_printf(/*MSG64*/"Out of memory...\n");
- return((Entsp)NULL) ;
- }
- tmp->ename[0] = 0L;
- tmp->ename[1] = 0L;
- tmp->nxt = (Entsp)NULL;
- return tmp;
- }
-
- /*
- * Get the equation of a straight line
- * passing through the given points.
- */
-
- short st_line(pt1, pt2, line)
- Point pt1, pt2;
- Line *line; /* equation is ax + by + c = 0 */
- {
-
- #ifdef __WATCOMC__
- double xd, yd;
- #else
- double sqrt(), xd, yd;
- #endif /* WATCOMC */
-
- if(requal(pt1.x, pt2.x, EXT_EPS) && requal(pt1.y, pt2.y, EXT_EPS))
- return(FALSE);
- line->x1 = pt1.x;
- line->y1 = pt1.y;
- line->x2 = pt2.x;
- line->y2 = pt2.y;
- xd = pt2.x - pt1.x;
- yd = pt2.y - pt1.y;
- line->len = sqrt((yd*yd) + (xd*xd));
- if(requal(pt1.x, pt2.x, EXT_EPS))
- {
- line->a = 1.0;
- line->b = 0.0;
- line->c = - pt1.x;
- return(TRUE);
- }
- if(requal(pt1.y, pt2.y, EXT_EPS))
- {
- line->a = 0.0;
- line->b = 1.0;
- line->c = - pt1.y;
- return(TRUE);
- }
- line->a = - (yd/xd);
- line->b = 1.0;
- line->c = - pt2.x * line->a - pt2.y;
- return(TRUE);
- }
-
- /*
- * Does the point lie on the line segment ?
- */
-
- short on_line(line, pt)
- Line line;
- Point pt;
- {
- double slope1, slope2;
- short in_between();
-
- if(requal(line.x2, line.x1, EXT_EPS) || requal(pt.x, line.x1, EXT_EPS))
- {
- if(requal(line.x2, line.x1, EXT_EPS) &&
- requal(pt.x, line.x1, EXT_EPS))
- {
- if(in_between(line.y1, line.y2, pt.y, EXT_EPS))
- return(TRUE);
- else
- return(FALSE);
- }
- else
- return(FALSE);
- }
- else
- {
- slope1 = (line.y2 - line.y1) / (line.x2 - line.x1);
- slope2 = (pt.y - line.y1) / (pt.x - line.x1);
- if(requal(slope1, slope2, EXT_EPS))
- if(in_between(line.x1, line.x2, pt.x, EXT_EPS))
- return(TRUE);
- return(FALSE);
- }
- }
-
- /*
- * Check if a number is in between 2 others
- * and not equal to either of them.
- *
- * **** Check if c is between a and b ******
- */
-
- short in_between(a, b, c, eps)
- double a, b, c, eps;
- {
- if (( c > a && c < b ) || ( c > b && c < a ))
- if ( !requal( c, a, eps ) && !requal( c, b, eps ))
- return TRUE;
- return FALSE;
- }
-
- /* utility function for tangent inverse to handle special cases */
-
- double
- asatan2(x, y)
- double x, y;
- {
- #ifndef __WATCOMC__
- double atan2(), fabs();
- #endif /* NOT WATCOMC */
-
- if ((fabs(x) < 1.0E-20) && (fabs(y) < 1.0E-20))
- return ASPI_2;
- else
- return atan2(x, y);
- }
-
- /* utility function for cosine inverse to handle special cases */
-
- double
- asacos(p)
- double p;
- {
- #ifndef __WATCOMC__
- double acos();
- #endif /* NOT WATCOMC */
-
- if (p > 1.0)
- return 0.0;
-
- if (p < -1.0)
- return ASPI;
-
- return acos(p);
- }
-
- /* utility function to compare two real numbers eqality within the epsilon */
-
- short
- requal(val1, val2, eps)
- double val1, val2, eps;
- {
- return (c_reqa(&val1, &val2, &eps));
- }
-
- /* tri_test() uses the signed_area of a triangle as a test whether
- three points in a plane are oriented in a CCW or CW direction */
-
- short
- tri_test(p1, p2, p3) /* 2D signed area: if > 0, then p1,p2 and p3 are CCW */
- ads_real *p1, *p2, *p3;
- {
- ads_real s_area;
- ads_real zero = 0.0;
- ads_real epsi;
- epsi = (ads_real)TRUNC_EPS;
-
- s_area = ((p3[0] - p1[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p3[1] - p1[1]));
- /* evaluate the determinant */
-
- if (c_reqa (&s_area, &zero, &epsi))
- return 0; /* straight line */
- if (s_area < 0)
- return 1; /* CCW */
- return -1;
- }
-
- /* EOF */
-