/* "UNTIL", a graphics editor, Copyright (C) 1985, 1990 California Institute of Technology. Original authors: Glenn Gribble, port by Steve DeWeerth Unix Port Maintainer: John Lazzaro Maintainers's address: lazzaro@hobiecat.cs.caltech.edu; CB 425 CU Boulder/Boulder CO 91125. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation (Version 1, 1989). This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*******************************************************************************/ /* */ /* file contains stuff to draw and edit primatives (lines, boxes, etc.) */ /* cleaned up by steve - 10 May 1990 */ /* */ /*******************************************************************************/ #include #include "prim_stuff.h" #ifndef SYSDEVS_H #include #endif #define max_segs 40 /* Maximum number of segments in wide stuff */ #define max_vecs (max_segs * 2 + 10) typedef long int_array[max_vecs]; typedef enum { mk_line, /* Only draw a line to this point */ mk_curve /* Draw a curve using this point */ } markKinds; typedef markKinds int_marks[max_vecs]; /* Information about a line segment/endpoint */ typedef struct seg_info { long x1, y1; /* First Endpoint (second in next record) */ double a, b, c; /* As in: Ax+By+C=0 */ double r; /* Length of line, ð(A^2+B^2) */ double wx, wy; /* Width vector perp to line */ double c1, c2; /* C's for parallel lines */ double sx, sy; /* Perpendicular side vector */ } seg_info; Char tmptext[256]; object *deleted; boolean add_point; /* Add points to lines?? */ boolean del_point; /* Delete points from lines?? */ lineType newLine; /* What kind of line are we making? */ long plotColor, plotPriority; /* What levels to draw currently */ boolean forceToGrid; /* Force things to grid? */ textState showTextState; /* Text display state */ bbrec plotArea; /* The screen plotting area */ Static seg_info parts[20]; Static long nparts, width; Static void *primInfo[10]; /* mark that current figure has been changed. */ void changed(void) { curFigure->changes++; } /* Copy the object pointed to and insert in the data structure. */ /* Return a pointer to the new object. */ object *copyObj(object *op) { object *op1, *n, *p; pnt_elem *p1, *p2; changed(); if (op->kind == o_base) return NULL; op1 = getprim(op->kind, 0, 0, 0, 0); /* Save these fields */ n = op1->next; p = op1->prev; /* Copy all data */ memmove((long *)op1, (long *)op, primBytes(op->kind)); /* Now restore links */ op1->next = n; op1->prev = p; /* Now copy special case stuff */ if (op->kind != pr_line) /* copy segments */ return op1; p1 = op->okind.l.pnts; op1->okind.l.pnts = Malloc(sizeof(pnt_elem)); *op1->okind.l.pnts = *p1; p1 = p1->next; p2 = op1->okind.l.pnts; while (p1 != NULL) { p2->next = Malloc(sizeof(pnt_elem)); *p2->next = *p1; p1 = p1->next; p2 = p2->next; } return op1; } void setup(long x, long y, objkinds kind) { pib pb; pb.x1 = x; pb.y1 = y; pb.req = p_setup; ((void(*)(pib *pb))primInfo[(long)kind])(&pb); } /* Local variables for finishSetup: */ struct LOC_finishSetup { objkinds pk; } ; Local void rband(long a, long b, long c, long d, struct LOC_finishSetup *LINK) { pib p; p.x1 = a; p.y1 = b; p.x2 = c; p.y2 = d; p.req = p_rb; ((void(*)(pib *pb))primInfo[(long)LINK->pk])(&p); } Static void finishSetup(pib *pb, objkinds pk_) { struct LOC_finishSetup V; boolean good; _PROCEDURE TEMP; V.pk = pk_; TEMP.proc = rband; TEMP.link = &V; rubberBand(TEMP, pb->x1, pb->y1, &pb->x2, &pb->y2, &good); if (!good) return; pb->req = p_add; ((void(*)(pib *pb))primInfo[(long)V.pk])(pb); } void refObj(object *op) { pib pb; pb.req = p_refresh; pb.op = op; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); } void drawObj(object *op) { if (op->kind != o_base) objColor(op); refObj(op); } /* Rubberband this object. Leave it turned off when done. */ void rubberBand(_PROCEDURE proc, long sx, long sy, long *ex, long *ey, boolean *good) { long x, y, ox, oy; boolean first; long c; ox = sx; oy = sy; first = true; c = m_curcolor() & 15; do { update_tablet(); m_colormode(m_xor); m_color(c); /* If did-refresh during update_tablet, then first := true; */ if (curPen.didRef) first = true; if (curPen.moving || first) { m_nocursor(); if (!first) { if (proc.link != NULL) /* turn off */ ((void(*)(long sx, long sy, long ex, long ey, void *_link)) proc.proc)(sx, sy, ox, oy, proc.link); else ((void(*)(long sx, long sy, long ex, long ey))proc.proc)(sx, sy, ox, oy); } if (proc.link != NULL) /* turn on */ ((void(*)(long sx, long sy, long ex, long ey, void *_link))proc.proc)( sx, sy, curPen.x, curPen.y, proc.link); else ((void(*)(long sx, long sy, long ex, long ey))proc.proc)(sx, sy, curPen.x, curPen.y); mat_transform(curPen.x, curPen.y, &x, &y); m_cursor(x, y); ox = curPen.x; oy = curPen.y; first = false; } } while (!curPen.dn && curPen.near_); if (proc.link != NULL) /* turn off */ ((void(*)(long sx, long sy, long ex, long ey, void *_link))proc.proc)(sx, sy, ox, oy, proc.link); else ((void(*)(long sx, long sy, long ex, long ey))proc.proc)(sx, sy, ox, oy); *good = curPen.dn; *ex = ox; *ey = oy; restore_color(); m_nocursor(); } Static long isqrt(long i) { return ((long)floor(sqrt((double)(i)) + 0.5)); } void objColor(object *op) { color_rec *WITH; WITH = &op->color; m_color(WITH->value); } Static void p_none(pib *pb) { switch (pb->req) { case p_rb: printf("\007p_none(rb): I should not be called\n"); break; case p_add: printf("\007p_none(add): I should not be called\n"); break; case p_setup: printf("\007p_none(setup): I should not be called\n"); break; case p_refresh: printf("\007p_none(refresh): I should not be called\n"); break; case p_select: printf("\007p_none(select): I should not be called\n"); break; case p_edit: printf("\007p_none(edit): I should not be called\n"); break; case p_flash: printf("\007p_none(flash): I should not be called\n"); break; case p_move: printf("\007p_none(move): I should not be called\n"); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* NONE */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rb_none(long sx, long sy, long ex, long ey) { printf("rb_none: I should not be called\n"); } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* DOT */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rb_dot(long sx, long sy, long ex, long ey) { drawDot(ex, ey); } Static void p_dot(pib *pb) { object *o; boolean good; long x, y; pr_dot_rec *WITH; _PROCEDURE TEMP; object *WITH1; switch (pb->req) { case p_rb: drawDot(pb->x2, pb->y2); break; case p_add: o = make_dot(pb->x2, pb->y2); drawDot(pb->x2, pb->y2); break; case p_setup: m_nocursor(); m_colormode(m_normal); o = make_dot(pb->x1, pb->y1); drawDot(pb->x1, pb->y1); break; case p_flash: WITH = &pb->op->okind.d; drawDot(WITH->x, WITH->y); break; case p_refresh: WITH = &pb->op->okind.d; newpath(true); drawDot(WITH->x, WITH->y); finpath(); break; case p_select: /* if it got to here, then we are obviously selected */ pb->part = 1; WITH = &pb->op->okind.d; pb->area = labs(bbx - WITH->x) + labs(bby - WITH->y); break; case p_edit: objColor(pb->op); x = pb->x1; y = pb->y1; TEMP.proc = rb_dot; TEMP.link = NULL; rubberBand(TEMP, x, y, &x, &y, &good); if (good) { m_color(0); drawDot(x, y); pb->op->okind.d.x = x; pb->op->okind.d.y = y; newbb(&pb->op->bb, x, y, x, y); } break; case p_move: WITH1 = pb->op; WITH = &WITH1->okind.d; WITH->x += pb->x1; WITH->y += pb->y1; newbb(&WITH1->bb, WITH->x, WITH->y, WITH->x, WITH->y); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* ARROW */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* Draw a single arrow head at (sx,sy). Big deal. */ Static void arrowHead(long sx, long sy, long ex, long ey, long len, long wng) { long dx, dy, ax, ay, bx, by, r; dx = ex - sx; dy = ey - sy; r = isqrt(dx * dx + dy * dy); if (r == 0) { r = 1; dx = 1; dy = 0; } ax = len * dx; ay = len * dy; bx = -wng * dy; by = wng * dx; move_(sx + (ax + bx) / r, sy + (ay + by) / r); draw(sx, sy); draw(sx + (ax - bx) / r, sy + (ay - by) / r); } Static void doline(long x1, long y1, long x2, long y2, seg_info *l) { seg_info l1; double dc; l1.x1 = x1; l1.y1 = y1; /* Compute line equation */ l1.a = y2 - y1; l1.b = x1 - x2; l1.c = -x1 * l1.a - y1 * l1.b; l1.r = sqrt((double)(l1.a * l1.a + l1.b * l1.b)); if (l1.r == 0) { l1.a = 0.0; l1.b = -1.0; l1.r = 1.0; l1.c = -x1 * l1.a - y1 * l1.b; } /* Now make the perpendicular vector */ l1.wx = width * l1.a / l1.r; l1.wy = width * l1.b / l1.r; /* Compute constants for one parallel line WIDTH units away */ dc = width * l1.r; l1.c1 = l1.c - dc; /* Save the information */ *l = l1; } Static void intersect(seg_info *l1, seg_info *l2) { double den; /* denominator of computations */ den = l1->a * l2->b - l2->a * l1->b; if (den == 0) { /* Parallel lines, just use the W-values */ l2->sx = l1->wx; l2->sy = l1->wy; } else { /* Compute the delta-intersection of one side */ l2->sx = (l2->c1 * l1->b - l1->c1 * l2->b) / den - l2->x1; l2->sy = (l1->c1 * l2->a - l2->c1 * l1->a) / den - l2->y1; } } Static void add_seg_point(long x, long y) { nparts++; if (nparts > max_segs) { printf("Too many segments in wide thing, aborting\n"); _Escape(1); } /*mat_transform(x,y,x,y);*/ parts[nparts - 1].x1 = x; parts[nparts - 1].y1 = y; if (nparts > 1) doline(parts[nparts - 2].x1, parts[nparts - 2].y1, x, y, &parts[nparts - 2]); if (nparts > 2) intersect(&parts[nparts - 3], &parts[nparts - 2]); } /* Make a wide arrow head and append the vectors to the passed arrays */ Static void make_wideArrowHead(long sx, long sy, long ex, long ey, long wwid, long wlen, long wwng, _PROCEDURE add) { /* Just a procedure with x, y as parameters */ long dx, dy, ax, ay, bx, by, cx, cy, r, xx, yy; dx = ex - sx; dy = ey - sy; r = isqrt(dx * dx + dy * dy); if (r == 0) { r = 1; dx = 1; dy = 0; } /* wide arrows */ ax = wlen * dx; ay = wlen * dy; bx = -wwid * dy; by = wwid * dx; cx = -wwng * dy; cy = wwng * dx; xx = sx + (ax + bx) / r; yy = sy + (ay + by) / r; ((void(*)(double x, double y, markKinds m, void *_link))add.proc) (xx, yy, mk_curve, add.link); ((void(*)(double x, double y, markKinds m, void *_link))add.proc) (sx + (ax + bx + cx) / r, sy + (ay + by + cy) / r, mk_line, add.link); ((void(*)(double x, double y, markKinds m, void *_link))add.proc) (sx, sy, mk_line, add.link); ((void(*)(double x, double y, markKinds m, void *_link))add.proc) (sx + (ax - bx - cx) / r, sy + (ay - by - cy) / r, mk_line, add.link); ((void(*)(double x, double y, markKinds m, void *_link))add.proc) (sx + (ax - bx) / r, sy + (ay - by) / r, mk_line, add.link); } /* Local variables for makeWideArrow: */ struct LOC_makeWideArrow { long *xa, *ya; markKinds *ma; long n; } ; Local void add(double x, double y, markKinds m, struct LOC_makeWideArrow *LINK) { LINK->n++; LINK->xa[LINK->n - 1] = (long)floor(x + 0.5); LINK->ya[LINK->n - 1] = (long)floor(y + 0.5); LINK->ma[LINK->n - 1] = m; } Static void makeWideArrow(object *op, long *xa_, long *ya_, markKinds *ma_, long *num) { struct LOC_makeWideArrow V; pnt_elem *p; long i, m_wlen, m_wwid; markKinds points; pr_line_rec *WITH; pnt_elem *WITH1; _PROCEDURE TEMP; seg_info *WITH2; long FORLIM; V.xa = xa_; V.ya = ya_; V.ma = ma_; V.n = 0; nparts = 0; WITH = &op->okind.l; if (WITH->curve) points = mk_curve; else points = mk_line; /*mat_rtransform(lwid,lwid,width,width); */ /*mat_rtransform(wlen,wlen,m_wlen,m_wlen);*/ /*mat_rtransform(wwid,wwid,m_wwid,m_wwid);*/ width = WITH->lwid; m_wlen = WITH->wlen; m_wwid = WITH->wwid; p = WITH->pnts; while (p != NULL) { WITH1 = p; add_seg_point(WITH1->x, WITH1->y); p = WITH1->next; } if (nparts > 1) { V.n = 0; WITH = &op->okind.l; if (WITH->h1) { TEMP.proc = add; TEMP.link = &V; make_wideArrowHead(parts[0].x1, parts[0].y1, parts[1].x1, parts[1].y1, width, m_wlen, m_wwid, TEMP); } else { WITH2 = parts; add(WITH2->x1 + WITH2->wx, WITH2->y1 + WITH2->wy, mk_line, &V); } FORLIM = nparts - 2; for (i = 1; i <= FORLIM; i++) { WITH2 = &parts[i]; add(WITH2->x1 + WITH2->sx, WITH2->y1 + WITH2->sy, points, &V); } WITH = &op->okind.l; if (WITH->h2) { TEMP.proc = add; TEMP.link = &V; make_wideArrowHead(parts[nparts - 1].x1, parts[nparts - 1].y1, parts[nparts - 2].x1, parts[nparts - 2].y1, width, m_wlen, m_wwid, TEMP); } else { WITH2 = &parts[nparts - 1]; add(WITH2->x1 + parts[nparts - 2].wx, WITH2->y1 + parts[nparts - 2].wy, points, &V); add(WITH2->x1 - parts[nparts - 2].wx, WITH2->y1 - parts[nparts - 2].wy, mk_line, &V); } for (i = nparts - 2; i >= 1; i--) { WITH2 = &parts[i]; add(WITH2->x1 - WITH2->sx, WITH2->y1 - WITH2->sy, points, &V); } if (!op->okind.l.h1) { WITH2 = parts; add(WITH2->x1 - WITH2->wx, WITH2->y1 - WITH2->wy, points, &V); } } /* Copy the first point==auto-close this path */ V.n++; V.xa[V.n - 1] = V.xa[0]; V.ya[V.n - 1] = V.ya[0]; V.ma[V.n - 1] = V.ma[0]; *num = V.n; } /* Local variables for draw_pnts: */ struct LOC_draw_pnts { pnt_elem *p, *q, *r, *s; long i; boolean did; }; Local void onept(struct LOC_draw_pnts *LINK) { LINK->i++; LINK->did = false; switch (LINK->i) { case 1: LINK->p = LINK->s; break; case 2: LINK->q = LINK->s; break; case 3: LINK->r = LINK->s; break; case 4: if (LINK->q == NULL) LINK->q = LINK->p; if (LINK->r == NULL) LINK->r = LINK->q; if (LINK->s == NULL) LINK->s = LINK->r; bezier(LINK->p->x, LINK->p->y, LINK->q->x, LINK->q->y, LINK->r->x, LINK->r->y, LINK->s->x, LINK->s->y); LINK->p = LINK->s; LINK->q = NULL; LINK->r = NULL; LINK->i = 1; LINK->did = true; break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* LINE */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void draw_pnts(pnt_elem *first, boolean curve, boolean closed) { struct LOC_draw_pnts V; long np; pnt_elem *WITH; np = numpnts(first); if (closed) /* simulate extra point */ np++; if (!curve) { /* or (np<4) This looks like a line */ V.p = first; if (V.p != NULL) { WITH = V.p; move_(WITH->x, WITH->y); V.p = WITH->next; } while (V.p != NULL) { WITH = V.p; draw(WITH->x, WITH->y); V.p = WITH->next; } if (closed && first != NULL) draw(first->x, first->y); return; } V.s = first; V.p = NULL; V.q = NULL; V.r = NULL; V.i = 0; while (V.s != NULL) { onept(&V); V.s = V.s->next; } /* Done drawing normal curves, now check for last part */ if (closed) { V.s = first; onept(&V); V.s = NULL; } if (!V.did) { V.i = 3; onept(&V); } /* This is a curve (we hope) */ } Static void rf_line(object *op) { pnt_elem *p, *q; int_array xa, ya; long n, i; int_marks ma; pr_line_rec *WITH; WITH = &op->okind.l; if (WITH->lwid != 0) { /* Wide line/arrow */ newpath(true); makeWideArrow(op, xa, ya, ma, &n); move_(xa[0], ya[0]); i = 2; while (i <= n) { if (ma[i - 1] != mk_curve || i + 2 > n) { draw(xa[i - 1], ya[i - 1]); i++; continue; } if (ma[i] == mk_curve && ma[i + 1] == mk_curve) { /* Good curve */ bezier(xa[i - 2], ya[i - 2], xa[i - 1], ya[i - 1], xa[i], ya[i], xa[i + 1], ya[i + 1]); move_(xa[i + 1], ya[i + 1]); i += 3; continue; } if (ma[i] == mk_curve) { /* Wimpy Curve */ bezier(xa[i - 2], ya[i - 2], xa[i - 1], ya[i - 1], xa[i - 1], ya[i - 1], xa[i], ya[i]); move_(xa[i], ya[i]); i += 2; } else { /* No curve */ draw(xa[i - 1], ya[i - 1]); i++; } } finpath(); return; } /* Draw arrowHeads first, so they can get "closed" */ p = WITH->pnts; if (p != NULL && p->next != NULL) { if (WITH->h1) { q = p->next; newpath(false); /* Allow user to close heads */ arrowHead(p->x, p->y, q->x, q->y, WITH->wlen, WITH->wwid); finpath(); } if (WITH->h2) { q = p; p = p->next; while (p->next != NULL) { q = p; p = p->next; } newpath(false); /* Allow user to close heads */ arrowHead(p->x, p->y, q->x, q->y, WITH->wlen, WITH->wwid); finpath(); } } newpath(WITH->closed); draw_pnts(WITH->pnts, WITH->curve, WITH->closed); finpath(); /* Narrow arrow or line or polygon */ } Static void rb_line(long sx, long sy, long ex, long ey) { move_(sx, sy); draw(ex, ey); } /* Parts of a line -- 0 == nothing, 1==whole thing */ /* 100..?? == endpoints, 1000..?? == segments */ Static void sl_line(object *op, long *part, long *area) { long x1, y1; pnt_elem *p, *last; long pn; pr_line_rec *WITH; long TEMP; pnt_elem *WITH1; long TEMP1; bbrec *WITH2; WITH = &op->okind.l; *part = 0; p = WITH->pnts; pn = 100; /* First endpoint */ TEMP = bbrx; *area = TEMP * TEMP * 3; /* For the points */ while (p != NULL && *part == 0) { WITH1 = p; if (pntcheck(WITH1->x, WITH1->y)) *part = pn; pn++; p = WITH1->next; } if (*part != 0) /* We have not found anything yet */ return; pn = 1000; /* First segment */ p = WITH->pnts; if (p != NULL) { WITH1 = p; x1 = WITH1->x; y1 = WITH1->y; p = WITH1->next; } while (p != NULL && *part == 0) { WITH1 = p; /*$IF FALSE$ in_bb := bbxrcheck(x1,y1,x,y); if in_bb then begin m_color(1+16); move(x,y); draw(x1,y); draw(x1,y1); draw(x,y1); draw(x,y); end; $END$*/ if (bbxrcheck(x1, y1, WITH1->x, WITH1->y) && linecheck(x1, y1, WITH1->x, WITH1->y)) { TEMP = WITH1->x - x1; TEMP1 = WITH1->y - y1; *area = isqrt(TEMP * TEMP + TEMP1 * TEMP1) * bbrx; *part = pn; } x1 = WITH1->x; y1 = WITH1->y; pn++; last = p; p = WITH1->next; } if (*part == 0 && WITH->closed) { /* Check closing segment */ if (WITH->pnts != NULL) { WITH1 = WITH->pnts; if (bbxrcheck(x1, y1, WITH1->x, WITH1->y) && linecheck(x1, y1, WITH1->x, WITH1->y)) { TEMP = WITH1->x - x1; TEMP1 = WITH1->y - y1; *area = isqrt(TEMP * TEMP + TEMP1 * TEMP1) * bbrx; *part = pn; } } } /* For lack of anything else, select whole line. */ if (*part != 0) return; WITH2 = &op->bb; *part = 1; *area = (WITH2->xh - WITH2->xl) * (WITH2->yh - WITH2->yl); } /* Local variables for st_line: */ struct LOC_st_line { pnt_elem *e; long ox, oy; object *op; } ; Local void mv_linePoint(long sx, long sy, long ex, long ey, struct LOC_st_line *LINK) { long dx, dy; pnt_elem *WITH; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; WITH = LINK->e->next; WITH->x += dx; WITH->y += dy; rf_line(LINK->op); } Static void st_line(long x, long y) { struct LOC_st_line V; boolean good; pnt_elem *p; _PROCEDURE TEMP; p = make_pnt_elem(x, y); V.op = make_line(p, newLine); V.e = p; do { V.e->next = make_pnt_elem(x, y); V.ox = x; V.oy = y; TEMP.proc = mv_linePoint; TEMP.link = &V; rubberBand(TEMP, x, y, &V.ox, &V.oy, &good); if (good) { V.e = V.e->next; x = V.ox; y = V.oy; /*rf_line(op);*/ } } while (good); Free(V.e->next); V.e->next = NULL; if (V.e == p) /* No line segments entered. */ dispose_obj(V.op); else { set_line_mbb(&V.op->bb, V.op->okind.l.pnts); rf_line(V.op); } } /* Find an endpoint in this line - Return previous point, this point, and next point */ Static void find_point(object *op, long part, pnt_elem **prev, pnt_elem **this_, pnt_elem **next) { pnt_elem *p, *p1; long i; if (part < 100 || part >= 1000) { printf("find_point: Bad part #%ld\n", part); return; } p1 = NULL; p = op->okind.l.pnts; i = part - 100; while (i != 0 && p != NULL) { p1 = p; p = p->next; i--; } if (p == NULL) { printf("find_point: Part #%ld does not exist.\n", part); *prev = NULL; *this_ = NULL; *next = NULL; return; } *prev = p1; *this_ = p; *next = p->next; } /* Find a segment in this line */ /* Return previous point, first endpoint, second endpoint, and next point */ Static void find_segment(object *op, long part, pnt_elem **prev, pnt_elem **first, pnt_elem **second, pnt_elem **next) { pnt_elem *p, *p1; long i; if (part < 1000 || part > 2000) { printf("find_segment: Bad part #%ld\n", part); return; } p1 = NULL; p = op->okind.l.pnts; i = part - 1000; while (i != 0 && p != NULL) { p1 = p; p = p->next; i--; } if (p == NULL || p->next == NULL && !op->okind.l.closed) { printf("find_segment: Part #%ld does not exist.\n", part); return; } *prev = p1; *first = p; *second = p->next; if (*second == NULL) /* Closed thingy. */ *second = op->okind.l.pnts; *next = (*second)->next; } Static void mv_pnts(pnt_elem *p, long dx, long dy) { pnt_elem *WITH; while (p != NULL) { WITH = p; WITH->x += dx; WITH->y += dy; p = WITH->next; } } /* Local variables for ed_line: */ struct LOC_ed_line { object *op; long ox, oy, tdx, tdy; /* Total delta(x,y) */ pnt_elem *p, *q; } ; Local void mv_lineSegment(long sx, long sy, long ex, long ey, struct LOC_ed_line *LINK) { long dx, dy; pnt_elem *WITH; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; LINK->tdx += dx; LINK->tdy += dy; WITH = LINK->p; WITH->x += dx; WITH->y += dy; WITH = LINK->q; WITH->x += dx; WITH->y += dy; rf_line(LINK->op); } Local void mv_linePoint_(long sx, long sy, long ex, long ey, struct LOC_ed_line *LINK) { long dx, dy; pnt_elem *WITH; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; WITH = LINK->p; if (forceToGrid) { WITH->x = ex; WITH->y = ey; } else { WITH->x += dx; WITH->y += dy; } rf_line(LINK->op); } Local void mv_wholeLine(long sx, long sy, long ex, long ey, struct LOC_ed_line *LINK) { long dx, dy; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; LINK->tdx += dx; LINK->tdy += dy; mv_pnts(LINK->op->okind.l.pnts, dx, dy); rf_line(LINK->op); } Static void ed_line(object *op_, long ox_, long oy_, long part) { struct LOC_ed_line V; /*n:pr_line_rec;*/ boolean good; long origx, origy; /* original values for x,y for one point */ pnt_elem *o, *r; _PROCEDURE TEMP; pnt_elem *WITH; V.op = op_; V.ox = ox_; V.oy = oy_; objColor(V.op); /*n := op^.l; { get working copy */ if (part == 1) { V.tdx = 0; V.tdy = 0; TEMP.proc = mv_wholeLine; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (!good) mv_pnts(V.op->okind.l.pnts, -V.tdx, -V.tdy); } else if (part >= 100 && part < 1000) { find_point(V.op, part, &o, &V.p, &V.q); if (!del_point) { origx = V.p->x; origy = V.p->y; TEMP.proc = mv_linePoint_; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (!good) { WITH = V.p; WITH->x = origx; WITH->y = origy; } } else { if (o == NULL) /* START OF LIST */ V.op->okind.l.pnts = V.q; else /* MIDDLE OF LIST */ o->next = V.q; Free(V.p); /* Check to see if there really is a line/whatever left */ if (numpnts(V.op->okind.l.pnts) <= 1) { /* But we might (will) loose the */ delete__(V.op); /* memory for one point! ... Oh, well. */ printf("Deleted line segment.\n"); good = false; } else good = true; } } else if (part >= 1000 && part <= 2000) { find_segment(V.op, part, &o, &V.p, &V.q, &r); if (!add_point) { V.tdx = 0; V.tdy = 0; TEMP.proc = mv_lineSegment; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (!good) { WITH = V.p; WITH->x -= V.tdx; WITH->y -= V.tdy; WITH = V.q; WITH->x -= V.tdx; WITH->y -= V.tdy; } } else { o = V.p; V.p->next = Malloc(sizeof(pnt_elem)); V.p = V.p->next; /* Are we adding a point at the end of a closed thingy? */ if (V.q == V.op->okind.l.pnts) /* Closed thingy. */ V.p->next = NULL; else V.p->next = V.q; V.p->x = V.ox; V.p->y = V.oy; good = true; V.tdx = 0; V.tdy = 0; TEMP.proc = mv_linePoint_; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (!good) { /* Delete inserted point */ o->next = V.p->next; Free(V.p); } } } else printf("ed_line: Bad part #%ld\n", part); if (!good) return; m_color(0); rf_line(V.op); set_line_mbb(&V.op->bb, V.op->okind.l.pnts); } Static void fl_line(object *op, long part) { pnt_elem *o, *p, *q, *r; if (part == 1) { rf_line(op); return; } if (part >= 100 && part < 1000) { find_point(op, part, &o, &p, &q); showPoint(p->x, p->y); return; } if (part < 1000 || part > 2000) { printf("fl_line: Bad part #%ld\n", part); return; } find_segment(op, part, &o, &p, &q, &r); move_(p->x, p->y); draw(q->x, q->y); } Static void p_line(pib *pb) { object *WITH; pr_line_rec *WITH1; switch (pb->req) { case p_rb: rb_line(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_add: /* blank case */ break; /*add_line(pb.x1,pb.y1,pb.x2,pb.y2);*/ case p_setup: st_line(pb->x1, pb->y1); break; case p_refresh: rf_line(pb->op); break; case p_flash: fl_line(pb->op, pb->part); break; case p_select: sl_line(pb->op, &pb->part, &pb->area); break; case p_edit: ed_line(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.l; mv_pnts(WITH1->pnts, pb->x1, pb->y1); set_line_mbb(&WITH->bb, WITH1->pnts); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* BOX */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rf_box(object *op) { pr_box_rec *WITH; WITH = &op->okind.b; newpath(true); drawbox(WITH->x1, WITH->y1, WITH->x2, WITH->y2); finpath(); } Static void rb_box(long sx, long sy, long ex, long ey) { drawbox(sx, sy, ex, ey); } Static void sl_box(object *op, long *part, long *area) { pr_box_rec *WITH; WITH = &op->okind.b; *area = (WITH->x2 - WITH->x1) * (WITH->y2 - WITH->y1); if (pntcheck(WITH->x1, WITH->y1)) { *part = 2; return; } if (pntcheck(WITH->x1, WITH->y2)) { *part = 3; return; } if (pntcheck(WITH->x2, WITH->y2)) { *part = 4; return; } if (pntcheck(WITH->x2, WITH->y1)) { *part = 5; return; } if (bbbb.xl <= WITH->x1) { *part = 6; return; } if (bbbb.yh >= WITH->y2) { *part = 7; return; } if (bbbb.xh >= WITH->x2) { *part = 8; return; } if (bbbb.yl <= WITH->y1) *part = 9; else *part = 1; } /* Local variables for ed_box: */ struct LOC_ed_box { long ox, oy, part; pr_box_rec n; } ; Local void mv_box(long sx, long sy, long ex, long ey, struct LOC_ed_box *LINK) { sx = ex - LINK->ox; sy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; switch (LINK->part) { case 1: LINK->n.x1 += sx; LINK->n.x2 += sx; LINK->n.y1 += sy; LINK->n.y2 += sy; break; case 6: if (forceToGrid) LINK->n.x1 = ex; else LINK->n.x1 += sx; break; case 7: if (forceToGrid) LINK->n.y2 = ey; else LINK->n.y2 += sy; break; case 8: if (forceToGrid) LINK->n.x2 = ex; else LINK->n.x2 += sx; break; case 9: if (forceToGrid) LINK->n.y1 = ey; else LINK->n.y1 += sy; break; } drawbox(LINK->n.x1, LINK->n.y1, LINK->n.x2, LINK->n.y2); } Static void ed_box(object *op, long ox_, long oy_, long part_) { struct LOC_ed_box V; boolean good; _PROCEDURE TEMP; V.ox = ox_; V.oy = oy_; V.part = part_; objColor(op); V.n = op->okind.b; /* get working copy */ switch (V.part) { case 1: case 6: case 7: case 8: case 9: TEMP.proc = mv_box; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); break; case 2: TEMP.proc = rb_box; TEMP.link = NULL; rubberBand(TEMP, V.n.x2, V.n.y2, &V.n.x1, &V.n.y1, &good); break; case 3: TEMP.proc = rb_box; TEMP.link = NULL; rubberBand(TEMP, V.n.x2, V.n.y1, &V.n.x1, &V.n.y2, &good); break; case 4: TEMP.proc = rb_box; TEMP.link = NULL; rubberBand(TEMP, V.n.x1, V.n.y1, &V.n.x2, &V.n.y2, &good); break; case 5: TEMP.proc = rb_box; TEMP.link = NULL; rubberBand(TEMP, V.n.x1, V.n.y2, &V.n.x2, &V.n.y1, &good); break; default: printf("ed_box: Bad #%ld\n", V.part); good = false; break; } if (!good) return; m_color(0); rf_box(op); newbb(&op->bb, V.n.x1, V.n.y1, V.n.x2, V.n.y2); op->okind.b.x1 = op->bb.xl; op->okind.b.x2 = op->bb.xh; op->okind.b.y1 = op->bb.yl; op->okind.b.y2 = op->bb.yh; } Static void fl_box(object *op, long part) { pr_box_rec *WITH; WITH = &op->okind.b; switch (part) { case 1: rf_box(op); break; case 2: showPoint(WITH->x1, WITH->y1); break; case 3: showPoint(WITH->x1, WITH->y2); break; case 4: showPoint(WITH->x2, WITH->y2); break; case 5: showPoint(WITH->x2, WITH->y1); break; case 6: move_(WITH->x1, WITH->y1); draw(WITH->x1, WITH->y2); break; case 7: move_(WITH->x1, WITH->y2); draw(WITH->x2, WITH->y2); break; case 8: move_(WITH->x2, WITH->y2); draw(WITH->x2, WITH->y1); break; case 9: move_(WITH->x2, WITH->y1); draw(WITH->x1, WITH->y1); break; default: printf("fl_box: Bad part #%ld\n", part); break; } } Static void p_box(pib *pb) { object *WITH; pr_box_rec *WITH1; switch (pb->req) { case p_rb: rb_box(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_add: rf_box(make_box(pb->x1, pb->y1, pb->x2, pb->y2)); break; case p_setup: finishSetup(pb, pr_box); break; case p_refresh: rf_box(pb->op); break; case p_flash: fl_box(pb->op, pb->part); break; case p_select: sl_box(pb->op, &pb->part, &pb->area); break; case p_edit: ed_box(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.b; WITH1->x1 += pb->x1; WITH1->y1 += pb->y1; WITH1->x2 += pb->x1; WITH1->y2 += pb->y1; newbb(&WITH->bb, WITH1->x1, WITH1->y1, WITH1->x2, WITH1->y2); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* CIRCLE */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rf_circle(object *op) { pr_circle_rec *WITH; newpath(true); WITH = &op->okind.c; circle(WITH->cx, WITH->cy, WITH->r); finpath(); } Static void rb_circle(long sx, long sy, long ex, long ey) { long TEMP, TEMP1; TEMP = sx - ex; TEMP1 = sy - ey; circle(sx, sy, isqrt(TEMP * TEMP + TEMP1 * TEMP1)); } Static void add_circle(long sx, long sy, long ex, long ey) { long rad, TEMP, TEMP1; TEMP = sx - ex; TEMP1 = sy - ey; rad = isqrt(TEMP * TEMP + TEMP1 * TEMP1); rf_circle(make_circle(sx, sy, rad)); } Static void sl_circle(object *op, long *part, long *area) { long r2; pr_circle_rec *WITH; long TEMP, TEMP1; WITH = &op->okind.c; *area = WITH->r * WITH->r * 3; TEMP = bbx - WITH->cx; TEMP1 = bby - WITH->cy; r2 = TEMP * TEMP + TEMP1 * TEMP1; TEMP = WITH->r + bbrx; if (r2 > TEMP * TEMP) { *part = 0; return; } if (WITH->r < bbrx || r2 > (TEMP1 = WITH->r - bbrx, TEMP1 * TEMP1)) *part = 2; else *part = 1; } /* Local variables for ed_circle: */ struct LOC_ed_circle { long ox, oy; pr_circle_rec n; } ; Local void mv_circle(long sx, long sy, long ex, long ey, struct LOC_ed_circle *LINK) { sx = ex - LINK->ox; sy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; if (forceToGrid) { LINK->n.cx = ex; /* ex, ey are already on GRID */ LINK->n.cy = ey; } else { LINK->n.cx += sx; LINK->n.cy += sy; } circle(LINK->n.cx, LINK->n.cy, LINK->n.r); } Static void ed_circle(object *op, long ox_, long oy_, long part) { struct LOC_ed_circle V; boolean good; _PROCEDURE TEMP; long TEMP1, TEMP2; V.ox = ox_; V.oy = oy_; objColor(op); V.n = op->okind.c; /* get working copy */ switch (part) { case 1: TEMP.proc = mv_circle; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); break; case 2: TEMP.proc = rb_circle; TEMP.link = NULL; rubberBand(TEMP, V.n.cx, V.n.cy, &V.ox, &V.oy, &good); if (good) { TEMP1 = V.n.cx - V.ox; TEMP2 = V.n.cy - V.oy; V.n.r = isqrt(TEMP1 * TEMP1 + TEMP2 * TEMP2); } break; default: printf("ed_circle: Bad #%ld\n", part); good = false; break; } if (!good) return; m_color(0); rf_circle(op); op->okind.c = V.n; newbb(&op->bb, V.n.cx - V.n.r, V.n.cy - V.n.r, V.n.cx + V.n.r, V.n.cy + V.n.r); } Static void fl_circle(object *op, long part) { rf_circle(op); if (part == 1) showPoint(op->okind.c.cx, op->okind.c.cy); } Static void p_circle(pib *pb) { object *WITH; pr_circle_rec *WITH1; switch (pb->req) { case p_rb: rb_circle(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_add: add_circle(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_setup: finishSetup(pb, pr_circle); break; case p_refresh: rf_circle(pb->op); break; case p_flash: fl_circle(pb->op, pb->part); break; case p_select: sl_circle(pb->op, &pb->part, &pb->area); break; case p_edit: ed_circle(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.c; WITH1->cx += pb->x1; WITH1->cy += pb->y1; newbb(&WITH->bb, WITH1->cx - WITH1->r, WITH1->cy - WITH1->r, WITH1->cx + WITH1->r, WITH1->cy + WITH1->r); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* ELLIPSE */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rf_ellipse(object *op) { pr_ellipse_rec *WITH; WITH = &op->okind.e; newpath(WITH->l >= 360 || WITH->pie); ellipseArc(WITH->cx, WITH->cy, WITH->a, WITH->b, WITH->s, WITH->l, WITH->r, WITH->pie); finpath(); } Static void rb_ellipse(long sx, long sy, long ex, long ey) { ellipseArc(sx, sy, labs(ex - sx), labs(ey - sy), 0, 360, 0, false); } Static void add_ellipse(long sx, long sy, long ex, long ey) { rf_ellipse(make_ellipse(sx, sy, labs(ex - sx), labs(ey - sy), 0, 360, 0)); } Static void sl_ellipse(object *op, long *part, long *area) { /* simplist check there is, just bounding box */ *part = 1; *area = (op->bb.xh - op->bb.xl) * (op->bb.yh - op->bb.yl); } /* Local variables for ed_ellipse: */ struct LOC_ed_ellipse { object *op; long ox, oy; } ; Local void mv_ellipse(long sx, long sy, long ex, long ey, struct LOC_ed_ellipse *LINK) { long dx, dy; pr_ellipse_rec *WITH; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; WITH = &LINK->op->okind.e; if (forceToGrid) { WITH->cx = ex; /* ex, ey are already on GRID */ WITH->cy = ey; } else { WITH->cx += dx; WITH->cy += dy; } rf_ellipse(LINK->op); } Static void ed_ellipse(object *op_, long ox_, long oy_, long part) { struct LOC_ed_ellipse V; long ocx, ocy; /* Total delta(x,y) */ boolean good; _PROCEDURE TEMP; pr_ellipse_rec *WITH; V.op = op_; V.ox = ox_; V.oy = oy_; if (part == 1) { ocx = V.op->okind.c.cx; ocy = V.op->okind.c.cy; TEMP.proc = mv_ellipse; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (!good) { WITH = &V.op->okind.e; WITH->cx = ocx; WITH->cy = ocy; } } else printf("\007ed_ellipse: unknown part #%ld\n", part); set_ellipse_mbb(V.op); } Static void fl_ellipse(object *op, long part) { rf_ellipse(op); } Static void p_ellipse(pib *pb) { object *WITH; pr_ellipse_rec *WITH1; switch (pb->req) { case p_rb: rb_ellipse(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_add: add_ellipse(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_setup: finishSetup(pb, pr_ellipse); break; case p_refresh: rf_ellipse(pb->op); break; case p_flash: fl_ellipse(pb->op, pb->part); break; case p_select: sl_ellipse(pb->op, &pb->part, &pb->area); break; case p_edit: ed_ellipse(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.e; WITH1->cx += pb->x1; WITH1->cy += pb->y1; set_ellipse_mbb(pb->op); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* TEXT */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void rf_text(object *op) { pr_text_rec *WITH; WITH = &op->okind.t; if (showTextState == sts_none) return; newpath(false); chooseFont(WITH->font, WITH->scale, WITH->rot, WITH->slant); switch (showTextState) { case sts_words: drawText(WITH->x, WITH->y, WITH->orig, WITH->words); break; case sts_TeXwords: drawText(WITH->x, WITH->y, WITH->orig, WITH->TeXwords); break; } finpath(); } Static void st_text(long x, long y) { Char STR1[256]; Char STR2[256]; m_nocursor(); if (CURRENTCRT == ALPHATYPE) printf("\f"); nc_gotoXY(10, 3); printf("Enter text : "); boop(); gets(tmptext); printf("\037\t"); strcpy(STR1, strltrim(strrtrim(strcpy(STR2, tmptext)))); strcpy(tmptext, STR1); if (*tmptext != '\0') rf_text(make_text(x, y, tmptext)); } Static void rb_text(long sx, long sy, long ex, long ey) { chooseFont(curTextFont, curTextScale, curTextRot, curTextSlant); drawText(ex, ey, curTextOrig, tmptext); } Static void add_text(long sx, long sy, long ex, long ey) { rf_text(make_text(ex, ey, tmptext)); } Static void sl_text(object *op, long *part, long *area) { /* simplist check there is, just bounding box */ *part = 1; *area = 50; } Static void ed_text(object *op, long x, long y, long part) { boolean good; centerType saveOrig; _PROCEDURE TEMP; saveOrig = curTextOrig; objColor(op); strcpy(tmptext, op->okind.t.words); curTextOrig = op->okind.t.orig; TEMP.proc = rb_text; TEMP.link = NULL; rubberBand(TEMP, x, y, &x, &y, &good); if (good) { m_color(0); rf_text(op); op->okind.t.x = x; op->okind.t.y = y; newbb(&op->bb, x - 100, y - 50, x + 100, y + 50); } curTextOrig = saveOrig; } Static void fl_text(object *op, long part) { rf_text(op); } Static void p_text(pib *pb) { object *WITH; pr_text_rec *WITH1; switch (pb->req) { case p_rb: rb_text(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_add: add_text(pb->x1, pb->y1, pb->x2, pb->y2); break; case p_setup: st_text(pb->x1, pb->y1); break; case p_refresh: rf_text(pb->op); break; case p_flash: fl_text(pb->op, pb->part); break; case p_select: sl_text(pb->op, &pb->part, &pb->area); break; case p_edit: ed_text(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.t; WITH1->x += pb->x1; WITH1->y += pb->y1; newbb(&WITH->bb, WITH1->x, WITH1->y - 25, WITH1->x + 100, WITH1->y + 25); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* INSTANCE ROUTINES */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ Static void instance_parts(object *op, long *cx, long *cy, bbrec *vbb) { object *WITH; WITH = op->okind.i.contents; *cx = (WITH->bb.xh + WITH->bb.xl) / 2; *cy = (WITH->bb.yh + WITH->bb.yl) / 2; *vbb = WITH->bb; } /* Parts of an instance: */ /* 0 == nothing, 1==center(whole thing) */ /* 2 == scale point, 3 == rotate point */ Static void sl_instance(object *op, long *part, long *area) { mat_state m; long x, y, cx, cy; bbrec bb; long TEMP; mat_push(&m); ctm = op->okind.i.m; instance_parts(op, &cx, &cy, &bb); TEMP = bbrx; /*cp := op^.i.contents;*/ *area = TEMP * TEMP * 3; /* For points */ mat_transform(cx, cy, &x, &y); if (pntcheck(x, y)) { /* center (move) point */ *part = 1; goto _L1; } mat_transform(cx, bb.yh, &x, &y); if (pntcheck(x, y)) { /* scale point */ *part = 2; goto _L1; } mat_transform(bb.xh, cy, &x, &y); if (pntcheck(x, y)) { /* rotate point */ *part = 3; goto _L1; } mat_transform(cx, bb.yl, &x, &y); if (pntcheck(x, y)) { /* mirror point */ *part = 4; goto _L1; } mat_transform(bb.xl, cy, &x, &y); if (pntcheck(x, y)) { /* copy point */ *part = 5; goto _L1; } /* Default is center */ *area = (bb.xh - bb.xl) * (bb.yh - bb.yl); /* For whole instance */ *part = 1; _L1: mat_pop(&m); } Static void fl_instance(object *op, long part) { mat_state m; long cx, cy; bbrec bb; instance_parts(op, &cx, &cy, &bb); mat_push(&m); mat_premult(&op->okind.i.m); drawbox(bb.xl, bb.yl, bb.xh, bb.yh); move_(cx, cy); draw(cx, bb.yh); m_moverel(0, 3); m_displaytext("S"); move_(cx, cy); draw(bb.xh, cy); m_moverel(3, 0); m_displaytext("R"); move_(bb.xl, cy); m_moverel(-3, 0); m_displaytext("C"); move_(cx, bb.yl); m_moverel(0, -3); m_displaytext("M"); switch (part) { case 0: /* blank case */ break; case 1: showPoint(cx, cy); break; case 2: showPoint(cx, bb.yh); break; case 3: showPoint(bb.xh, cy); break; case 4: showPoint(cx, bb.yl); break; case 5: showPoint(bb.xl, cy); break; default: printf("fl_instance: Bad part #%ld\n", part); break; } mat_pop(&m); } /* Local variables for ed_instance: */ struct LOC_ed_instance { object *op; long ox, oy; boolean matOnly; pr_inst_rec oInst; long cx, cy, oldLen; } ; Local void mv_instance(long sx, long sy, long ex, long ey, struct LOC_ed_instance *LINK) { long dx, dy; mat_matrix *WITH; pr_inst_rec *WITH1; dx = ex - LINK->ox; dy = ey - LINK->oy; LINK->ox = ex; LINK->oy = ey; if (LINK->matOnly) { WITH = &LINK->op->okind.i.m; WITH->e += dx * WITH->g; WITH->f += dy * WITH->g; } else { WITH1 = &LINK->op->okind.i; if (forceToGrid) { WITH1->tx = ex; /* ex, ey are already on GRID */ WITH1->ty = ey; } else { WITH1->tx += dx; WITH1->ty += dy; } set_instance_mat(LINK->op); } fl_instance(LINK->op, 0); } Local void sc_instance(long sx, long sy, long ex, long ey, struct LOC_ed_instance *LINK) { long newLen; mat_state m; long TEMP, TEMP1; pr_inst_rec *WITH; TEMP = ex - LINK->cx; TEMP1 = ey - LINK->cy; newLen = isqrt(TEMP * TEMP + TEMP1 * TEMP1); if (LINK->matOnly) { mat_push(&m); ctm = LINK->oInst.m; mat_scale(newLen, newLen, LINK->oldLen); LINK->op->okind.i.m = ctm; mat_pop(&m); } else { WITH = &LINK->op->okind.i; WITH->sx = LINK->oInst.sx * newLen; WITH->sy = LINK->oInst.sy * newLen; WITH->den = LINK->oInst.den * LINK->oldLen; while (labs(WITH->sx) > 64 || labs(WITH->sy) > 64 || labs(WITH->den) > 64) { WITH->sx /= 2; WITH->sy /= 2; WITH->den /= 2; } set_instance_mat(LINK->op); } fl_instance(LINK->op, 0); } Local void rot_instance(long sx, long sy, long ex, long ey, struct LOC_ed_instance *LINK) { long d; pr_inst_rec *WITH; if (LINK->matOnly) printf("Can't rotate this instance."); else { WITH = &LINK->op->okind.i; WITH->rot = aTan2I(ex - LINK->cx, ey - LINK->cy); d = 360 / curRots; WITH->rot = (WITH->rot + d / 2) / d * d; set_instance_mat(LINK->op); } fl_instance(LINK->op, 0); } Static void ed_instance(object *op_, long ox_, long oy_, long part) { struct LOC_ed_instance V; boolean good; bbrec bb; long x1, y1; mat_state m; object *op1; _PROCEDURE TEMP; long TEMP1, TEMP2; pr_inst_rec *WITH; V.op = op_; V.ox = ox_; V.oy = oy_; V.matOnly = V.op->okind.i.matOnly; V.oInst = V.op->okind.i; m_color(15); switch (part) { case 1: TEMP.proc = mv_instance; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (good) { m_color(m_black); fl_instance(V.op, 0); set_instance_mbb(V.op, false); } else V.op->okind.i = V.oInst; break; case 2: instance_parts(V.op, &V.cx, &V.cy, &bb); mat_push(&m); ctm = V.op->okind.i.m; mat_transform(bb.xh, V.cy, &x1, &y1); mat_transform(V.cx, V.cy, &V.cx, &V.cy); TEMP1 = x1 - V.cx; TEMP2 = y1 - V.cy; V.oldLen = isqrt(TEMP1 * TEMP1 + TEMP2 * TEMP2); mat_pop(&m); TEMP.proc = sc_instance; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (good) { m_color(m_black); fl_instance(V.op, 0); set_instance_mbb(V.op, false); } else V.op->okind.i = V.oInst; break; case 3: instance_parts(V.op, &V.cx, &V.cy, &bb); mat_push(&m); ctm = V.op->okind.i.m; mat_transform(V.cx, V.cy, &V.cx, &V.cy); mat_pop(&m); TEMP.proc = rot_instance; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (good) { m_color(m_black); fl_instance(V.op, 0); set_instance_mbb(V.op, false); } else V.op->okind.i = V.oInst; break; case 4: WITH = &V.op->okind.i; if (!WITH->matOnly) { WITH->sx = -WITH->sx; set_instance_mat(V.op); set_instance_mbb(V.op, false); } break; case 5: /* Copy current instance */ op1 = make_instance(V.op->okind.i.contents, V.op->okind.i.m, true); op1->bb = V.op->bb; op1->okind.i = V.op->okind.i; TEMP.proc = mv_instance; TEMP.link = &V; rubberBand(TEMP, V.ox, V.oy, &V.ox, &V.oy, &good); if (good) { m_color(m_black); fl_instance(V.op, 0); set_instance_mbb(V.op, false); } else { V.op->okind.i = V.oInst; /* Delete copied instance */ dispose_obj(op1); } break; default: printf("ed_instance: Bad part #%ld\n", part); break; } } Static boolean instKind(object *o) { return (o->kind == pr_inst); } Static void findScreenBox(bbrec *screenInWorld) { long x, y; emptybb(screenInWorld); /* must check all 4 corners in case rotated */ mat_untransform(plotArea.xl, plotArea.yl, &x, &y); addbbpnt(screenInWorld, x, y); mat_untransform(plotArea.xh, plotArea.yl, &x, &y); addbbpnt(screenInWorld, x, y); mat_untransform(plotArea.xl, plotArea.yh, &x, &y); addbbpnt(screenInWorld, x, y); mat_untransform(plotArea.xh, plotArea.yh, &x, &y); addbbpnt(screenInWorld, x, y); } Static boolean insideBB(bbrec *bout, bbrec *bin) { return (bin->xl >= bout->xl && bin->yl >= bout->yl && bin->xh <= bout->xh && bin->yh <= bout->yh); } Static boolean overlapBB(bbrec *b1, bbrec *b2) { return (b1->xl <= b2->xh && b1->yl <= b2->yh && b2->xl <= b1->xh && b2->yl <= b1->yh); } /* rf_root should be a pointer to an instance (with matrix) */ Static void rf_instance(object *rf_root, boolean checkClip) { /* return */ object *o; mat_state m; pib pb; bbrec scb, *WITH; object *WITH1; color_rec *WITH2; if (rf_root == NULL || !instKind(rf_root) || rf_root->okind.i.contents == NULL) { printf("rf_instance: BIG PROBLEMS.\007\n"); goto _L2; } if (showInstBB || rf_root->okind.i.closed) { m_color(3); m_linestyle(3); WITH = &rf_root->bb; drawbox(WITH->xl, WITH->yl, WITH->xh, WITH->yh); m_linestyle(0); if (rf_root->okind.i.closed) goto _L2; } mat_push(&m); /* Pre-multiply the current transformation matrix by rf_root^.i.m */ mat_premult(&rf_root->okind.i.m); /* Convert the borders of the screen into the current space, for clipping */ if (checkClip) findScreenBox(&scb); o = rf_root->okind.i.contents; /* this will scan the horizontal list */ do { if (o->kind != o_base) { WITH1 = o; WITH2 = &WITH1->color; if (WITH1->kind == pr_inst) { if (!checkClip) rf_instance(o, false); else if (insideBB(&scb, &WITH1->bb)) rf_instance(o, false); else if (overlapBB(&scb, &WITH1->bb)) rf_instance(o, true); } else { if (plotColor < 0 || WITH2->value == plotColor) { if (!checkClip) { m_color(WITH2->value); pb.req = p_refresh; pb.op = o; ((void(*)(pib *pb))primInfo[(long)WITH1->kind])(&pb); } else if (overlapBB(&scb, &WITH1->bb)) { m_color(WITH2->value); pb.req = p_refresh; pb.op = o; ((void(*)(pib *pb))primInfo[(long)WITH1->kind])(&pb); } } } } o = o->next; } while (o->kind != o_base); mat_pop(&m); _L2: ; /* Instance clipped away! */ /*writeln('Clipped a ',prKind);*/ } Static void p_instance(pib *pb) { object *WITH; pr_inst_rec *WITH1; mat_matrix *WITH2; switch (pb->req) { case p_rb: /* blank case */ break; /*rb_instance(pb.x1,pb.y1,pb.x2,pb.y2);*/ case p_add: break; /*add_instance(pb.x1,pb.y1,pb.x2,pb.y2);*/ case p_setup: finishSetup(pb, pr_inst); break; case p_refresh: /* No path-setting here either. */ rf_instance(pb->op, plotColor < 0); break; /* clipCheck if plotting on screen */ case p_flash: fl_instance(pb->op, pb->part); break; case p_select: sl_instance(pb->op, &pb->part, &pb->area); break; case p_edit: ed_instance(pb->op, pb->x1, pb->y1, pb->part); break; case p_move: WITH = pb->op; WITH1 = &WITH->okind.i; if (WITH1->matOnly) { WITH2 = &WITH1->m; WITH2->e += pb->x1 * WITH2->g; WITH2->f += pb->y1 * WITH2->g; } else { WITH1->tx += pb->x1; WITH1->ty += pb->y1; set_instance_mat(pb->op); } set_instance_mbb(pb->op, false); break; } } /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ /* GENERIC ROUTINES */ /*# # # # # # # # # # # # # # # # # # # # # # # # # # # #*/ void pr_refresh(void) { mat_state m; /*ch : gr_charstate;*/ mat_push(&m); m_nocursor(); m_colormode(m_normal); /*gr_savechar(ch);*/ m_clear(); plotColor = -2; rf_instance(curFigure->guts, true); restore_color(); /*gr_restorechar(ch);*/ mat_pop(&m); } void flash(object *op, long part) { pib pb; if (op->kind == o_base) return; m_colormode(m_xor); m_color(15); m_nocursor(); pb.req = p_flash; pb.op = op; pb.part = part; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); restore_color(); } /* Remove from linked lists, dispose of memory */ void dispose_obj(object *op) { /* Unlink from current list */ op->prev->next = op->next; op->next->prev = op->prev; /* Something is wrong down here, so don't do anything... */ /*$IF FALSE$ with op^ do begin if (op^.kind=o_prim) and (op^.prkind=pr_line) then begin p := op^.l.pnts; while p<>NIL do begin q := p^.next; dispose(p); p := q; end; end; dispose(op); end; $END$*/ } Static Char *objkinds_NAMES[] = { "O_BASE", "O_PRIM" } ; /* Link into current figure at end of figure */ Static void insert_obj(object *o) { object *basep; basep = curFigure->guts->okind.i.contents; if (basep->kind != o_base) { printf("insert_obj: base.kind is not a o_base, = %s\n", objkinds_NAMES[(long)basep->kind]); return; } o->next = basep; o->prev = basep->prev; o->prev->next = o; basep->prev = o; /* insert in linked list */ } /* Restore the top thing from the deleted list */ void until_undelete(void) { object *next; if (deleted == NULL) return; next = deleted->next; insert_obj(deleted); if (deleted->kind != o_base) objColor(deleted); refObj(deleted); deleted = next; changed(); } /* Put on deleted list */ Static void delete_obj(object *op) { /* Unlink from current list */ op->prev->next = op->next; op->next->prev = op->prev; /* Install on deleted list */ op->prev = NULL; op->next = deleted; deleted = op; } void delete__(object *op) { m_nocursor(); if (op->kind == o_base) printf("delete: can't delete o_base\n"); else { objColor(op); /* set colormode and linewidth */ m_colormode(m_erase); refObj(op); delete_obj(op); changed(); } restore_color(); } void moveObj(object *op, long dx, long dy, boolean erase) { pib pb; m_nocursor(); if (op->kind != o_base) { pb.op = op; pb.x1 = dx; pb.y1 = dy; if (erase) { objColor(op); m_colormode(m_erase); pb.req = p_refresh; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); } pb.req = p_move; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); objColor(op); m_colormode(m_normal); pb.req = p_refresh; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); } restore_color(); } void edit(object *op, long x, long y, long part) { pib pb; m_nocursor(); if (op->kind != o_base) { objColor(op); m_colormode(m_erase); pb.op = op; pb.x1 = x; pb.y1 = y; pb.part = part; pb.req = p_refresh; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); pb.req = p_edit; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); objColor(op); m_colormode(m_normal); pb.req = p_refresh; ((void(*)(pib *pb))primInfo[(long)op->kind])(&pb); changed(); } restore_color(); } #define box_rad 3 /* number of pixels */ void selectOne(object **vop, long x, long y, long *vpart, long *varea) { long rx, ry; object *o; /* to follow the linked list */ long npart, narea; /* returned from latest call */ object *op; /* current best object */ long part, area; /* current best part and area */ pib pb; op = NULL; part = -1; area = LONG_MAX; /* setup bounding box information */ mat_runtransform(box_rad, box_rad, &rx, &ry); makebb(x, y, rx, ry); o = curFigure->guts; if (o == NULL) goto _L1; if (o->kind != pr_inst) { printf("selectOne: ROOT KIND WRONG.\007\n"); goto _L1; } o = o->okind.i.contents; if (o->kind != o_base) { printf("selectOne: ROOT^.CONTENTS.KIND WRONG.\007\n"); goto _L1; } /* this will scan the horizontal list */ o = o->next; while (o->kind != o_base) { if (bbrcheck(&o->bb)) { pb.req = p_select; pb.op = o; ((void(*)(pib *pb))primInfo[(long)o->kind])(&pb); npart = pb.part; narea = pb.area; if (npart != 0 && narea < area) { area = narea; part = npart; op = o; } } o = o->next; } _L1: *vop = op; *varea = area; *vpart = part; } #undef box_rad void selectLots(selListElem **vl, long x, long y, long ex, long ey) { long rx, ry; object *o; /* To follow the linked list */ selListElem *l; /* Selected items list */ selListElem *t; bbrec *WITH; l = NULL; rx = labs(x - ex) / 2; ry = labs(y - ey) / 2; makebb((x + ex) / 2, (y + ey) / 2, rx, ry); o = curFigure->guts; if (o == NULL) goto _L1; if (!instKind(o)) { printf("selectLots: ROOT KIND WRONG.\007\n"); goto _L1; } o = o->okind.i.contents; if (o->kind != o_base) { printf("selectLots: ROOT^.CONTENTS.KIND WRONG.\007\n"); goto _L1; } /* this will scan the horizontal list */ o = o->next; while (o->kind != o_base) { if (bbincheck(&o->bb)) { m_color(18); if (false) { WITH = &o->bb; drawbox(WITH->xl, WITH->yl, WITH->xh, WITH->yh); } /* Put on selected list */ t = Malloc(sizeof(selListElem)); t->next = l; t->obj = o; l = t; } o = o->next; } _L1: *vl = l; } Static void setupPrimTable(void) { objkinds i; for (i = pr_none; i < pr_last; i = (objkinds)((long)i + 1)) primInfo[(long)i] = p_none; primInfo[pr_line] = p_line; primInfo[pr_dot] = p_dot; primInfo[pr_box] = p_box; primInfo[pr_circle] = p_circle; primInfo[pr_ellipse] = p_ellipse; primInfo[pr_text] = p_text; primInfo[pr_inst] = p_instance; } void update_root_mbb(void) { set_base_mbb(curFigure->guts->okind.i.contents, false); set_instance_mbb(curFigure->guts, false); } void init_prim_stuff(void) { setupPrimTable(); forceToGrid = true; deleted = NULL; showTextState = sts_words; }