1 /*
2 * tkgeomapLnArr.c --
3 *
4 * This file defines functions that display geolinearrays as canvas items.
5 *
6 * Copyright (c) 2004 Gordon D. Carrie. All rights reserved.
7 *
8 * Licensed under the Open Software License version 2.1
9 *
10 * Please address questions and feedback to user0@tkgeomap.org
11 *
12 * @(#) $Id: tkgeomapLnArr.c,v 1.20 2009/10/23 20:37:25 tkgeomap Exp $
13 *
14 **********************************************************************
15 *
16 */
17
18 #include "tkgeomap.h"
19 #include "tkgeomapInt.h"
20
21 /*
22 * This structure stores one geomap_lnarr item.
23 */
24
25 typedef struct {
26 Tk_Item header; /* Generic stuff that's the same for all
27 * types. MUST BE FIRST IN STRUCTURE. */
28 Tcl_Interp *interp; /* Interpreter in which item was created */
29 Tk_Canvas canvas; /* Canvas in which item is displayed */
30 double xRef, yRef; /* Canvas coordinates of reference point */
31 GeoPt refPt; /* Geographic coordinates of reference point */
32 Tclgeomap_Proj proj; /* Cartographic projection */
33 double scale; /* Cartographic scale (pure number ratio) */
34 Tclgeomap_LnArr tclGeoLnArr;/* Geolinearray the item displays */
35 int nLines; /* Number of lines to draw */
36 int nMax; /* Number of points in longest line */
37 MapLnArr mapLnArr; /* Array of map coordinates for the lines */
38 double **coordPtrPtr; /* Array of canvas coordinates corresponding to
39 * the points in the map. Dimensions are
40 * [nLines][num pts in line] */
41 int *nPtsPtr; /* Number of points in each line of
42 * coordPtrPtr. Dimension is [num lines] */
43 int updateMap; /* If true, mapLnArr is out of date */
44 int updateCvs; /* If true, coordPtrPtr is out of date */
45 int width; /* Line width */
46 XColor *lineColor; /* Outline color */
47 int lineStyle; /* LineSolid, LineOnOffDash, or
48 * LineDoubleDash */
49 int dashes; /* Dash length */
50 GC lineGC; /* Graphics context for drawing outline */
51 int smooth; /* If true, smooth the line. Currently
52 * smoothing is done only with Tk's bezier
53 * function */
54 int splineSteps; /* Number of steps in each spline segment */
55 XColor *fillColor; /* Color to fill shapes */
56 Pixmap stipple; /* Stipple pattern to fill shapes */
57 int shape; /* Complex, Convex, or Nonconvex */
58 GC fillGC; /* Graphics context for filling */
59 int dotSize; /* Dot size at segment ends */
60 } LnArrItem;
61
62 /*
63 * Prototypes for procedures defined in this file:
64 */
65
66 static int createProc _ANSI_ARGS_((Tcl_Interp *interp,
67 Tk_Canvas canvas, struct Tk_Item *itemPtr,
68 int objc, Tcl_Obj *CONST objv[]));
69 static int configProc _ANSI_ARGS_((Tcl_Interp *interp,
70 Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
71 Tcl_Obj *CONST objv[], int flags));
72 static int coordProc _ANSI_ARGS_((Tcl_Interp *interp,
73 Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
74 Tcl_Obj *CONST objv[]));
75 static void deleteProc _ANSI_ARGS_((Tk_Canvas canvas,
76 Tk_Item *itemPtr, Display *display));
77 static void forgetLnArr _ANSI_ARGS_((ClientData clientData));
78 static void forgetProj _ANSI_ARGS_((ClientData clientData));
79 static void hide _ANSI_ARGS_((LnArrItem *lnArrItemPtr));
80 static void displayProc _ANSI_ARGS_((Tk_Canvas canvas,
81 Tk_Item *itemPtr, Display *display,
82 Drawable dst, int x, int y, int width,
83 int height));
84 static double pointProc _ANSI_ARGS_((Tk_Canvas canvas,
85 Tk_Item *itemPtr, double *coordPtr));
86 static int areaProc _ANSI_ARGS_((Tk_Canvas canvas,
87 Tk_Item *itemPtr, double *rectPtr));
88 static int postscriptProc _ANSI_ARGS_((Tcl_Interp *interp,
89 Tk_Canvas canvas, Tk_Item *itemPtr,
90 int prepass));
91 static void scaleProc _ANSI_ARGS_((Tk_Canvas canvas,
92 Tk_Item *itemPtr, double originX,
93 double originY, double scaleX, double scaleY));
94 static void translateProc _ANSI_ARGS_((Tk_Canvas canvas,
95 Tk_Item *itemPtr, double deltaX,
96 double deltaY));
97 static int parseGeoLnArrOption _ANSI_ARGS_((ClientData clientData,
98 Tcl_Interp *interp, Tk_Window tkwin,
99 char *value, char *widgRec, int offset));
100 static char * printGeoLnArrOption _ANSI_ARGS_((ClientData clientData,
101 Tk_Window tkwin, char *widgRec, int offset,
102 Tcl_FreeProc **freeProcPtr));
103 static int parseRefPtOption _ANSI_ARGS_((ClientData clientData,
104 Tcl_Interp *interp, Tk_Window tkwin,
105 char *value, char *widgRec, int offset));
106 static char * printRefPtOption _ANSI_ARGS_((ClientData clientData,
107 Tk_Window tkwin, char *widgRec, int offset,
108 Tcl_FreeProc **freeProcPtr));
109 static int parseProjOption _ANSI_ARGS_((ClientData clientData,
110 Tcl_Interp *interp, Tk_Window tkwin,
111 char *value, char *widgRec, int offset));
112 static char * printProjOption _ANSI_ARGS_((ClientData clientData,
113 Tk_Window tkwin, char *widgRec, int offset,
114 Tcl_FreeProc **freeProcPtr));
115 static int parseLineStyleOption _ANSI_ARGS_((ClientData clientData,
116 Tcl_Interp *interp, Tk_Window tkwin,
117 char *value, char *widgRec, int offset));
118 static char * printLineStyleOption _ANSI_ARGS_((ClientData clientData,
119 Tk_Window tkwin, char *widgRec, int offset,
120 Tcl_FreeProc **freeProcPtr));
121 static int parseShapeOption _ANSI_ARGS_((ClientData clientData,
122 Tcl_Interp *interp, Tk_Window tkwin,
123 char *value, char *widgRec, int offset));
124 static char * printShapeOption _ANSI_ARGS_((ClientData clientData,
125 Tk_Window tkwin, char *widgRec, int offset,
126 Tcl_FreeProc **freeProcPtr));
127 static void updateMap _ANSI_ARGS_((ClientData clientData));
128 static void updateCvs _ANSI_ARGS_((ClientData clientData));
129
130 /*
131 * Custom configuration options
132 */
133
134 static Tk_CustomOption geoLnArrOption = {
135 parseGeoLnArrOption,
136 printGeoLnArrOption,
137 NULL
138 };
139
140 static Tk_CustomOption refPtOption = {
141 parseRefPtOption,
142 printRefPtOption,
143 NULL
144 };
145
146 static Tk_CustomOption projOption = {
147 parseProjOption,
148 printProjOption,
149 NULL
150 };
151
152 static Tk_CustomOption shapeOption = {
153 parseShapeOption,
154 printShapeOption,
155 NULL
156 };
157
158 static Tk_CustomOption lineStyleOption = {
159 parseLineStyleOption,
160 printLineStyleOption,
161 NULL
162 };
163
164 /*
165 * The members of tagsOption will be set in TkgeomapLnArrInit
166 */
167
168 static Tk_CustomOption tagsOption = {
169 NULL, NULL, NULL
170 };
171
172 /*
173 * Configuration options for the geomap_lnarr item
174 */
175
176 static Tk_ConfigSpec configSpecs[] = {
177 {TK_CONFIG_CUSTOM, "-lnarr", NULL, NULL, "", 0, TK_CONFIG_NULL_OK,
178 &geoLnArrOption},
179 {TK_CONFIG_CUSTOM, "-refpoint", NULL, NULL, "0.0 0.0", 0, 0,
180 &refPtOption},
181 {TK_CONFIG_CUSTOM, "-projection", NULL, NULL, "", 0, 0,
182 &projOption},
183 {TK_CONFIG_DOUBLE, "-scale", NULL, NULL, "1.0e-7",
184 Tk_Offset(LnArrItem, scale), 0, NULL},
185 {TK_CONFIG_COLOR, "-outline", NULL, NULL, "NavyBlue",
186 Tk_Offset(LnArrItem, lineColor), TK_CONFIG_NULL_OK, NULL},
187 {TK_CONFIG_PIXELS, "-width", NULL, NULL, "1",
188 Tk_Offset(LnArrItem, width), 0, NULL},
189 {TK_CONFIG_CUSTOM, "-linestyle", NULL, NULL, "LineSolid",
190 0, 0, &lineStyleOption},
191 {TK_CONFIG_INT, "-dashes", NULL, NULL, "4",
192 Tk_Offset(LnArrItem, dashes), 0, NULL},
193 {TK_CONFIG_BOOLEAN, "-smooth", NULL, NULL, "0",
194 Tk_Offset(LnArrItem, smooth), 0, NULL},
195 {TK_CONFIG_INT, "-splinesteps", NULL, NULL, "12",
196 Tk_Offset(LnArrItem, splineSteps), 0, NULL},
197 {TK_CONFIG_COLOR, "-fill", NULL, NULL, "",
198 Tk_Offset(LnArrItem, fillColor), TK_CONFIG_NULL_OK, NULL},
199 {TK_CONFIG_BITMAP, "-stipple", NULL, NULL, NULL,
200 Tk_Offset(LnArrItem, stipple), TK_CONFIG_NULL_OK, NULL},
201 {TK_CONFIG_CUSTOM, "-shape", "shape", "Shape", "Complex", 0, 0,
202 &shapeOption},
203 {TK_CONFIG_PIXELS, "-dotsize", NULL, NULL, "0",
204 Tk_Offset(LnArrItem, dotSize), 0, NULL},
205 {TK_CONFIG_CUSTOM, "-tags", NULL, NULL, NULL, 0, TK_CONFIG_NULL_OK,
206 &tagsOption},
207 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0, NULL}
208 };
209
210 /*
211 * The structures below defines the geomap_lnarr item type in terms of
212 * procedures that can be invoked by generic item code.
213 */
214
215 static Tk_ItemType geoLnArrType = {
216 "geomap_lnarr", /* item type name */
217 sizeof(LnArrItem), /* itemSize */
218 createProc, /* createProc */
219 configSpecs, /* configSpecs */
220 configProc, /* configureProc */
221 coordProc, /* coordProc */
222 deleteProc, /* deleteProc */
223 displayProc, /* displayProc */
224 TK_CONFIG_OBJS, /* alwaysredraw or flags (?) */
225 pointProc, /* pointProc */
226 areaProc, /* areaProc */
227 postscriptProc, /* postscriptProc */
228 scaleProc, /* scaleProc */
229 translateProc, /* translateProc */
230 (Tk_ItemIndexProc *) NULL, /* indexProc */
231 (Tk_ItemCursorProc *) NULL, /* icursorProc */
232 (Tk_ItemSelectionProc *) NULL, /* selectionProc */
233 (Tk_ItemInsertProc *) NULL, /* insertProc */
234 (Tk_ItemDCharsProc *) NULL, /* dTextProc */
235 (Tk_ItemType *) NULL, /* nextPtr */
236 };
237
238 /*
239 *------------------------------------------------------------------------
240 *
241 * TkgeomapLnArrInit --
242 *
243 * This procedure adds the geomap_lnarr item type to the canvas widget.
244 * See the user documentation for a description of the its effect
245 * on Tcl.
246 *
247 * Results:
248 * A standard Tcl result.
249 *
250 * Side effects:
251 * Prerequisite packages are initialized, and the "geomap_lnarr" item is
252 * added to the Tk canvas interface.
253 *
254 *------------------------------------------------------------------------
255 */
256
257 int
TkgeomapLnArrInit(interp)258 TkgeomapLnArrInit(interp)
259 Tcl_Interp *interp; /* Current interpreter */
260 {
261 static int loaded; /* If true, package is loaded */
262
263 if (loaded) {
264 return TCL_OK;
265 }
266 #ifdef USE_TCL_STUBS
267 if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
268 return TCL_ERROR;
269 }
270 #endif
271 #ifdef USE_TK_STUBS
272 if (Tk_InitStubs(interp, TK_VERSION, 0) == NULL) {
273 return TCL_ERROR;
274 }
275 #endif
276
277 /*
278 * Set tagsOption. This must be done at run time because the stubs
279 * library set the functions to non-static values, so they cannot be
280 * used in an initializer.
281 */
282
283 tagsOption.parseProc = Tk_CanvasTagsParseProc;
284 tagsOption.printProc = Tk_CanvasTagsPrintProc;
285
286 Tk_CreateItemType(&geoLnArrType);
287 loaded = 1;
288 return TCL_OK;
289 }
290
291 /*
292 *--------------------------------------------------------------
293 *
294 * createProc --
295 *
296 * This procedure is invoked to create a new geomap_lnarr
297 * item in a canvas.
298 *
299 * Results:
300 * A standard Tcl return value. If an error occurred in
301 * creating the item, then an error message is left in
302 * the interp's result; in this case itemPtr is left uninitialized,
303 * so it can be safely freed by the caller.
304 *
305 * Side effects:
306 * A new geomap_lnarr item is created.
307 *
308 *--------------------------------------------------------------
309 */
310
311 static int
createProc(interp,canvas,itemPtr,objc,objv)312 createProc(interp, canvas, itemPtr, objc, objv)
313 Tcl_Interp *interp; /* Interpreter for error reporting. */
314 Tk_Canvas canvas; /* Canvas to hold new item. */
315 Tk_Item *itemPtr; /* Record to hold new item; header
316 * has been initialized by caller. */
317 int objc; /* Number of arguments in objv. */
318 Tcl_Obj *CONST objv[]; /* Arguments describing linearray. */
319 {
320 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
321 double xRef, yRef;
322
323
324 /*
325 * Set location of reference point from coordinates given on command line.
326 */
327
328 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], &xRef) != TCL_OK)
329 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], &yRef)
330 != TCL_OK)) {
331 return TCL_ERROR;
332 }
333 lnArrItemPtr->xRef = xRef;
334 lnArrItemPtr->yRef = yRef;
335
336 /*
337 * Initialize values. Bogus initializers will be set properly
338 * when the item is configured.
339 */
340
341 lnArrItemPtr->interp = interp;
342 lnArrItemPtr->canvas = canvas;
343 lnArrItemPtr->refPt = GeoPtFmDeg(0.0, 0.0);
344 lnArrItemPtr->proj = NULL;
345 lnArrItemPtr->scale = 0.0;
346 lnArrItemPtr->tclGeoLnArr = NULL;
347 lnArrItemPtr->nLines = 0;
348 lnArrItemPtr->mapLnArr = NULL;
349 lnArrItemPtr->coordPtrPtr = NULL;
350 lnArrItemPtr->nPtsPtr = NULL;
351 lnArrItemPtr->updateMap = 1;
352 lnArrItemPtr->updateCvs = 1;
353 lnArrItemPtr->width = 0;
354 lnArrItemPtr->lineColor = None;
355 lnArrItemPtr->lineStyle = LineSolid;
356 lnArrItemPtr->dashes = 4;
357 lnArrItemPtr->lineGC = None;
358 lnArrItemPtr->fillColor = None;
359 lnArrItemPtr->stipple = None;
360 lnArrItemPtr->shape = Nonconvex;
361 lnArrItemPtr->fillGC = None;
362 lnArrItemPtr->dotSize = 0;
363
364 /*
365 * Configure the new geomap_lnarr item.
366 */
367
368 if (configProc(interp, canvas, itemPtr, objc - 2, objv + 2, 0) != TCL_OK) {
369 deleteProc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
370 return TCL_ERROR;
371 }
372
373 return TCL_OK;
374 }
375
376 /*
377 *------------------------------------------------------------------------
378 *
379 * parseGeoLnArrOption --
380 *
381 * This procedure is invoked during option processing to handle
382 * the "-lnarr" option.
383 *
384 * Results:
385 * A standard Tcl result.
386 *
387 * Side effects:
388 * The state for a given item gets replaced by the state
389 * indicated in the value argument.
390 *
391 *------------------------------------------------------------------------
392 */
393
394 static int
parseGeoLnArrOption(clientData,interp,tkwin,value,widgRec,offset)395 parseGeoLnArrOption(clientData, interp, tkwin, value, widgRec, offset)
396 ClientData clientData; /* Not used */
397 Tcl_Interp *interp; /* Current interpreter */
398 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
399 char *value; /* Value of the option */
400 char *widgRec; /* Pointer to item record */
401 int offset; /* Offset into widgRec */
402 {
403 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
404 char *arrNm = value;
405 Tclgeomap_LnArr tclGeoLnArr;
406 int n;
407
408 if ( strlen(value) > 0 ) {
409 /*
410 * User has requested that a linearray be displayed in the item.
411 */
412
413 tclGeoLnArr = Tclgeomap_GetLnArr(interp, arrNm);
414 if ( !tclGeoLnArr ) {
415 Tcl_AppendResult(interp, "No linearray named ", value, NULL);
416 return TCL_ERROR;
417 }
418 if ( tclGeoLnArr == lnArrItemPtr->tclGeoLnArr ) {
419 return TCL_OK;
420 }
421 if (lnArrItemPtr->tclGeoLnArr) {
422 Tclgeomap_CnxLnArrDeleteTask(lnArrItemPtr->tclGeoLnArr,
423 lnArrItemPtr);
424 }
425 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
426 lnArrItemPtr->mapLnArr = NULL;
427 lnArrItemPtr->updateMap = 1;
428 for (n = 0; n < lnArrItemPtr->nLines; n++) {
429 CKFREE((char *)lnArrItemPtr->coordPtrPtr[n]);
430 lnArrItemPtr->coordPtrPtr[n] = NULL;
431 }
432 lnArrItemPtr->tclGeoLnArr = tclGeoLnArr;
433 Tclgeomap_AddLnArrDeleteTask(tclGeoLnArr, forgetLnArr, lnArrItemPtr);
434 lnArrItemPtr->nLines = 0;
435 } else {
436 /*
437 * User has requested that NO linearray be displayed in the item.
438 */
439
440 if (lnArrItemPtr->tclGeoLnArr) {
441 Tclgeomap_CnxLnArrDeleteTask(lnArrItemPtr->tclGeoLnArr,
442 lnArrItemPtr);
443 for (n = 0; n < lnArrItemPtr->nLines; n++) {
444 CKFREE((char *)lnArrItemPtr->coordPtrPtr[n]);
445 lnArrItemPtr->coordPtrPtr[n] = NULL;
446 }
447 lnArrItemPtr->tclGeoLnArr = NULL;
448 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
449 lnArrItemPtr->mapLnArr = NULL;
450 lnArrItemPtr->updateMap = 0;
451 lnArrItemPtr->nLines = 0;
452 }
453 }
454 return TCL_OK;
455 }
456
457 /*
458 *------------------------------------------------------------------------
459 *
460 * printGeoLnArrOption --
461 *
462 * This procedure is invoked by the Tk configuration code
463 * to produce a printable string for the "-refpoint" configuration
464 * option.
465 *
466 * Results:
467 * The return value is a string describing the state for
468 * the item referred to by "widgRec". In addition, *freeProcPtr
469 * is filled in with the address of a procedure to call to free
470 * the result string when it's no longer needed.
471 *
472 * Side effects:
473 * None.
474 *
475 *------------------------------------------------------------------------
476 */
477
478 static char *
printGeoLnArrOption(clientData,tkwin,widgRec,offset,freeProc)479 printGeoLnArrOption(clientData, tkwin, widgRec, offset, freeProc)
480 ClientData clientData; /* Not used */
481 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
482 char *widgRec; /* Pointer to item record */
483 int offset; /* Offset into widgRec */
484 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
485 * information about how to reclaim
486 * storage for return string. */
487 {
488 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
489 CONST char *arrNm;
490 char *rtn;
491
492 arrNm = lnArrItemPtr->tclGeoLnArr
493 ? Tclgeomap_LnArrName(lnArrItemPtr->tclGeoLnArr)
494 : "";
495 rtn = Tcl_Alloc(strlen(arrNm) + 1);
496 strcpy(rtn, arrNm);
497 *freeProc = Tcl_Free;
498 return rtn;
499 }
500
501 /*
502 *------------------------------------------------------------------------
503 *
504 * parseRefPtOption --
505 *
506 * This procedure is invoked during option processing to handle
507 * the "-refpoint" option.
508 *
509 * Results:
510 * A standard Tcl result.
511 *
512 * Side effects:
513 * The state for a given item gets replaced by the state
514 * indicated in the value argument.
515 *
516 *------------------------------------------------------------------------
517 */
518
519 static int
parseRefPtOption(clientData,interp,tkwin,value,widgRec,offset)520 parseRefPtOption(clientData, interp, tkwin, value, widgRec, offset)
521 ClientData clientData; /* Not used */
522 Tcl_Interp *interp; /* Current interpreter */
523 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
524 char *value; /* Value of the option */
525 char *widgRec; /* Pointer to item record */
526 int offset; /* Offset into widgRec */
527 {
528
529 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
530 GeoPt refPt;
531 double lat, lon;
532
533 if (sscanf(value, "%lf %lf", &lat, &lon) == 2) {
534 refPt = GeoPtFmDeg(lat, lon);
535 lnArrItemPtr->refPt = GwchLonPt(refPt);
536 lnArrItemPtr->updateMap = lnArrItemPtr->updateCvs = 1;
537 return TCL_OK;
538 } else {
539 Tcl_AppendResult(interp, "Expected {lat lon}, got ", value, NULL);
540 return TCL_ERROR;
541 }
542 }
543
544 /*
545 *------------------------------------------------------------------------
546 *
547 * printRefPtOption --
548 *
549 * This procedure is invoked by the Tk configuration code
550 * to produce a printable string for the "-refpoint" configuration
551 * option.
552 *
553 * Results:
554 * The return value is a string describing the state for
555 * the item referred to by "widgRec". In addition, *freeProcPtr
556 * is filled in with the address of a procedure to call to free
557 * the result string when it's no longer needed.
558 *
559 * Side effects:
560 * None.
561 *
562 *------------------------------------------------------------------------
563 */
564
565 static char *
printRefPtOption(clientData,tkwin,widgRec,offset,freeProc)566 printRefPtOption(clientData, tkwin, widgRec, offset, freeProc)
567 ClientData clientData; /* Not used */
568 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
569 char *widgRec; /* Pointer to item record */
570 int offset; /* Offset into widgRec */
571 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
572 * information about how to reclaim
573 * storage for return string. */
574 {
575 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
576 char lat[TCL_DOUBLE_SPACE], lon[TCL_DOUBLE_SPACE];
577 char *coordPtr[2];
578 double dLat, dLon;
579
580 coordPtr[0] = lat;
581 coordPtr[1] = lon;
582 *freeProc = Tcl_Free;
583 GeoPtGetDeg(lnArrItemPtr->refPt, &dLat, &dLon);
584 Tcl_PrintDouble(NULL, dLat, lat);
585 Tcl_PrintDouble(NULL, dLon, lon);
586 return Tcl_Merge(2, coordPtr);
587 }
588
589 /*
590 *------------------------------------------------------------------------
591 *
592 * parseProjOption --
593 *
594 * This procedure is invoked during option processing to handle
595 * the "-projection" option.
596 *
597 * Results:
598 * A standard Tcl result.
599 *
600 * Side effects:
601 * The state for a given item gets replaced by the state
602 * indicated in the value argument.
603 *
604 *------------------------------------------------------------------------
605 */
606
607 static int
parseProjOption(clientData,interp,tkwin,value,widgRec,offset)608 parseProjOption(clientData, interp, tkwin, value, widgRec, offset)
609 ClientData clientData; /* Not used */
610 Tcl_Interp *interp; /* Current interpreter */
611 Tk_Window tkwin; /* Window containing the linearray item */
612 char *value; /* Value of the option */
613 char *widgRec; /* Pointer to item record */
614 int offset; /* Offset into widgRec */
615 {
616 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
617 Tclgeomap_Proj proj;
618
619 if (*value == '\0') {
620 if (lnArrItemPtr->proj) {
621 Tclgeomap_CnxProjUpdateTask(lnArrItemPtr->proj, lnArrItemPtr);
622 Tclgeomap_CnxProjDeleteTask(lnArrItemPtr->proj, lnArrItemPtr);
623 }
624 lnArrItemPtr->proj = NULL;
625 return TCL_OK;
626 }
627 if ( !(proj = Tclgeomap_GetProj(interp, value)) ) {
628 Tcl_AppendResult(interp, "No projection named ", value, NULL);
629 return TCL_ERROR;
630 }
631 if (lnArrItemPtr->proj) {
632 Tclgeomap_CnxProjUpdateTask(lnArrItemPtr->proj, lnArrItemPtr);
633 Tclgeomap_CnxProjDeleteTask(lnArrItemPtr->proj, lnArrItemPtr);
634 }
635 lnArrItemPtr->proj = proj;
636 Tclgeomap_AddProjUpdateTask(lnArrItemPtr->proj, updateMap, lnArrItemPtr);
637 Tclgeomap_AddProjDeleteTask(lnArrItemPtr->proj, forgetProj, lnArrItemPtr);
638 lnArrItemPtr->updateMap = 1;
639 return TCL_OK;
640 }
641
642 /*
643 *------------------------------------------------------------------------
644 *
645 * printProjOption --
646 *
647 * This procedure is invoked by the Tk configuration code
648 * to produce a printable string for the "-projection" configuration
649 * option.
650 *
651 * Results:
652 * The return value is a string describing the state for
653 * the item referred to by "widgRec". In addition, *freeProcPtr
654 * is filled in with the address of a procedure to call to free
655 * the result string when it's no longer needed.
656 *
657 * Side effects:
658 * None.
659 *
660 *------------------------------------------------------------------------
661 */
662
663 static char *
printProjOption(clientData,tkwin,widgRec,offset,freeProc)664 printProjOption(clientData, tkwin, widgRec, offset, freeProc)
665 ClientData clientData; /* Not used */
666 Tk_Window tkwin; /* Window containing the geomap item */
667 char *widgRec; /* Pointer to item record */
668 int offset; /* Offset into widgRec */
669 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
670 * information about how to reclaim
671 * storage for return string. */
672 {
673 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
674 CONST char *projNm;
675 char *rtn;
676
677 projNm = lnArrItemPtr->proj ? Tclgeomap_ProjName(lnArrItemPtr->proj) : "";
678 rtn = Tcl_Alloc(strlen(projNm) + 1);
679 strcpy(rtn, projNm);
680 *freeProc = Tcl_Free;
681 return rtn;
682 }
683
684 /*
685 *------------------------------------------------------------------------
686 *
687 * parseShapeOption --
688 *
689 * This procedure is invoked during option processing to handle
690 * the "-shape" option.
691 *
692 * Results:
693 * A standard Tcl result.
694 *
695 * Side effects:
696 * The state for a given item gets replaced by the state
697 * indicated in the value argument.
698 *
699 *------------------------------------------------------------------------
700 */
701
702 static int
parseShapeOption(clientData,interp,tkwin,value,widgRec,offset)703 parseShapeOption(clientData, interp, tkwin, value, widgRec, offset)
704 ClientData clientData; /* Not used */
705 Tcl_Interp *interp; /* Current interpreter */
706 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
707 char *value; /* Value of the option */
708 char *widgRec; /* Pointer to item record */
709 int offset; /* Offset into widgRec */
710 {
711 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
712
713 if (strcmp(value, "Convex") == 0) {
714 lnArrItemPtr->shape = Convex;
715 } else if (strcmp(value, "Nonconvex") == 0) {
716 lnArrItemPtr->shape = Nonconvex;
717 } else if (strcmp(value, "Complex") == 0) {
718 lnArrItemPtr->shape = Complex;
719 } else {
720 Tcl_AppendResult(interp,
721 "Shape must be \"Convex\", \"Nonconvex\" or \"Complex\"", NULL);
722 return TCL_ERROR;
723 }
724 return TCL_OK;
725 }
726
727 /*
728 *------------------------------------------------------------------------
729 *
730 * printShapeOption --
731 *
732 * This procedure is invoked by the Tk configuration code
733 * to produce a printable string for the "-shape" configuration
734 * option.
735 *
736 * Results:
737 * The return value is a string describing the state for
738 * the item referred to by "widgRec". In addition, *freeProcPtr
739 * is filled in with the address of a procedure to call to free
740 * the result string when it's no longer needed.
741 *
742 * Side effects:
743 * None.
744 *
745 *------------------------------------------------------------------------
746 */
747
748 static char *
printShapeOption(clientData,tkwin,widgRec,offset,freeProc)749 printShapeOption(clientData, tkwin, widgRec, offset, freeProc)
750 ClientData clientData; /* Not used */
751 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
752 char *widgRec; /* Pointer to item record */
753 int offset; /* Offset into widgRec */
754 Tcl_FreeProc **freeProc; /* Not used */
755 {
756 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
757 char *rslt = "Convex";
758
759 switch (lnArrItemPtr->shape) {
760 case Convex:
761 rslt = "Convex";
762 break;
763 case Nonconvex:
764 rslt = "Nonconvex";
765 break;
766 case Complex:
767 rslt = "Complex";
768 break;
769 }
770 return rslt;
771 }
772
773 /*
774 *------------------------------------------------------------------------
775 *
776 * parseLineStyleOption --
777 *
778 * This procedure is invoked during option processing to handle
779 * the "-linestyle" option.
780 *
781 * Results:
782 * A standard Tcl result.
783 *
784 * Side effects:
785 * The state for a given item gets replaced by the state
786 * indicated in the value argument.
787 *
788 *------------------------------------------------------------------------
789 */
790
791 static int
parseLineStyleOption(clientData,interp,tkwin,value,widgRec,offset)792 parseLineStyleOption(clientData, interp, tkwin, value, widgRec, offset)
793 ClientData clientData; /* Not used */
794 Tcl_Interp *interp; /* Current interpreter */
795 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
796 char *value; /* Value of the option */
797 char *widgRec; /* Pointer to item record */
798 int offset; /* Offset into widgRec */
799 {
800 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
801
802 if (strcmp(value, "LineSolid") == 0) {
803 lnArrItemPtr->lineStyle = LineSolid;
804 } else if (strcmp(value, "LineOnOffDash") == 0) {
805 lnArrItemPtr->lineStyle = LineOnOffDash;
806 } else if (strcmp(value, "LineDoubleDash") == 0) {
807 lnArrItemPtr->lineStyle = LineDoubleDash;
808 } else {
809 Tcl_AppendResult(interp,
810 "LineStyle must be \"LineSolid\", \"LineOnOffDash\" or"
811 " \"LineDoubleDash\"", NULL);
812 return TCL_ERROR;
813 }
814 return TCL_OK;
815 }
816
817 /*
818 *------------------------------------------------------------------------
819 *
820 * printLineStyleOption --
821 *
822 * This procedure is invoked by the Tk configuration code
823 * to produce a printable string for the "-linestyle" configuration
824 * option.
825 *
826 * Results:
827 * The return value is a string describing the state for
828 * the item referred to by "widgRec". In addition, *freeProcPtr
829 * is filled in with the address of a procedure to call to free
830 * the result string when it's no longer needed.
831 *
832 * Side effects:
833 * None.
834 *
835 *------------------------------------------------------------------------
836 */
837
838 static char *
printLineStyleOption(clientData,tkwin,widgRec,offset,freeProc)839 printLineStyleOption(clientData, tkwin, widgRec, offset, freeProc)
840 ClientData clientData; /* Not used */
841 Tk_Window tkwin; /* Window containing the geomap_lnarr item */
842 char *widgRec; /* Pointer to item record */
843 int offset; /* Offset into widgRec */
844 Tcl_FreeProc **freeProc; /* Not used */
845 {
846 LnArrItem *lnArrItemPtr = (LnArrItem *)(widgRec + offset);
847 char *rslt = "Convex";
848
849 switch (lnArrItemPtr->lineStyle) {
850 case LineSolid:
851 rslt = "LineSolid";
852 break;
853 case LineOnOffDash:
854 rslt = "LineOnOffDash";
855 break;
856 case LineDoubleDash:
857 rslt = "LineDoubleDash";
858 break;
859 }
860 return rslt;
861 }
862
863 /*
864 *--------------------------------------------------------------
865 *
866 * configProc --
867 *
868 * This procedure is invoked to configure various aspects
869 * of a geomap_lnarr item, such as its anchor position.
870 *
871 * Results:
872 * A standard Tcl result code. If an error occurs, then
873 * an error message is left in the interp's result.
874 *
875 * Side effects:
876 * Configuration information may be set for itemPtr.
877 *
878 *--------------------------------------------------------------
879 */
880
881 static int
configProc(interp,canvas,itemPtr,objc,objv,flags)882 configProc(interp, canvas, itemPtr, objc, objv, flags)
883 Tcl_Interp *interp; /* Used for error reporting. */
884 Tk_Canvas canvas; /* Canvas containing itemPtr. */
885 Tk_Item *itemPtr; /* Geolinearray item to reconfigure. */
886 int objc; /* Number of elements in objv. */
887 Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */
888 int flags; /* Flags to pass to Tk_ConfigureWidget. */
889 {
890 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
891 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
892 unsigned long mask;
893 XGCValues gcVals;
894 GC gc;
895
896 /*
897 * Configure the item.
898 */
899
900 if (Tk_ConfigureWidget(interp, Tk_CanvasTkwin(canvas),
901 geoLnArrType.configSpecs, objc, (char **)objv,
902 (char *)lnArrItemPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
903 return TCL_ERROR;
904 }
905 if (lnArrItemPtr->lineColor != None) {
906 gcVals.foreground = lnArrItemPtr->lineColor->pixel;
907 gcVals.line_width = lnArrItemPtr->width;
908 gcVals.line_style = lnArrItemPtr->lineStyle;
909 gcVals.dashes = lnArrItemPtr->dashes;
910 mask = GCForeground|GCLineWidth|GCLineStyle|GCDashList;
911 gc = Tk_GetGC(tkwin, mask, &gcVals);
912 if (lnArrItemPtr->lineGC != None) {
913 Tk_FreeGC(Tk_Display(tkwin), lnArrItemPtr->lineGC);
914 }
915 lnArrItemPtr->lineGC = gc;
916 }
917
918 if (lnArrItemPtr->fillColor != None) {
919 gcVals.foreground = lnArrItemPtr->fillColor->pixel;
920 mask = GCForeground;
921 if (lnArrItemPtr->stipple != None) {
922 gcVals.stipple = lnArrItemPtr->stipple;
923 gcVals.fill_style = FillStippled;
924 mask |= GCStipple|GCFillStyle;
925 }
926 gc = Tk_GetGC(tkwin, mask, &gcVals);
927 if (lnArrItemPtr->fillGC != None) {
928 Tk_FreeGC(Tk_Display(tkwin), lnArrItemPtr->fillGC);
929 }
930 lnArrItemPtr->fillGC = gc;
931 }
932 updateCvs(lnArrItemPtr);
933 return TCL_OK;
934 }
935
936 /*
937 *--------------------------------------------------------------
938 *
939 * coordProc --
940 *
941 * This procedure is invoked to process the "coords" widget
942 * command on geomap_lnarr items. See the user documentation for
943 * details on what it does.
944 *
945 * Results:
946 * Returns TCL_OK or TCL_ERROR, and sets the interp's result.
947 *
948 * Side effects:
949 * The coordinates for the given item may be changed.
950 *
951 *--------------------------------------------------------------
952 */
953
954 static int
coordProc(interp,canvas,itemPtr,objc,objv)955 coordProc(interp, canvas, itemPtr, objc, objv)
956 Tcl_Interp *interp; /* Used for error reporting. */
957 Tk_Canvas canvas; /* Canvas containing item. */
958 Tk_Item *itemPtr; /* Item whose coordinates are to be
959 * read or modified. */
960 int objc; /* Number of coordinates supplied in
961 * objv. */
962 Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1,
963 * x2, y2, ... */
964 {
965 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
966
967 if (objc == 0) {
968 /*
969 * Set result to item coordinates
970 */
971
972 Tcl_Obj *obj = Tcl_NewObj();
973 Tcl_Obj *subobj = Tcl_NewDoubleObj(lnArrItemPtr->xRef);
974 Tcl_ListObjAppendElement(interp, obj, subobj);
975 subobj = Tcl_NewDoubleObj(lnArrItemPtr->yRef);
976 Tcl_ListObjAppendElement(interp, obj, subobj);
977 Tcl_SetObjResult(interp, obj);
978 } else if (objc == 1) {
979 Tcl_Obj *lineObj, *rslt; /* Result */
980 int nl, np; /* Loop indeces */
981 double *coordPtr; /* Canvas coordinate to put in result */
982
983 if (strcmp(Tcl_GetString(objv[0]), "dump") == 0) {
984 /*
985 * User wants dump of canvas coordinates for the linearray.
986 */
987
988 updateCvs(lnArrItemPtr);
989 rslt = Tcl_NewObj();
990 if (lnArrItemPtr->nLines == 1) {
991 /*
992 * Array has one line. Set result to list of {x y x y ...}
993 * values.
994 */
995
996 for (coordPtr = lnArrItemPtr->coordPtrPtr[0], np = 0;
997 np < lnArrItemPtr->nPtsPtr[0];
998 np++) {
999 Tcl_ListObjAppendElement(interp, rslt,
1000 Tcl_NewDoubleObj(*coordPtr++));
1001 Tcl_ListObjAppendElement(interp, rslt,
1002 Tcl_NewDoubleObj(*coordPtr++));
1003 }
1004 } else {
1005 /*
1006 * If array has several lines, set result to a list of lists of
1007 * {x y x y ...} values.
1008 */
1009
1010 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1011 lineObj = Tcl_NewObj();
1012 for (coordPtr = lnArrItemPtr->coordPtrPtr[nl], np = 0;
1013 np < lnArrItemPtr->nPtsPtr[nl];
1014 np++) {
1015 Tcl_ListObjAppendElement(interp, lineObj,
1016 Tcl_NewDoubleObj(*coordPtr++));
1017 Tcl_ListObjAppendElement(interp, lineObj,
1018 Tcl_NewDoubleObj(*coordPtr++));
1019 }
1020 Tcl_ListObjAppendElement(interp, rslt, lineObj);
1021 }
1022 }
1023 Tcl_SetObjResult(interp, rslt);
1024 return TCL_OK;
1025 } else {
1026 /*
1027 * New coordinates given on command line in form
1028 * "pathName coords {x y}"
1029 */
1030
1031 Tcl_Obj **coordsPtr;
1032 int n;
1033
1034 if (Tcl_ListObjGetElements(interp, objv[0], &n, &coordsPtr)
1035 != TCL_OK || n != 2) {
1036 Tcl_AppendResult(interp, "Could not split coords list\n", NULL);
1037 return TCL_ERROR;
1038 }
1039 if ((Tk_CanvasGetCoordFromObj(interp, canvas, coordsPtr[0],
1040 &lnArrItemPtr->xRef) != TCL_OK)
1041 || (Tk_CanvasGetCoordFromObj(interp, canvas, coordsPtr[1],
1042 &lnArrItemPtr->yRef) != TCL_OK)) {
1043 return TCL_ERROR;
1044 }
1045 lnArrItemPtr-> updateCvs = 1;
1046 updateCvs(lnArrItemPtr);
1047 }
1048 } else if (objc == 2) {
1049 /*
1050 * New coordinates given on command line in form "pathName coords x y"
1051 */
1052
1053 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0],
1054 &lnArrItemPtr->xRef) != TCL_OK)
1055 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1],
1056 &lnArrItemPtr->yRef) != TCL_OK)) {
1057 return TCL_ERROR;
1058 }
1059 lnArrItemPtr-> updateCvs = 1;
1060 updateCvs(lnArrItemPtr);
1061 } else {
1062 Tcl_AppendResult(interp, "Coordinates must be specified as",
1063 " \"x y\" or \"{x y}\" or \"dump\"", NULL);
1064 return TCL_ERROR;
1065 }
1066 return TCL_OK;
1067 }
1068
1069 /*
1070 *--------------------------------------------------------------
1071 *
1072 * deleteProc --
1073 *
1074 * This procedure is called to clean up the data structure
1075 * associated with a geomap_lnarr item.
1076 *
1077 * Results:
1078 * None.
1079 *
1080 * Side effects:
1081 * Resources associated with itemPtr are released.
1082 *
1083 *--------------------------------------------------------------
1084 */
1085
1086 static void
deleteProc(canvas,itemPtr,display)1087 deleteProc(canvas, itemPtr, display)
1088 Tk_Canvas canvas; /* Info about overall canvas widget. */
1089 Tk_Item *itemPtr; /* Item that is being deleted. */
1090 Display *display; /* Display containing window for
1091 * canvas. */
1092 {
1093 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
1094 int nl;
1095
1096 Tclgeomap_CnxProjUpdateTask(lnArrItemPtr->proj, lnArrItemPtr);
1097 Tclgeomap_CnxProjDeleteTask(lnArrItemPtr->proj, lnArrItemPtr);
1098 Tclgeomap_CnxLnArrDeleteTask(lnArrItemPtr->tclGeoLnArr, lnArrItemPtr);
1099 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1100 CKFREE((char *)lnArrItemPtr->coordPtrPtr[nl]);
1101 }
1102 CKFREE((char *)lnArrItemPtr->nPtsPtr);
1103 CKFREE((char *)lnArrItemPtr->coordPtrPtr);
1104 if (lnArrItemPtr->lineGC != None) {
1105 Tk_FreeGC(display, lnArrItemPtr->lineGC);
1106 }
1107 if (lnArrItemPtr->fillGC != None) {
1108 Tk_FreeGC(display, lnArrItemPtr->fillGC);
1109 }
1110 Tk_FreeOptions(geoLnArrType.configSpecs, (char *)lnArrItemPtr,
1111 display, 0);
1112 }
1113
1114 /*
1115 *--------------------------------------------------------------
1116 *
1117 * forgetLnArr --
1118 *
1119 * This procedure modifies a LnArrItem if the linearray it is
1120 * displaying is deleted.
1121 *
1122 * Results:
1123 * None.
1124 *
1125 * Side effects:
1126 * The item is removed from the display and appropriate members are
1127 * updated.
1128 *
1129 *--------------------------------------------------------------
1130 */
1131
1132 static void
forgetLnArr(clientData)1133 forgetLnArr(clientData)
1134 ClientData clientData; /* Geolinearray item */
1135 {
1136 LnArrItem *lnArrItemPtr = (LnArrItem *)clientData;
1137 Tk_Window tkwin = Tk_CanvasTkwin(lnArrItemPtr->canvas);
1138
1139 lnArrItemPtr->tclGeoLnArr = NULL;
1140 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
1141 lnArrItemPtr->mapLnArr = NULL;
1142 lnArrItemPtr->updateMap = 0;
1143 if (lnArrItemPtr->lineGC != None) {
1144 Tk_FreeGC(Tk_Display(tkwin), lnArrItemPtr->lineGC);
1145 }
1146 lnArrItemPtr->lineGC = None;
1147 if (lnArrItemPtr->fillGC != None) {
1148 Tk_FreeGC(Tk_Display(tkwin), lnArrItemPtr->fillGC);
1149 }
1150 lnArrItemPtr->fillGC = None;
1151 hide(lnArrItemPtr);
1152 }
1153
1154 /*
1155 *--------------------------------------------------------------
1156 *
1157 * forgetProj --
1158 *
1159 * This procedure modifies a LnArrItem if the projection it is
1160 * using is deleted.
1161 *
1162 * Results:
1163 * None.
1164 *
1165 * Side effects:
1166 * The item is removed from the display and appropriate members are
1167 * updated.
1168 *
1169 *--------------------------------------------------------------
1170 */
1171
1172 static void
forgetProj(clientData)1173 forgetProj(clientData)
1174 ClientData clientData; /* Geolinearray item */
1175 {
1176 LnArrItem *lnArrItemPtr = (LnArrItem *)clientData;
1177
1178 lnArrItemPtr->proj = NULL;
1179 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
1180 lnArrItemPtr->mapLnArr = NULL;
1181 lnArrItemPtr->updateMap = 0;
1182 hide(lnArrItemPtr);
1183 }
1184
1185 /*
1186 *--------------------------------------------------------------
1187 *
1188 * hide --
1189 *
1190 * This procedure removes a linearray from the display, although the
1191 * item continues to exist.
1192 *
1193 * Results:
1194 * None.
1195 *
1196 * Side effects:
1197 * None.
1198 *
1199 *--------------------------------------------------------------
1200 */
1201
1202 static void
hide(lnArrItemPtr)1203 hide(lnArrItemPtr)
1204 LnArrItem *lnArrItemPtr; /* Linearray to remove from display */
1205 {
1206 int n;
1207
1208 for (n = 0; n < lnArrItemPtr->nLines; n++) {
1209 CKFREE((char *)lnArrItemPtr->coordPtrPtr[n]);
1210 lnArrItemPtr->coordPtrPtr[n] = NULL;
1211 }
1212 lnArrItemPtr->nLines = 0;
1213 Tk_CanvasEventuallyRedraw(lnArrItemPtr->canvas,
1214 lnArrItemPtr->header.x1, lnArrItemPtr->header.y1,
1215 lnArrItemPtr->header.x2, lnArrItemPtr->header.y2);
1216 lnArrItemPtr->header.x1 = lnArrItemPtr->header.y1 = INT_MAX;
1217 lnArrItemPtr->header.x2 = lnArrItemPtr->header.y2 = INT_MIN;
1218 lnArrItemPtr->updateCvs = 0;
1219 }
1220
1221 /*
1222 *--------------------------------------------------------------
1223 *
1224 * displayProc --
1225 *
1226 * This procedure is invoked to draw a geomap_lnarr item in a given
1227 * drawable.
1228 *
1229 * Results:
1230 * None.
1231 *
1232 * Side effects:
1233 * ItemPtr is drawn in drawable using the transformation
1234 * information in canvas.
1235 *
1236 *--------------------------------------------------------------
1237 */
1238
1239 static void
displayProc(canvas,itemPtr,display,drawable,x,y,width,height)1240 displayProc(canvas, itemPtr, display, drawable, x, y, width, height)
1241 Tk_Canvas canvas; /* Canvas that contains item. */
1242 Tk_Item *itemPtr; /* Item to be displayed. */
1243 Display *display; /* Display on which to draw item. */
1244 Drawable drawable; /* Pixmap or window in which to draw
1245 * item. */
1246 int x, y, width, height; /* Describes region of canvas that
1247 * must be redisplayed. */
1248 {
1249 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
1250 static XPoint *xPtsPtr;
1251 XPoint *pPtr, *ePtr;
1252 double *coordPtr, xc, yc;
1253 unsigned sz, nl, nMax;
1254 int nPts;
1255 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
1256
1257 if (!tkwin || !Tk_IsMapped(tkwin)) {
1258 return;
1259 }
1260 if ( lnArrItemPtr->nLines == 0 || !lnArrItemPtr->nPtsPtr
1261 || !lnArrItemPtr->coordPtrPtr ) {
1262 return;
1263 }
1264 if (lnArrItemPtr->updateMap) {
1265 updateMap(lnArrItemPtr);
1266 }
1267 if ( !lnArrItemPtr->mapLnArr ) {
1268 return;
1269 }
1270 if (lnArrItemPtr->updateCvs) {
1271 updateCvs(lnArrItemPtr);
1272 }
1273
1274 nMax = lnArrItemPtr->nMax;
1275 if ((lnArrItemPtr->smooth) && (nMax > 2)) {
1276 sz = sizeof(XPoint) * TkgeomapMakeBezierCurve(canvas, NULL,
1277 (int)nMax, lnArrItemPtr->splineSteps, NULL, NULL);
1278 } else {
1279 sz = sizeof(XPoint) * nMax;
1280 }
1281 if (sz == 0) {
1282 return;
1283 } else {
1284 xPtsPtr = (XPoint *)CKREALLOC((char *)xPtsPtr, sz);
1285 }
1286
1287 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1288
1289 nPts = lnArrItemPtr->nPtsPtr[nl];
1290
1291 /*
1292 * Put the shape into drawable (X) coordinates.
1293 */
1294
1295 if ((lnArrItemPtr->smooth) && (nMax > 2)) {
1296 nPts = TkgeomapMakeBezierCurve(canvas,
1297 lnArrItemPtr->coordPtrPtr[nl], nPts,
1298 lnArrItemPtr->splineSteps, xPtsPtr, NULL);
1299 } else {
1300 for (pPtr = xPtsPtr, ePtr = pPtr + nPts,
1301 coordPtr = lnArrItemPtr->coordPtrPtr[nl];
1302 pPtr < ePtr; pPtr++) {
1303 xc = *coordPtr++;
1304 yc = *coordPtr++;
1305 Tk_CanvasDrawableCoords(canvas, xc, yc, &pPtr->x, &pPtr->y);
1306 }
1307 }
1308
1309 /*
1310 * Fill in the area.
1311 */
1312
1313 if (lnArrItemPtr->fillColor != None) {
1314 XFillPolygon(display, drawable, lnArrItemPtr->fillGC, xPtsPtr,
1315 nPts, lnArrItemPtr->shape, CoordModeOrigin);
1316 }
1317
1318
1319 /*
1320 * Draw the line segments.
1321 */
1322
1323 if (lnArrItemPtr->width > 0
1324 && lnArrItemPtr->lineColor != None) {
1325 XDrawLines(display, drawable, lnArrItemPtr->lineGC, xPtsPtr,
1326 nPts, CoordModeOrigin);
1327 }
1328
1329 /*
1330 * Draw dots at segment endpoints.
1331 */
1332
1333 if (lnArrItemPtr->dotSize > 0 && lnArrItemPtr->lineColor != None) {
1334 for (pPtr = xPtsPtr, ePtr = pPtr + nPts,
1335 coordPtr = lnArrItemPtr->coordPtrPtr[nl];
1336 pPtr < ePtr; pPtr++) {
1337 unsigned dotSize = lnArrItemPtr->dotSize;
1338 int spShift = dotSize / 2;
1339 short x, y;
1340
1341 xc = *coordPtr++;
1342 yc = *coordPtr++;
1343 Tk_CanvasDrawableCoords(canvas, xc, yc, &x, &y);
1344 if (dotSize == 1) {
1345 XDrawPoint(display, drawable, lnArrItemPtr->lineGC, x, y);
1346 } else {
1347 XFillArc(display, drawable, lnArrItemPtr->lineGC,
1348 x - spShift, y - spShift, dotSize, dotSize,
1349 0, 23040);
1350 }
1351 }
1352 }
1353 }
1354 }
1355
1356 /*
1357 *--------------------------------------------------------------
1358 *
1359 * pointProc --
1360 *
1361 * Computes the distance from a given point to a given
1362 * geomap_lnarr item, in canvas units.
1363 *
1364 * Results:
1365 * The return value is 0.0 if the point whose x and y coordinates
1366 * are pointPtr[0] and pointPtr[1] is inside the geomap_lnarr. If the
1367 * point isn't inside the geomap_lnarr then the return value is the
1368 * distance from the point to the geomap_lnarr.
1369 *
1370 * Side effects:
1371 * None.
1372 *
1373 *--------------------------------------------------------------
1374 */
1375
1376 static double
pointProc(canvas,itemPtr,pointPtr)1377 pointProc(canvas, itemPtr, pointPtr)
1378 Tk_Canvas canvas; /* Canvas containing item. */
1379 Tk_Item *itemPtr; /* Item to check against point. */
1380 double *pointPtr; /* Pointer to x and y coordinates. */
1381 {
1382 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
1383 int nl, np, nPair;
1384 double **coordPtrPtr;
1385 int *nPtsPtr;
1386 double x0 = pointPtr[0], y0 = pointPtr[1];
1387 double end1Ptr[2], end2Ptr[2];
1388 double *coordPtr;
1389 double d, dx, dy, closest;
1390
1391 if (lnArrItemPtr->updateCvs) {
1392 updateCvs(lnArrItemPtr);
1393 }
1394 if ( !itemPtr || !lnArrItemPtr->coordPtrPtr || lnArrItemPtr->nLines == 0 ) {
1395 return DBL_MAX;
1396 }
1397 coordPtrPtr = lnArrItemPtr->coordPtrPtr;
1398 nPtsPtr = lnArrItemPtr->nPtsPtr;
1399 if (lnArrItemPtr->fillColor != None) {
1400 /*
1401 * Treat all lines as closed polygons.
1402 */
1403
1404 closest = DBL_MAX;
1405 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1406 d = TkgeomapPolygonToPoint(coordPtrPtr[nl], nPtsPtr[nl], pointPtr);
1407 if (d == 0.0) {
1408 return 0.0;
1409 } else if (d < closest) {
1410 closest = d;
1411 }
1412 }
1413 } else if (lnArrItemPtr->width < 0) {
1414 /*
1415 * Points are not connected. Return distance to nearest point.
1416 */
1417
1418 closest = DBL_MAX;
1419 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1420 coordPtr = coordPtrPtr[nl];
1421 for (np = 0; np < nPtsPtr[nl]; np++) {
1422 dx = x0 - *coordPtr++;
1423 dy = y0 - *coordPtr++;
1424 d = dx * dx + dy * dy;
1425 closest = (d < closest) ? d : closest;
1426 }
1427 }
1428 closest = sqrt(closest);
1429 } else {
1430 /*
1431 * Lines are either closed polygons that are not filled, or they
1432 * are open.
1433 */
1434
1435 closest = DBL_MAX;
1436 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1437 coordPtr = coordPtrPtr[nl];
1438 nPair = nPtsPtr[nl] - 1;
1439 if (nPair == 0) {
1440 continue;
1441 }
1442 for (np = 0, coordPtr = coordPtrPtr[nl];
1443 np < nPair; np++, coordPtr += 2) {
1444 end1Ptr[0] = coordPtr[0];
1445 end1Ptr[1] = coordPtr[1];
1446 end2Ptr[0] = coordPtr[2];
1447 end2Ptr[1] = coordPtr[3];
1448 d = TkgeomapLineToPoint(end1Ptr, end2Ptr, pointPtr);
1449 closest = (d < closest) ? d : closest;
1450 }
1451 }
1452 }
1453 return closest;
1454 }
1455
1456 /*
1457 *--------------------------------------------------------------
1458 *
1459 * areaProc --
1460 *
1461 * This procedure is called to determine whether an item
1462 * lies entirely inside, entirely outside, or overlapping
1463 * a given rectangle.
1464 *
1465 * Results:
1466 * -1 is returned if the item is entirely outside the area
1467 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
1468 * inside the given area.
1469 *
1470 * Side effects:
1471 * None.
1472 *
1473 *--------------------------------------------------------------
1474 */
1475
areaProc(canvas,itemPtr,rectPtr)1476 static int areaProc(canvas, itemPtr, rectPtr)
1477 Tk_Canvas canvas; /* Canvas containing item. */
1478 Tk_Item *itemPtr; /* Item to check against rectangle. */
1479 double *rectPtr; /* Pointer to array of four coordinates
1480 * (x1, y1, x2, y2) describing rectangular
1481 * area. */
1482 {
1483 LnArrItem *lnArrItemPtr = (LnArrItem *)itemPtr;
1484 double x1, y1, x2, y2; /* Limits of rectPtr */
1485 double x, y;
1486 int nl, np, nPts;
1487 double **coordPtrPtr = lnArrItemPtr->coordPtrPtr;
1488 int *nPtsPtr = lnArrItemPtr->nPtsPtr;
1489 double end1Ptr[2], end2Ptr[2];
1490 double *coordPtr;
1491 int currInside, prevInside; /* Status of current and previous polygon, line,
1492 * or point. 1 means inside, 0 means
1493 * overlapping, and -1 means outside. */
1494
1495 if (lnArrItemPtr->updateCvs) {
1496 updateCvs(lnArrItemPtr);
1497 }
1498 if ( !lnArrItemPtr->coordPtrPtr || lnArrItemPtr->nLines == 0 ) {
1499 return -1;
1500 }
1501 x1 = rectPtr[0];
1502 y1 = rectPtr[1];
1503 x2 = rectPtr[2];
1504 y2 = rectPtr[3];
1505 if (lnArrItemPtr->fillColor != None) {
1506 /*
1507 * Treat all lines as closed polygons.
1508 */
1509
1510 prevInside = currInside
1511 = TkgeomapPolygonToArea(coordPtrPtr[0], nPtsPtr[0], rectPtr);
1512 for (nl = 1; nl < lnArrItemPtr->nLines; nl++) {
1513 currInside = TkgeomapPolygonToPoint(coordPtrPtr[nl], nPtsPtr[nl],
1514 rectPtr);
1515 if (currInside == 0 || currInside != prevInside) {
1516 return 0;
1517 }
1518 prevInside = currInside;
1519 }
1520 return currInside;
1521 } else if (lnArrItemPtr->width < 0) {
1522 /*
1523 * Points are not connected.
1524 */
1525
1526 x = coordPtrPtr[0][0];
1527 y = coordPtrPtr[0][1];
1528 prevInside = currInside
1529 = (x > x1 && x < x2 && y > y1 && y < y2) ? 1 : 0;
1530 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1531 coordPtr = coordPtrPtr[nl];
1532 for (np = 0; np < nPtsPtr[nl]; np++) {
1533 x = *coordPtr++;
1534 y = *coordPtr++;
1535 currInside = (x > x1 && x < x2 && y > y1 && y < y2) ? 1 : 0;
1536 if (currInside != prevInside) {
1537 return 0;
1538 }
1539 prevInside = currInside;
1540 }
1541 }
1542 return currInside;
1543 } else {
1544 /*
1545 * Lines are either closed polygons that are not filled, or they
1546 * are open lines.
1547 */
1548
1549 nPts = nPtsPtr[0];
1550 end1Ptr[0] = coordPtrPtr[0][0];
1551 end1Ptr[1] = coordPtrPtr[0][1];
1552 end2Ptr[0] = coordPtrPtr[0][2 * nPts - 2];
1553 end2Ptr[1] = coordPtrPtr[0][2 * nPts - 1];
1554 if ((end1Ptr[0] == end2Ptr[0]) && (end1Ptr[1] == end2Ptr[1])) {
1555 /*
1556 * First line in the linearray is closed. Treat it as a
1557 * polygon.
1558 */
1559
1560 prevInside = currInside
1561 = TkgeomapPolygonToArea(coordPtrPtr[0], nPts, rectPtr);
1562 if (lnArrItemPtr->nLines == 1) {
1563 return prevInside;
1564 }
1565
1566 } else {
1567 /*
1568 * First line in the linearray is open. Compute the distances
1569 * to the segments.
1570 */
1571
1572 x = coordPtrPtr[0][0];
1573 y = coordPtrPtr[0][1];
1574 prevInside = currInside
1575 = (x > x1 && x < x2 && y > y1 && y < y2) ? 1 : 0;
1576 coordPtr = coordPtrPtr[0];
1577 for (np = 0; np < nPtsPtr[0]; np++) {
1578 x = *coordPtr++;
1579 y = *coordPtr++;
1580 currInside = (x > x1 && x < x2 && y > y1 && y < y2) ? 1 : 0;
1581 if (currInside != prevInside) {
1582 return 0;
1583 }
1584 currInside = prevInside;
1585 }
1586 }
1587 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1588 coordPtr = coordPtrPtr[nl];
1589 nPts = nPtsPtr[nl];
1590 end1Ptr[0] = coordPtr[0];
1591 end1Ptr[1] = coordPtr[1];
1592 end2Ptr[0] = coordPtr[2 * nPts - 2];
1593 end2Ptr[1] = coordPtr[2 * nPts - 1];
1594 if ((end1Ptr[0] == end2Ptr[0]) && (end1Ptr[1] == end2Ptr[1])) {
1595 /*
1596 * This line in the linearray is closed. Treat it as a
1597 * polygon.
1598 */
1599
1600 currInside = TkgeomapPolygonToArea(coordPtrPtr[0], nPts,
1601 rectPtr);
1602 if (currInside != prevInside) {
1603 return 0;
1604 }
1605 currInside = prevInside;
1606 } else {
1607 /*
1608 * This line in the linearray is open. Compute the distances
1609 * to the segments.
1610 */
1611
1612 for (np = 0; np < nPts; np++) {
1613 x = *coordPtr++;
1614 y = *coordPtr++;
1615 currInside = (x > x1 && x < x2 && y > y1 && y < y2) ? 1 : 0;
1616 if (currInside != prevInside) {
1617 return 0;
1618 }
1619 currInside = prevInside;
1620 }
1621 }
1622 }
1623 }
1624 return -1;
1625 }
1626
1627 /*
1628 *--------------------------------------------------------------
1629 *
1630 * postscriptProc --
1631 *
1632 * This procedure is called to generate Postscript for
1633 * geomap_lnarr items.
1634 *
1635 * Results:
1636 * The return value is a standard Tcl result. If an error
1637 * occurs in generating Postscript then an error message is
1638 * left in interp->result, replacing whatever used to be there.
1639 * If no error occurs, then Postscript for the item is appended
1640 * to the result.
1641 *
1642 * Side effects:
1643 * None.
1644 *
1645 *--------------------------------------------------------------
1646 */
1647
1648 static int
postscriptProc(interp,canvas,itemPtr,prepass)1649 postscriptProc(interp, canvas, itemPtr, prepass)
1650 Tcl_Interp *interp; /* Leave Postscript or error message
1651 * here. */
1652 Tk_Canvas canvas; /* Information about overall canvas. */
1653 Tk_Item *itemPtr; /* Item for which Postscript is
1654 * wanted. */
1655 int prepass; /* 1 means this is a prepass to
1656 * collect font information; 0 means
1657 * final Postscript is being created.*/
1658 {
1659 LnArrItem *lnArrItemPtr; /* Geomap in which to draw line array */
1660 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
1661 static double *coord1Ptr; /* Array of canvas coordinates for
1662 * one line. This pointer holds
1663 * the result of CKREALLOC. */
1664 double *coordPtr; /* Array of canvas coordinates for
1665 * one line. May be the same as
1666 * coord1Ptr, or may point into the
1667 * item's coordinates array. */
1668 double x, y;
1669 int nl, nPts, np; /* Loop indices and limits */
1670 char bytes[200]; /* Printing space */
1671 double cnr[8]; /* 4 corner points in canvas coord's */
1672
1673 lnArrItemPtr = (LnArrItem *)itemPtr;
1674 if ( !lnArrItemPtr->tclGeoLnArr ) {
1675 return TCL_OK;
1676 }
1677 if (lnArrItemPtr->updateMap) {
1678 updateMap(lnArrItemPtr);
1679 }
1680 if (lnArrItemPtr->updateCvs) {
1681 updateCvs(lnArrItemPtr);
1682 }
1683 if ( !lnArrItemPtr->mapLnArr || lnArrItemPtr->nLines == 0
1684 || !lnArrItemPtr->nPtsPtr || !lnArrItemPtr->coordPtrPtr) {
1685 Tcl_AppendResult(interp,
1686 "Could not generate postscript for linearray ",
1687 Tclgeomap_LnArrName(lnArrItemPtr->tclGeoLnArr), NULL);
1688 return TCL_ERROR;
1689 }
1690
1691 Tcl_AppendResult(interp, "%% Drawing linearray ",
1692 Tclgeomap_LnArrName(lnArrItemPtr->tclGeoLnArr), "\n", NULL);
1693
1694 /*
1695 * Create clipping region for item
1696 */
1697
1698 Tcl_AppendResult(interp, "%% Create clipping region for item\n", NULL);
1699 cnr[0] = 0;
1700 cnr[1] = 0;
1701 cnr[2] = Tk_Width(tkwin);
1702 cnr[3] = 0;
1703 cnr[4] = Tk_Width(tkwin);
1704 cnr[5] = Tk_Height(tkwin);
1705 cnr[6] = 0;
1706 cnr[7] = Tk_Height(tkwin);
1707 Tk_CanvasPsPath(interp, canvas, cnr, 4);
1708 Tcl_AppendResult(interp, "closepath clip\n", NULL);
1709
1710 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
1711
1712 nPts = lnArrItemPtr->nPtsPtr[nl];
1713 if (nPts == 0) {
1714 continue;
1715 }
1716 if ( !lnArrItemPtr->smooth || nPts < 3 ) {
1717 coordPtr = lnArrItemPtr->coordPtrPtr[nl];
1718 } else {
1719 nPts = TkgeomapMakeBezierCurve(canvas, NULL,
1720 lnArrItemPtr->nPtsPtr[nl], lnArrItemPtr->splineSteps,
1721 NULL, NULL);
1722 coordPtr = coord1Ptr = (double *)CKREALLOC((char *)coord1Ptr,
1723 nPts * 2 * sizeof(double));
1724 nPts = TkgeomapMakeBezierCurve(canvas,
1725 lnArrItemPtr->coordPtrPtr[nl], lnArrItemPtr->nPtsPtr[nl],
1726 lnArrItemPtr->splineSteps, NULL, coordPtr);
1727 }
1728
1729 /*
1730 * Fill in the area.
1731 */
1732
1733 if (lnArrItemPtr->fillColor) {
1734 Tk_CanvasPsColor(interp, canvas, lnArrItemPtr->fillColor);
1735 Tcl_AppendResult(interp, "newpath\n", NULL);
1736 Tk_CanvasPsPath(interp, canvas, coordPtr, nPts);
1737 Tcl_AppendResult(interp, "closepath\n", NULL);
1738 if (lnArrItemPtr->stipple != None) {
1739 Tcl_AppendResult(interp, "clip\n", NULL);
1740 Tcl_AppendResult(interp, "newpath\n", NULL);
1741 Tk_CanvasPsPath(interp, canvas, coordPtr, nPts);
1742 Tcl_AppendResult(interp, "closepath\n", NULL);
1743 if (Tk_CanvasPsStipple(interp, canvas, lnArrItemPtr->stipple)
1744 == TCL_ERROR) {
1745 return TCL_ERROR;
1746 }
1747 } else {
1748 Tcl_AppendResult(interp, "fill\n", NULL);
1749 }
1750 }
1751
1752 /*
1753 * Draw the outline.
1754 */
1755
1756 if (lnArrItemPtr->width > 0
1757 && lnArrItemPtr->lineColor != None) {
1758 sprintf(bytes, "%d", lnArrItemPtr->width);
1759 Tcl_AppendResult(interp, bytes, " setlinewidth\n", NULL);
1760 if (lnArrItemPtr->lineStyle == LineSolid) {
1761 Tcl_AppendResult(interp, "[] 0 setdash\n", NULL);
1762 } else if (lnArrItemPtr->lineStyle == LineOnOffDash) {
1763 sprintf(bytes, "[%d %d] 0 setdash\n",
1764 lnArrItemPtr->dashes, lnArrItemPtr->dashes);
1765 Tcl_AppendResult(interp, bytes, NULL);
1766 }
1767 Tk_CanvasPsColor(interp, canvas, lnArrItemPtr->lineColor);
1768 Tcl_AppendResult(interp, "newpath\n", NULL);
1769 Tk_CanvasPsPath(interp, canvas, coordPtr, nPts);
1770 Tcl_AppendResult(interp, "stroke\n", NULL);
1771 }
1772
1773 /*
1774 * Draw dots at segment endpoints.
1775 */
1776
1777 if (lnArrItemPtr->dotSize != 0) {
1778 Tk_CanvasPsColor(interp, canvas, lnArrItemPtr->lineColor);
1779 for (np = 0; np < nPts; np++) {
1780 x = *coordPtr++;
1781 y = *coordPtr++;
1782 if (lnArrItemPtr->dotSize != 0) {
1783 sprintf(bytes, "newpath %f %f %f",
1784 x, y, 0.5 * lnArrItemPtr->dotSize);
1785 Tcl_AppendResult(interp, bytes, " 0 360 arc fill\n", NULL);
1786 }
1787 }
1788 }
1789 }
1790
1791 return TCL_OK;
1792 }
1793
1794 /*
1795 *--------------------------------------------------------------
1796 *
1797 * scaleProc --
1798 *
1799 * This function rescales a geomap_lnarr item. It should not be confused
1800 * with the "-scale" configuration option, which sets the cartographic
1801 * scale of the map containing the item.
1802 *
1803 * Results:
1804 * None.
1805 *
1806 * Side effects:
1807 * The reference point for a geomap_lnarr item is moved according to the
1808 * transformation:
1809 * xRef' = originX + scaleX*(xRef-originX)
1810 * yRef' = originY + scaleY*(yRef-originY)
1811 * The geomap_lnarr's points on the canvas may or may not move.
1812 *
1813 *--------------------------------------------------------------
1814 */
1815
1816 static void
scaleProc(canvas,itemPtr,originX,originY,scaleX,scaleY)1817 scaleProc(canvas, itemPtr, originX, originY, scaleX, scaleY)
1818 Tk_Canvas canvas; /* Canvas containing rectangle. */
1819 Tk_Item *itemPtr; /* Rectangle to be scaled. */
1820 double originX, originY; /* Origin about which to scale rect. */
1821 double scaleX; /* Amount to scale in X direction. */
1822 double scaleY; /* Amount to scale in Y direction. */
1823 {
1824 LnArrItem *lnArrItemPtr = (LnArrItem *) itemPtr;
1825
1826 lnArrItemPtr->xRef = originX + scaleX * (lnArrItemPtr->xRef - originX);
1827 lnArrItemPtr->yRef = originY + scaleY * (lnArrItemPtr->yRef - originY);
1828 updateCvs(lnArrItemPtr);
1829 return;
1830 }
1831
1832 /*
1833 *--------------------------------------------------------------
1834 *
1835 * translateProc --
1836 *
1837 * This procedure is called to move an item by a given amount.
1838 *
1839 * Results:
1840 * None.
1841 *
1842 * Side effects:
1843 * The position of the item is offset by (xDelta, yDelta), and
1844 * the bounding box is updated in the generic part of the item
1845 * structure.
1846 *
1847 *--------------------------------------------------------------
1848 */
1849
1850 static void
translateProc(canvas,itemPtr,deltaX,deltaY)1851 translateProc(canvas, itemPtr, deltaX, deltaY)
1852 Tk_Canvas canvas; /* Canvas containing item. */
1853 Tk_Item *itemPtr; /* Item that is being moved. */
1854 double deltaX, deltaY; /* Amount by which item is to be
1855 * moved. */
1856 {
1857 LnArrItem *lnArrItemPtr = (LnArrItem *) itemPtr;
1858
1859 lnArrItemPtr->xRef += deltaX;
1860 lnArrItemPtr->yRef += deltaY;
1861 updateCvs(lnArrItemPtr);
1862 }
1863 /*
1864 *------------------------------------------------------------------------
1865 *
1866 * updateMap --
1867 *
1868 * This procedure updates the map coordinates of a geomap_lnarr item.
1869 *
1870 * Results:
1871 * None.
1872 *
1873 * Side effects:
1874 * The mapLnArr member of the geomap_lnarr item are updated.
1875 *
1876 *------------------------------------------------------------------------
1877 */
1878
1879 static void
updateMap(clientData)1880 updateMap(clientData)
1881 ClientData clientData; /* Geolinearray item to update */
1882 {
1883 LnArrItem *lnArrItemPtr = (LnArrItem *)clientData;
1884 Tk_Canvas canvas = lnArrItemPtr->canvas;
1885 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
1886 Tclgeomap_LnArr tclGeoLnArr = lnArrItemPtr->tclGeoLnArr;
1887 GeoLnArr geoLnArr = (GeoLnArr)lnArrItemPtr->tclGeoLnArr;
1888 Tclgeomap_Proj tclGeoProj = lnArrItemPtr->proj;
1889 GeoProj proj = (GeoProj)tclGeoProj;
1890 MapLnArr mapLnArr = lnArrItemPtr->mapLnArr;
1891
1892 if ( !tclGeoLnArr || !proj ) {
1893 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
1894 lnArrItemPtr->mapLnArr = NULL;
1895 lnArrItemPtr->updateMap = 0;
1896 hide(lnArrItemPtr);
1897 return;
1898 }
1899
1900 if (lnArrItemPtr->mapLnArr) {
1901 MapLnArrDestroy(lnArrItemPtr->mapLnArr);
1902 lnArrItemPtr->mapLnArr = NULL;
1903 }
1904 if ( !(mapLnArr = GeoLnArrToMap(geoLnArr, proj)) ) {
1905 lnArrItemPtr->mapLnArr = NULL;
1906 hide(lnArrItemPtr);
1907 return;
1908 }
1909 lnArrItemPtr->mapLnArr = mapLnArr;
1910 lnArrItemPtr->updateMap = 0;
1911 lnArrItemPtr->updateCvs = 1;
1912 }
1913
1914 /*
1915 *------------------------------------------------------------------------
1916 *
1917 * updateCvs --
1918 *
1919 * This procedure updates the canvas coordinates of a geomap_lnarr item.
1920 *
1921 * Results:
1922 * None.
1923 *
1924 * Side effects:
1925 * The coords member and bounding box of the geomap_lnarr item are updated.
1926 *
1927 *------------------------------------------------------------------------
1928 */
1929
1930 static void
updateCvs(clientData)1931 updateCvs(clientData)
1932 ClientData clientData; /* Geolinearray item to update */
1933 {
1934 LnArrItem *lnArrItemPtr = (LnArrItem *)clientData;
1935 Tk_Canvas canvas = lnArrItemPtr->canvas;
1936 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
1937 Tclgeomap_LnArr tclGeoLnArr = lnArrItemPtr->tclGeoLnArr;
1938 Tclgeomap_Proj tclGeoProj = lnArrItemPtr->proj;
1939 GeoProj proj = (GeoProj)tclGeoProj;
1940 MapLnArr mapLnArr = lnArrItemPtr->mapLnArr;
1941 static Tcl_Obj *cvsPerMObj; /* Object storing measure for 1 meter */
1942 double cvsPerM; /* Canvas units per meter on display */
1943 double cvsPerMapM; /* Canvas units per meter on map
1944 * (2D surface which contains projected
1945 * and rotated lat-lons) */
1946 double xRef = lnArrItemPtr->xRef;
1947 double yRef = lnArrItemPtr->yRef;
1948 int x, y;
1949 int x1, y1, x2, y2;
1950 int width, height;
1951 MapPt mRefPt; /* Reference point in map coordinates */
1952 double ordMax, absMax, ordMin, absMin;
1953 unsigned nl, nls, np;
1954 unsigned nlc; /* Number of lines in canvas */
1955 unsigned r; /* Dot radius */
1956 int noLines, noFill; /* Booleans to indicate whether
1957 * anything visible in display */
1958
1959 if ( !tclGeoLnArr || !proj ) {
1960 hide(lnArrItemPtr);
1961 return;
1962 }
1963 if (lnArrItemPtr->updateMap) {
1964 updateMap(lnArrItemPtr);
1965 }
1966 if ( !lnArrItemPtr->mapLnArr ) {
1967 hide(lnArrItemPtr);
1968 return;
1969 }
1970 mapLnArr = lnArrItemPtr->mapLnArr;
1971 noLines = !lnArrItemPtr->lineColor
1972 || (lnArrItemPtr->width <= 0 && lnArrItemPtr->dotSize <= 0);
1973 noFill = !lnArrItemPtr->fillColor;
1974 if (noLines && noFill) {
1975 hide(lnArrItemPtr);
1976 return;
1977 }
1978 mRefPt = LatLonToProj(lnArrItemPtr->refPt, proj);
1979 if ( !cvsPerMObj ) {
1980 cvsPerMObj = Tcl_NewStringObj("100.0c", -1);
1981 }
1982 Tk_CanvasGetCoordFromObj(NULL, canvas, cvsPerMObj, &cvsPerM);
1983 cvsPerMapM = cvsPerM * lnArrItemPtr->scale;
1984 Tk_CanvasEventuallyRedraw(canvas,
1985 lnArrItemPtr->header.x1, lnArrItemPtr->header.y1,
1986 lnArrItemPtr->header.x2, lnArrItemPtr->header.y2);
1987 if (!tkwin || !Tk_IsMapped(tkwin)) {
1988 /*
1989 * If canvas limits are not know yet, draw everything.
1990 */
1991
1992 ordMax = DBL_MAX;
1993 absMax = DBL_MAX;
1994 ordMin = -DBL_MAX;
1995 absMin = -DBL_MAX;
1996 } else {
1997 /*
1998 * If canvas limits are known, only draw lines on canvas.
1999 */
2000
2001 width = Tk_Width(tkwin);
2002 height = Tk_Height(tkwin);
2003 ordMax = mRefPt.ord + yRef / cvsPerMapM;
2004 absMax = mRefPt.abs + (width - xRef) / cvsPerMapM;
2005 ordMin = mRefPt.ord - (height -yRef) / cvsPerMapM;
2006 absMin = mRefPt.abs - xRef / cvsPerMapM;
2007 }
2008 nls = mapLnArr->nLines;
2009 if (nls == 0) {
2010 hide(lnArrItemPtr);
2011 return;
2012 }
2013
2014 /*
2015 * Reinitialize coords arrays and array sizes in lnArrItemPtr.
2016 */
2017
2018 for (nl = 0; nl < lnArrItemPtr->nLines; nl++) {
2019 CKFREE((char *)lnArrItemPtr->coordPtrPtr[nl]);
2020 }
2021 CKFREE((char *)lnArrItemPtr->coordPtrPtr);
2022 lnArrItemPtr->nLines = 0;
2023 lnArrItemPtr->coordPtrPtr = (double **)CKALLOC(nls * sizeof(double *));
2024 for (nl = 0, nlc = 0; nl < nls; nl++) {
2025 lnArrItemPtr->coordPtrPtr[nl] = NULL;
2026 }
2027
2028 CKFREE((char *)lnArrItemPtr->nPtsPtr);
2029 lnArrItemPtr->nPtsPtr = (int *)CKALLOC(nls * sizeof(int));
2030 for (nl = 0, nlc = 0; nl < nls; nl++) {
2031 lnArrItemPtr->nPtsPtr[nl] = 0;
2032 }
2033
2034 x1 = y1 = INT_MAX;
2035 x2 = y2 = INT_MIN;
2036 for (nl = 0, nlc = 0; nl < nls; nl++) {
2037 size_t sz;
2038
2039 /*
2040 * Compute canvas coordinates for one line from mapLnArr,
2041 * if it has points in the window.
2042 */
2043
2044 MapLn mapLn = MapLnArrGetLine(mapLnArr, nl);
2045
2046 /*
2047 * Update bounding box of the linearray.
2048 */
2049
2050 if (mapLn->ordMax > ordMin && mapLn->ordMin < ordMax
2051 && mapLn->absMax > absMin && mapLn->absMin < absMax) {
2052 double *coordPtr;
2053
2054 lnArrItemPtr->nPtsPtr[nlc] = mapLn->nPts;
2055 sz = lnArrItemPtr->nPtsPtr[nlc] * 2 * sizeof(double);
2056 lnArrItemPtr->coordPtrPtr[nlc] = (double *)CKALLOC(sz);
2057 for (np = 0, coordPtr = lnArrItemPtr->coordPtrPtr[nlc];
2058 np < lnArrItemPtr->nPtsPtr[nlc];
2059 np++) {
2060 MapPt mapPt = MapLnGetPt(mapLn, np);
2061 x = xRef + (mapPt.abs - mRefPt.abs) * cvsPerMapM;
2062 x1 = (x < x1) ? x : x1;
2063 x2 = (x > x2) ? x : x2;
2064 *coordPtr++ = x;
2065 y = yRef - (mapPt.ord - mRefPt.ord) * cvsPerMapM;
2066 y1 = (y < y1) ? y : y1;
2067 y2 = (y > y2) ? y : y2;
2068 *coordPtr++ = y;
2069 }
2070
2071 nlc++;
2072 }
2073 }
2074
2075 /*
2076 * Store new coords arrays and array sizes in lnArrItemPtr.
2077 */
2078
2079 if (nlc == 0) {
2080 hide(lnArrItemPtr);
2081 return;
2082 }
2083 lnArrItemPtr->nLines = nlc;
2084 lnArrItemPtr->nMax = mapLnArr->nMax;
2085 r = (lnArrItemPtr->dotSize + 1) / 2;
2086 lnArrItemPtr->header.x1 = x1 - lnArrItemPtr->width - r - 1;
2087 lnArrItemPtr->header.x2 = x2 + lnArrItemPtr->width + r + 1;
2088 lnArrItemPtr->header.y1 = y1 - lnArrItemPtr->width - r - 1;
2089 lnArrItemPtr->header.y2 = y2 + lnArrItemPtr->width + r + 1;
2090 if ( lnArrItemPtr->header.x1 >= lnArrItemPtr->header.x2
2091 || lnArrItemPtr->header.y1 >= lnArrItemPtr->header.y2 ) {
2092 hide(lnArrItemPtr);
2093 return;
2094 }
2095 Tk_CanvasEventuallyRedraw(lnArrItemPtr->canvas,
2096 lnArrItemPtr->header.x1, lnArrItemPtr->header.y1,
2097 lnArrItemPtr->header.x2, lnArrItemPtr->header.y2);
2098 lnArrItemPtr->updateCvs = 0;
2099 }
2100