date and time created 84/10/21 15:02:56 by opcode
[unix-history] / usr / src / local / ditroff / ditroff.old.okeeffe / sunsrc / gremlin / db.c
CommitLineData
a9a9e6b8
MO
1/*
2 * @(#)db.c 1.1 %G%
3 *
4 * This file contains routines for database manipulation for the
5 * SUN Gremlin picture editor.
6 *
7 * Mark Opperman (opcode@monet.BERKELEY)
8 *
9 */
10
11#include "gremlin.h"
12#include <ctype.h>
13
14/* imports from undodb */
15
16extern UNRembAdd();
17extern UNRembDelete();
18extern UNRembMod();
19
20/* imports from C */
21
22extern char *malloc();
23
24/* imports from point.c */
25
26extern PTModifyTextPoints();
27extern POINT *PTMakePoint();
28
29/* imports from text.c */
30
31extern TxPutMsg();
32extern TxMsgOK();
33
34/* imports from main */
35
36extern SEARCH; /* Search the path for filename */
37extern TOOLINSTALLED;
38
39/* cset is a pointer to the current set available to the outside world. */
40
41ELT *cset;
42
43#ifdef oldway
44/*
45 * This routine returns a pointer to an initialized database element
46 * which would be the only element in an empty list.
47 */
48ELT *
49DBInit()
50{
51 return((ELT *) NULL);
52}
53#endif
54
55
56/*
57 * This routine creates a new element with the specified attributes and
58 * links it into database db.
59 */
60ELT *
61DBCreateElt(type, pointlist, brush, size, text, db)
62int type, brush, size;
63POINT *pointlist;
64char *text;
65ELT *(*db);
66{
67 register ELT *temp;
68
69 temp = (ELT *) malloc(sizeof(ELT));
70 temp->nextelt = *db;
71 temp->type = type;
72 temp->ptlist = pointlist;
73 temp->brushf = brush;
74 temp->size = size;
75 temp->textpt = text;
76 *db = temp;
77 UNRembAdd(temp, db);
78 return(temp);
79} /* end DBCreateElt */
80
81
82/*
83 * This routine deletes the specified element by searching the database
84 * for its predecessor and deleting the pointer to the element.
85 * Flag indicates whether or not the element was in the current set
86 * and is passed along for use by the undo routines.
87 */
88DBDelete(elt, db)
89register ELT *elt, *(*db);
90{
91 register ELT *(*temp);
92
93 temp = db;
94
95 while (*temp != elt) {
96 if (DBNullelt(*temp)) {
97 error("no such element");
98 return;
99 }
100 temp = &(DBNextElt((*temp)));
101 }
102
103 UNRembDelete(*temp, db);
104 *temp = DBNextElt(elt);
105} /* end DBDelete */
106
107
108#define highval 100000 /* arbitrary value greater than any
109 * expected distance */
110
111
112/*
113 * This routine searches the database for the point closest to
114 * (Euclidean distance) point1. This point is returned as point2
115 * and the element which contained the point is also returned.
116 * The point must be closer than some predefined maximum distance
117 * in order to be gravitated.
118 * If setonly == TRUE the element's "setnext" pointer is used to
119 * find the elements in the list, otherwise "nextelt" is used.
120 */
121DBGravitate(x1, y1, x2, y2, point, elt, db, setonly)
122float x1, y1, *x2, *y2;
123POINT *(*point);
124ELT *(*elt), *db;
125int setonly;
126{
127 register POINT *holdpt;
128 register ELT *temp;
129 register t, t1, t2;
130 register distance = highval;
131
132 temp = db;
133 *elt = DBInit();
134 *x2 = x1;
135 *y2 = y1;
136 while (!DBNullelt(temp)) {
137 holdpt = temp->ptlist;
138 while (!Nullpoint(holdpt)) {
139 /* Calculate the distance between the point in the data
140 base and the specified point. Use Euclidean distance
141 except that, since we only need relative distance and
142 not an absolute number, it is not necessary to take the
143 square root. The equation for the distance was broken up
144 as below in order to allow integer arithmetic wherever
145 possible to increase efficiency when it was discovered
146 that this routine was too slow. */
147 t1 = holdpt->x - x1;
148 t1 *= t1;
149 t2 = holdpt->y - y1;
150 t2 *= t2;
151 t = t1 + t2;
152
153 if ((t < distance) && (t < MAXGDIST)) {
154 distance = t;
155 *x2 = holdpt->x;
156 *y2 = holdpt->y;
157 *point = holdpt;
158 *elt = temp;
159 }
160
161 holdpt = holdpt->nextpt;
162 }
163 temp = setonly ? DBNextofSet(temp) : DBNextElt(temp);
164 }
165} /* end DBGravitate */
166
167
168/*
169 * This routine returns all storage associated with the element to
170 * free storage.
171 */
172DBClearElt(elt)
173register ELT *elt;
174{
175 register POINT *pt, *pt2;
176
177 pt = elt->ptlist;
178
179 while (!Nullpoint(pt)) {
180 pt2 = PTNextPoint(pt);
181 free ((char *) pt);
182 pt = pt2;
183 }
184
185 free(elt->textpt);
186 free((char *) elt);
187} /* end DBClearElt */
188
189
190/*
191 * This routine reads the specified file into a database and
192 * returns a pointer to that database. Orient and pos are also set
193 * from the file.
194 *
195 * The format of a file written by gremlin is:
196 * the string: "gremlinfile" followed by a carriage return.
197 * the orientation (integer) and the x and y coordinates of a positioning
198 * point (float) followed by another carriage return.
199 * The output of 0 or more elements (see below).
200 * a -1 (integer) indicating end of data.
201 *
202 * The format of each element is:
203 * The element type (integer) followed by a carriage return.
204 * a list of 0 or more pairs of point coordinates (float) each on separate
205 * lines and terminated by the coordinates -1.0 -1.0.
206 * the brush (font) and size (integer) the element was defined with then <cr>
207 * the length (integer) of the string followed by the string terminated with
208 * a carriage return.
209 *
210 * All numbers are printed using standard C output conversion (ascii).
211 *
212 * +++ NEW FORMAT FOR SUN +++
213 *
214 * "sungremlinfile" is keyword in place of "gremlinfile"
215 *
216 * Point lists are terminated by a line containing a single asterik ('*')
217 * to allow the legal point (-1.00 -1.00) in the point list. All negative
218 * coordinates are now legal. Element types are indicated by ascii text,
219 * eg, POLYGON, VECTOR, ARC, BOTLEFT, TOPCENT, etc.
220 */
221ELT *
222DBRead(filename, orient, pos)
223char *filename;
224int *orient;
225POINT *pos;
226{
227 FILE *fp, *POpen();
228 ELT *elt, *elist;
229 POINT *plist;
230 char string[128], *txt, *prealname;
231 float x, y;
232 int len, type, i, brush, size, done, lastpoint, sunfile;
233
234 sunfile = FALSE;
235 elist = DBInit();
236 fp = POpen(filename, &prealname, SEARCH);
237
238 if (fp == NULL) {
239 (void) sprintf(string, "can't open %s",filename);
240 error(string);
241 return(elist);
242 }
243
244 if (TOOLINSTALLED) /* no message if reading startup edit file */
245 TxPutMsg("reading file...");
246 (void) fscanf(fp, "%s\n", string);
247
248 if (strcmp(string, "gremlinfile")) {
249 if (strcmp(string, "sungremlinfile")) {
250 error("not gremlin file");
251 return(elist);
252 }
253 sunfile = TRUE;
254 }
255
256 (void) fscanf(fp, "%d%f%f\n", orient, &x, &y);
257 pos->x = x;
258 pos->y = y;
259
260 done = FALSE;
261 while (!done) {
262 if (fscanf(fp,"%s\n", string) == EOF) { /* element type */
263 error("error in file format");
264 fclose(fp);
265 return(elist);
266 }
267
268 if ((type = DBGetType(string)) < 0) { /* no more data */
269 done = TRUE;
270 }
271 else {
272 plist = PTInit();
273 (void) fscanf(fp, "%f%f\n", &x, &y); /* read first point */
274
275 /* Files created on the SUN have point lists terminated
276 * by a line containing only an asterik ('*'). Files
277 * created on the AED have point lists terminated by the
278 * coordinate pair (-1.00 -1.00).
279 */
280 lastpoint = FALSE;
281 do {
282 (void) PTMakePoint(x, y, &plist);
283 fgets(string, 127, fp);
284 if (string[0] == '*') { /* SUN gremlin file */
285 lastpoint = TRUE;
286 }
287 else {
288 (void) sscanf(string, "%f%f", &x, &y);
289 if ((x == -1.00 && y == -1.00) && (!sunfile))
290 lastpoint = TRUE;
291 }
292 } while (!lastpoint);
293#ifdef oldway
294 while ((x != -1) && (y != -1)) { /* plist terminated by -1, -1 */
295 (void) PTMakePoint(x, y, &plist);
296 (void) fscanf(fp, "%f%f\n", &x, &y);
297 }
298#endif
299
300 (void) fscanf(fp, "%d%d\n", &brush, &size);
301 (void) fscanf(fp, "%d", &len);
302 (void) getc(fp); /* eat blank */
303 txt = malloc((unsigned) len + 1);
304 for (i=0; i<len; ++i)
305 txt[i] = getc(fp);
306 txt[len] = '\0';
307 elt = DBCreateElt(type, plist, brush, size, txt, &elist);
308 if (TEXT(elt->type)) /* recompute text reference points */
309 PTModifyTextPoints(elt);
310 }
311 }
312
313 TxMsgOK();
314 fclose(fp);
315 return(elist);
316} /* end DBRead */
317
318
319/*
320 * Interpret element type in string s.
321 * Old file format consisted of integer element types.
322 * New file format has literal names for element types.
323 */
324DBGetType(s)
325register char *s;
326{
327 if (isdigit(s[0]) || (s[0] == '-')) /* old element format or EOF */
328 return(atoi(s));
329
330 switch (s[0]) {
331 case 'P':
332 return(POLYGON);
333 case 'V':
334 return(VECTOR);
335 case 'A':
336 return(ARC);
337 case 'C':
338 if (s[1] == 'U')
339 return(CURVE);
340 switch (s[4]) {
341 case 'L':
342 return(CENTLEFT);
343 case 'C':
344 return(CENTCENT);
345 case 'R':
346 return(CENTRIGHT);
347 default:
348 error("unknown element type");
349 return(-1);
350 }
351 case 'B':
352 switch (s[3]) {
353 case 'L':
354 return(BOTLEFT);
355 case 'C':
356 return(BOTCENT);
357 case 'R':
358 return(BOTRIGHT);
359 default:
360 error("unknown element type");
361 return(-1);
362 }
363 case 'T':
364 switch (s[3]) {
365 case 'L':
366 return(TOPLEFT);
367 case 'C':
368 return(TOPCENT);
369 case 'R':
370 return(TOPRIGHT);
371 default:
372 error("unknown element type");
373 return(-1);
374 }
375 default:
376 error("unknown element type");
377 return(-1);
378 }
379} /* end DBGetType */
380
381
382/*
383 * This routine returns true if all points in elt are bounded by
384 * the rectangle who diagonal is formed by (x1, y1) and (x2, y2).
385 */
386DBBounded(elt, x1, y1, x2, y2)
387register ELT *elt;
388register float x1, y1, x2, y2;
389{
390 register POINT *p1;
391 register float lox, loy, hix, hiy; /* OK to compare register floats */
392
393 lox = (x1 < x2) ? x1 : x2;
394 loy = (y1 < y2) ? y1 : y2;
395 hix = (x1 > x2) ? x1 : x2;
396 hiy = (y1 > y2) ? y1 : y2;
397 p1 = elt->ptlist;
398
399 while (!Nullpoint(p1)) {
400 if ((p1->x < lox) || (p1->x > hix) || (p1->y < loy) || (p1->y > hiy))
401 return(FALSE);
402 p1 = PTNextPoint(p1);
403 }
404
405 return(TRUE);
406} /* end DBBounded */
407
408
409/*
410 * This routine creates a copy of the the element transformed by
411 * the transformation matrix and adds the new copy to the database.
412 */
413ELT *
414DBCopy(elt, transform, db)
415register ELT *elt;
416ELT *(*db);
417float transform[3][2];
418{
419 register POINT *pt;
420 POINT *newlist;
421 char *newtext;
422
423 newlist = PTInit();
424 pt = elt->ptlist;
425
426 while (!Nullpoint(pt)) { /* matrix multiply */
427 (void) PTMakePoint((((pt->x) * transform[0][0]) +
428 ((pt->y) * transform[1][0]) +
429 transform[2][0]),
430 (((pt->x) * transform[0][1]) +
431 ((pt->y) * transform[1][1]) +
432 transform[2][1]), &newlist);
433 pt = pt->nextpt;
434 }
435
436 newtext = malloc((unsigned) strlen(elt->textpt) + 1);
437 (void) strcpy(newtext, elt->textpt);
438 return( DBCreateElt(elt->type, newlist, elt->brushf,
439 elt->size, newtext, db) );
440} /* end DBCopy */
441
442
443/*
444 * This routine transforms the element by multiplying the
445 * coordinates of each of the points in the element by the
446 * transformation matrix.
447 */
448DBXform(elt, transform, db)
449register ELT *elt;
450float transform[3][2];
451ELT *(*db);
452{
453 register POINT *pt;
454 float px, py;
455
456 UNRembMod(elt, db);
457 pt = elt->ptlist;
458
459 while (!Nullpoint(pt)) {
460 px = ((pt->x) * transform[0][0]) +
461 ((pt->y) * transform[1][0]) + transform[2][0];
462 py = ((pt->x) * transform[0][1]) +
463 ((pt->y) * transform[1][1]) + transform[2][1];
464 pt->x = px;
465 pt->y = py;
466 pt = pt->nextpt;
467 }
468} /* end DBXform */
469
470
471/*
472 * This routine changes the brush attribute of the element.
473 */
474DBChangeBrush(elt, brush, db)
475ELT *elt, *(*db);
476int brush;
477{
478 UNRembMod(elt, db);
479 elt->brushf = brush;
480} /* end DBChangeBrush */
481
482
483/*
484 * This routine changes the justify attribute of the element.
485 */
486DBChangeJustify(elt, justmode, db)
487ELT *elt, *(*db);
488int justmode;
489{
490 register length;
491 register POINT *pos, *point;
492
493 UNRembMod(elt, db);
494 elt->type = justmode;
495 PTModifyTextPoints(elt);
496} /* end DBChangeJustify */
497
498
499/*
500 * This routine changes the font attribute of the given element.
501 */
502DBChangeFont(elt, font, db)
503ELT *elt, *(*db);
504int font;
505{
506 UNRembMod(elt, db);
507 elt->brushf = font;
508 PTModifyTextPoints(elt);
509} /* end DBChangeFont */
510
511
512/*
513 * This routine changes the size attribute of the given element.
514 */
515DBChangeSize(elt, size, db)
516ELT *elt, *(*db);
517int size;
518{
519 UNRembMod(elt, db);
520 elt->size = size;
521 PTModifyTextPoints(elt);
522} /* end DBChangeSize */
523
524
525/*
526 * This routine changes the stipple attribute of the given element.
527 */
528DBChangeStipple(elt, stipple, db)
529ELT *elt, *(*db);
530int stipple;
531{
532 UNRembMod(elt, db);
533 elt->size = stipple;
534} /* end DBChangeStipple */
535
536
537/*
538 * This routine changes the text attribute of the given element.
539 */
540DBChangeText(elt, text, db)
541ELT *elt, *(*db);
542char *text;
543{
544 char *new;
545
546 UNRembMod(elt, db);
547 free(elt->textpt);
548 new = malloc((unsigned) strlen(text) + 1);
549 (void) strcpy(new, text);
550 elt->textpt = new;
551 PTModifyTextPoints(elt);
552} /* end DBChangeText */
553
554
555/*
556 * This routine changes the type attribute of the given element.
557 */
558DBChangeType(elt, newtype, db)
559ELT *elt, *(*db);
560int newtype;
561{
562 UNRembMod(elt, db);
563 elt->type = newtype;
564} /* end DBChangeType */
565
566
567/*
568 * This routine changes the type and stipple attributes of the given element.
569 */
570DBChangeTypeStipple(elt, newtype, newstipple, db)
571ELT *elt, *(*db);
572int newtype, newstipple;
573{
574 UNRembMod(elt, db);
575 elt->type = newtype;
576 elt->size = newstipple;
577} /* end DBChangeType */
578
579
580/*
581 * This routine changes the type, brush and stipple attributes
582 * of the given element.
583 */
584DBChangeTypeBrushStipple(elt, newtype, newbrush, newstipple, db)
585ELT *elt, *(*db);
586int newtype, newbrush, newstipple;
587{
588 UNRembMod(elt, db);
589 elt->type = newtype;
590 elt->brushf = newbrush;
591 elt->size = newstipple;
592} /* end DBChangeType */
593
594
595/*
596 * This routine adds the element to the current set database.
597 */
598DBAddSet(elt)
599register ELT *elt;
600{
601 register ELT *elist;
602
603 elist = cset;
604
605 while (!DBNullelt(elist)) { /* makes sure element not already in list */
606 if (elist == elt)
607 return;
608 elist = DBNextofSet(elist);
609 }
610
611 elt->setnext = cset;
612 cset = elt;
613} /* end DBAddSet */
614
615
616/*
617 * Return TRUE if element in current set, else FALSE.
618 */
619DBInCset(elt)
620register ELT *elt;
621{
622 register ELT *elist;
623
624 elist = cset;
625
626 while (!DBNullelt(elist)) { /* makes sure element not already in list */
627 if (elist == elt)
628 return(TRUE);
629 elist = DBNextofSet(elist);
630 }
631 return(FALSE);
632} /* end DBInCset */
633
634
635/*
636 * This routine clears the current set by setting the pointer
637 * to a null element.
638 */
639DBClearSet()
640{
641 while (!DBNullelt(cset))
642 cset = DBNextofSet(cset);
643} /* end DBClearSet */