1 /*
2 * tkgeomapPlace.c --
3 *
4 * This file defines functions that display geoplaces 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: tkgeomapPlace.c,v 1.19 2007/06/26 21:58:34 tkgeomap Exp $
13 *
14 **********************************************************************
15 *
16 */
17
18 #include "tkgeomap.h"
19 #include "tkgeomapInt.h"
20
21 /*
22 * The structure below declares the record for each geoplace 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 * This is NOT necessarily where the place is */
32 GeoPt refPt; /* Geographic coordinates of reference point.
33 * This is NOT necessarily where the place is */
34 MapPt mRefPt; /* Map coordinates of reference point. */
35 Tclgeomap_Place tclGeoPlace;/* Geoplace the item displays */
36 MapPt mapPt; /* Map coordinates of the place. */
37 double xPlc, yPlc; /* Canvas coordinates of the place */
38 Tclgeomap_Proj proj; /* Cartographic projection */
39 double scale; /* Cartographic scale (pure number ratio) */
40 int updateMap; /* If true, recompute place map coordinates */
41 int updateCvs; /* If true, recompute place canvas coord's */
42 XColor *dotColor; /* Dot color */
43 int dotSize; /* Dot size */
44 GC dotGC; /* Graphics context for drawing dot */
45 Pixmap bitmap; /* Bitmap to draw at place */
46 XColor *bmColor; /* Bitmap foreground color */
47 GC bmGC; /* Graphics context for drawing bitmap */
48 char *text; /* Text string to print at place */
49 XColor *textColor; /* Text color */
50 Tk_Font font; /* Text font */
51 Tk_Anchor textAnchor; /* Relative location of text. */
52 GC txtGC; /* Graphics context for drawing text */
53 Tk_TextLayout layout; /* Text layout */
54 int xTxt; /* Offset from place to left edge of text box */
55 int yTxt; /* Offset from place to top of text box */
56 int txtWidth; /* Width of text box */
57 int txtHeight; /* Height of text box */
58 Angle arrow_az; /* Arrow azimuth relative to true north */
59 double arrow_len; /* Arrow length, pixels */
60 double arrow_tip_sz; /* Length of edges of arrow tip, fraction of
61 * arrow length */
62 short arrow_base_x; /* Offset from place to arrow base, in */
63 short arrow_base_y; /* drawable coordinates */
64 short arrow_head_x; /* Offset from place to arrow head, in */
65 short arrow_head_y; /* drawable coordinates */
66 short arrow_ltip_x; /* Offset from arrow head to left side of */
67 short arrow_ltip_y; /* arrow tip, drawable coordinates */
68 short arrow_rtip_x; /* Offset from arrow head right side of */
69 short arrow_rtip_y; /* arrow tip, drawable coordinates */
70 XColor *arrowColor;
71 GC arrowGC; /* Graphics context for drawing arrow */
72 } PlaceItem;
73
74 /*
75 * Prototypes for procedures defined in this file:
76 */
77
78 static int createProc _ANSI_ARGS_((Tcl_Interp *interp,
79 Tk_Canvas canvas, struct Tk_Item *itemPtr,
80 int objc, Tcl_Obj *CONST objv[]));
81 static int configProc _ANSI_ARGS_((Tcl_Interp *interp,
82 Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
83 Tcl_Obj *CONST objv[], int flags));
84 static int coordProc _ANSI_ARGS_((Tcl_Interp *interp,
85 Tk_Canvas canvas, Tk_Item *itemPtr, int objc,
86 Tcl_Obj *CONST objv[]));
87 static void deleteProc _ANSI_ARGS_((Tk_Canvas canvas,
88 Tk_Item *itemPtr, Display *display));
89 static void forgetPlace _ANSI_ARGS_((ClientData clientData));
90 static void forgetProj _ANSI_ARGS_((ClientData clientData));
91 static void hide _ANSI_ARGS_((PlaceItem *plcItemPtr));
92 static void displayProc _ANSI_ARGS_((Tk_Canvas canvas,
93 Tk_Item *itemPtr, Display *display,
94 Drawable dst, int x, int y, int width,
95 int height));
96 static double pointProc _ANSI_ARGS_((Tk_Canvas canvas,
97 Tk_Item *itemPtr, double *coordPtr));
98 static int areaProc _ANSI_ARGS_((Tk_Canvas canvas,
99 Tk_Item *itemPtr, double *rectPtr));
100 static int postscriptProc _ANSI_ARGS_((Tcl_Interp *interp,
101 Tk_Canvas canvas, Tk_Item *itemPtr,
102 int prepass));
103 static void scaleProc _ANSI_ARGS_((Tk_Canvas canvas,
104 Tk_Item *itemPtr, double originX,
105 double originY, double scaleX, double scaleY));
106 static void translateProc _ANSI_ARGS_((Tk_Canvas canvas,
107 Tk_Item *itemPtr, double deltaX,
108 double deltaY));
109 static int parseGeoPlaceOption _ANSI_ARGS_((ClientData clientData,
110 Tcl_Interp *interp, Tk_Window tkwin,
111 char *value, char *widgRec, int offset));
112 static char * printGeoPlaceOption _ANSI_ARGS_((ClientData clientData,
113 Tk_Window tkwin, char *widgRec, int offset,
114 Tcl_FreeProc **freeProcPtr));
115 static void geoPlaceUpdate _ANSI_ARGS_((ClientData clientData));
116 static int parseRefPtOption _ANSI_ARGS_((ClientData clientData,
117 Tcl_Interp *interp, Tk_Window tkwin,
118 char *value, char *widgRec, int offset));
119 static char * printRefPtOption _ANSI_ARGS_((ClientData clientData,
120 Tk_Window tkwin, char *widgRec, int offset,
121 Tcl_FreeProc **freeProcPtr));
122 static int parseProjOption _ANSI_ARGS_((ClientData clientData,
123 Tcl_Interp *interp, Tk_Window tkwin,
124 char *value, char *widgRec, int offset));
125 static char * printProjOption _ANSI_ARGS_((ClientData clientData,
126 Tk_Window tkwin, char *widgRec, int offset,
127 Tcl_FreeProc **freeProcPtr));
128 static int parseArrowOption _ANSI_ARGS_((ClientData clientData,
129 Tcl_Interp *interp, Tk_Window tkwin,
130 char *value, char *widgRec, int offset));
131 static char * printArrowOption _ANSI_ARGS_((ClientData clientData,
132 Tk_Window tkwin, char *widgRec, int offset,
133 Tcl_FreeProc **freeProcPtr));
134 static void computeTextLayout _ANSI_ARGS_((
135 PlaceItem *plcItemPtr));
136 static void updateMap _ANSI_ARGS_((ClientData clientData));
137 static void updateCvs _ANSI_ARGS_((PlaceItem *plcItemPtr));
138
139 /*
140 * Custom configuration options
141 */
142
143 static Tk_CustomOption geoPlaceOption = {
144 parseGeoPlaceOption,
145 printGeoPlaceOption,
146 NULL
147 };
148
149 static Tk_CustomOption refPtOption = {
150 parseRefPtOption,
151 printRefPtOption,
152 NULL
153 };
154
155 static Tk_CustomOption projOption = {
156 parseProjOption,
157 printProjOption,
158 NULL
159 };
160
161 static Tk_CustomOption arrowOption = {
162 parseArrowOption,
163 printArrowOption,
164 NULL
165 };
166
167 /*
168 * The members of tagsOption will be set in TkgeomapPlaceInit
169 */
170
171 static Tk_CustomOption tagsOption = {
172 NULL, NULL, NULL
173 };
174
175 /*
176 * Configuration options for the geoplace item
177 */
178
179 static Tk_ConfigSpec configSpecs[] = {
180 {TK_CONFIG_CUSTOM, "-place", NULL, NULL, "", 0,
181 TK_CONFIG_NULL_OK, &geoPlaceOption},
182 {TK_CONFIG_CUSTOM, "-refpoint", NULL, NULL, "0.0 0.0", 0, 0,
183 &refPtOption},
184 {TK_CONFIG_CUSTOM, "-projection", NULL, NULL, "", 0, 0,
185 &projOption},
186 {TK_CONFIG_DOUBLE, "-scale", NULL, NULL, "1.0e-7",
187 Tk_Offset(PlaceItem, scale), 0, NULL},
188 {TK_CONFIG_COLOR, "-dotcolor", NULL, NULL, "Black",
189 Tk_Offset(PlaceItem, dotColor), TK_CONFIG_NULL_OK, NULL},
190 {TK_CONFIG_PIXELS, "-dotsize", NULL, NULL, "1",
191 Tk_Offset(PlaceItem, dotSize), 0, NULL},
192 {TK_CONFIG_BITMAP, "-bitmap", NULL, NULL, "",
193 Tk_Offset(PlaceItem, bitmap), TK_CONFIG_NULL_OK, NULL},
194 {TK_CONFIG_COLOR, "-bitmapcolor", NULL, NULL, "Black",
195 Tk_Offset(PlaceItem, bmColor), TK_CONFIG_NULL_OK, NULL},
196 {TK_CONFIG_STRING, "-text", NULL, NULL, "", Tk_Offset(PlaceItem, text),
197 0, NULL},
198 {TK_CONFIG_COLOR, "-textcolor", NULL, NULL, "Black",
199 Tk_Offset(PlaceItem, textColor), TK_CONFIG_NULL_OK, NULL},
200 {TK_CONFIG_FONT, "-font", NULL, NULL, "fixed",
201 Tk_Offset(PlaceItem, font), TK_CONFIG_NULL_OK, NULL},
202 {TK_CONFIG_ANCHOR, "-anchor", NULL, NULL, "center",
203 Tk_Offset(PlaceItem, textAnchor), 0, NULL},
204 {TK_CONFIG_CUSTOM, "-arrow", NULL, NULL, "0.0 0 0.0", 0, 0,
205 &arrowOption},
206 {TK_CONFIG_COLOR, "-arrowcolor", NULL, NULL, "Black",
207 Tk_Offset(PlaceItem, arrowColor), TK_CONFIG_NULL_OK, NULL},
208 {TK_CONFIG_CUSTOM, "-tags", NULL, NULL, NULL, 0, TK_CONFIG_NULL_OK,
209 &tagsOption},
210 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0, NULL}
211 };
212
213 /*
214 * The structures below defines the geoplace item type in terms of
215 * procedures that can be invoked by generic item code.
216 */
217
218 static Tk_ItemType geoPlaceType = {
219 "geomap_place",
220 sizeof(PlaceItem),
221 createProc,
222 configSpecs,
223 configProc,
224 coordProc,
225 deleteProc,
226 displayProc,
227 TK_CONFIG_OBJS,
228 pointProc,
229 areaProc,
230 postscriptProc,
231 scaleProc,
232 translateProc,
233 (Tk_ItemIndexProc *) NULL,
234 (Tk_ItemCursorProc *) NULL,
235 (Tk_ItemSelectionProc *) NULL,
236 (Tk_ItemInsertProc *) NULL,
237 (Tk_ItemDCharsProc *) NULL,
238 (Tk_ItemType *) NULL,
239 };
240
241 /*
242 *------------------------------------------------------------------------
243 *
244 * TkgeomapPlaceInit --
245 *
246 * This procedure adds the geoplace item type to the canvas widget.
247 * See the user documentation for a description of the its effect
248 * on Tcl.
249 *
250 * Results:
251 * A standard Tcl result.
252 *
253 * Side effects:
254 * Prerequisite packages are initialized, and the "geoplace" item is
255 * added to the Tk canvas interface.
256 *
257 *------------------------------------------------------------------------
258 */
259
260 int
TkgeomapPlaceInit(interp)261 TkgeomapPlaceInit(interp)
262 Tcl_Interp *interp; /* Current interpreter */
263 {
264 static int loaded; /* If true, package is loaded */
265
266 if (loaded) {
267 return TCL_OK;
268 }
269 #ifdef USE_TCL_STUBS
270 if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
271 return TCL_ERROR;
272 }
273 #endif
274 #ifdef USE_TK_STUBS
275 if (Tk_InitStubs(interp, TK_VERSION, 0) == NULL) {
276 return TCL_ERROR;
277 }
278 #endif
279
280 /*
281 * Set tagsOption. This must be done at run time because the stubs
282 * library set the functions to non-static values, so they cannot be
283 * used in an initializer.
284 */
285
286 tagsOption.parseProc = Tk_CanvasTagsParseProc;
287 tagsOption.printProc = Tk_CanvasTagsPrintProc;
288
289 Tk_CreateItemType(&geoPlaceType);
290 loaded = 1;
291 return TCL_OK;
292 }
293
294 /*
295 *--------------------------------------------------------------
296 *
297 * createProc --
298 *
299 * This procedure is invoked to create a new geoplace
300 * item in a canvas.
301 *
302 * Results:
303 * A standard Tcl return value. If an error occurred in
304 * creating the item, then an error message is left in
305 * the interp's result; in this case itemPtr is left uninitialized,
306 * so it can be safely freed by the caller.
307 *
308 * Side effects:
309 * A new geoplace item is created.
310 *
311 *--------------------------------------------------------------
312 */
313
314 static int
createProc(interp,canvas,itemPtr,objc,objv)315 createProc(interp, canvas, itemPtr, objc, objv)
316 Tcl_Interp *interp; /* Interpreter for error reporting. */
317 Tk_Canvas canvas; /* Canvas to hold new item. */
318 Tk_Item *itemPtr; /* Record to hold new item; header
319 * has been initialized by caller. */
320 int objc; /* Number of arguments in objv. */
321 Tcl_Obj *CONST objv[]; /* Arguments describing rectangle. */
322 {
323 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
324 double x, y;
325
326
327 /*
328 * Set location of reference point from coordinates given on command line.
329 */
330
331 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0], &x) != TCL_OK)
332 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1], &y)
333 != TCL_OK)) {
334 return TCL_ERROR;
335 }
336 plcItemPtr->xRef = x;
337 plcItemPtr->yRef = y;
338
339 /*
340 * Initialize values. Bogus initializers will be set properly
341 * when the item is configured.
342 */
343
344 plcItemPtr->interp = interp;
345 plcItemPtr->canvas = canvas;
346 plcItemPtr->refPt = GeoPtFmDeg(0.0, 0.0);
347 plcItemPtr->proj = NULL;
348 plcItemPtr->scale = 0.0;
349 plcItemPtr->tclGeoPlace = NULL;
350 plcItemPtr->mapPt = MapPtNowhere();
351 plcItemPtr->updateMap = 1;
352 plcItemPtr->updateCvs = 1;
353 plcItemPtr->dotColor = None;
354 plcItemPtr->dotSize = 0;
355 plcItemPtr->dotGC = None;
356 plcItemPtr->bitmap = None;
357 plcItemPtr->bmColor = None;
358 plcItemPtr->bmGC = None;
359 plcItemPtr->text = CKALLOC(1);
360 strcpy(plcItemPtr->text, "");
361 plcItemPtr->textColor = None;
362 plcItemPtr->font = NULL;
363 plcItemPtr->textAnchor = TK_ANCHOR_CENTER;
364 plcItemPtr->txtGC = None;
365 plcItemPtr->layout = NULL;
366 plcItemPtr->arrowColor = None;
367 plcItemPtr->arrowGC = None;
368
369 /*
370 * Configure the new geoplace item.
371 */
372
373 if (configProc(interp, canvas, itemPtr, objc - 2, objv + 2, 0)
374 != TCL_OK) {
375 deleteProc(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
376 return TCL_ERROR;
377 }
378
379 return TCL_OK;
380 }
381
382 /*
383 *--------------------------------------------------------------
384 *
385 * configProc --
386 *
387 * This procedure is invoked to configure various aspects
388 * of a geoplace item, such as its anchor position.
389 *
390 * Results:
391 * A standard Tcl result code. If an error occurs, then
392 * an error message is left in the interp's result.
393 *
394 * Side effects:
395 * Configuration information may be set for itemPtr.
396 *
397 *--------------------------------------------------------------
398 */
399
400 static int
configProc(interp,canvas,itemPtr,objc,objv,flags)401 configProc(interp, canvas, itemPtr, objc, objv, flags)
402 Tcl_Interp *interp; /* Used for error reporting. */
403 Tk_Canvas canvas; /* Canvas containing itemPtr. */
404 Tk_Item *itemPtr; /* Geoplace item to reconfigure. */
405 int objc; /* Number of elements in objv. */
406 Tcl_Obj *CONST objv[]; /* Arguments describing things to configure. */
407 int flags; /* Flags to pass to Tk_ConfigureWidget. */
408 {
409 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
410 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
411 double oldScale;
412 Tk_Anchor oldAnchor;
413 XGCValues gcVals;
414 GC gc;
415
416 oldScale = plcItemPtr->scale;
417 oldAnchor = plcItemPtr->textAnchor;
418 if (Tk_ConfigureWidget(interp, Tk_CanvasTkwin(canvas),
419 geoPlaceType.configSpecs, objc, (char **)objv,
420 (char *)plcItemPtr, flags|TK_CONFIG_OBJS) != TCL_OK) {
421 return TCL_ERROR;
422 }
423
424 /*
425 * Update graphics contexts.
426 */
427
428 if (plcItemPtr->dotSize > 0 && plcItemPtr->dotColor != None) {
429 gcVals.foreground = plcItemPtr->dotColor->pixel;
430 gc = Tk_GetGC(tkwin, GCForeground, &gcVals);
431 if (plcItemPtr->dotGC != None) {
432 Tk_FreeGC(Tk_Display(tkwin), plcItemPtr->dotGC);
433 }
434 plcItemPtr->dotGC = gc;
435 }
436 if (plcItemPtr->bitmap != None && plcItemPtr->bmColor != None) {
437 gcVals.foreground = plcItemPtr->bmColor->pixel;
438 gcVals.clip_mask = plcItemPtr->bitmap;
439 gc = Tk_GetGC(tkwin, GCForeground|GCClipMask, &gcVals);
440 if (plcItemPtr->bmGC != None) {
441 Tk_FreeGC(Tk_Display(tkwin), plcItemPtr->bmGC);
442 }
443 plcItemPtr->bmGC = gc;
444 }
445 if ( (plcItemPtr->textColor != None) && plcItemPtr->font) {
446 gcVals.foreground = plcItemPtr->textColor->pixel;
447 gcVals.font = Tk_FontId(plcItemPtr->font);
448 gc = Tk_GetGC(tkwin, GCForeground|GCFont, &gcVals);
449 if (plcItemPtr->txtGC != None) {
450 Tk_FreeGC(Tk_Display(tkwin), plcItemPtr->txtGC);
451 }
452 plcItemPtr->txtGC = gc;
453 }
454 if (plcItemPtr->arrow_len >= 1.0 && plcItemPtr->arrowColor != None) {
455 gcVals.foreground = plcItemPtr->arrowColor->pixel;
456 gc = Tk_GetGC(tkwin, GCForeground, &gcVals);
457 if (plcItemPtr->arrowGC != None) {
458 Tk_FreeGC(Tk_Display(tkwin), plcItemPtr->arrowGC);
459 }
460 plcItemPtr->arrowGC = gc;
461 }
462
463 /*
464 * If text has changed, compute new text layout.
465 */
466
467 if (strlen(plcItemPtr->text) > 0) {
468 computeTextLayout(plcItemPtr);
469 }
470 updateCvs(plcItemPtr);
471 return TCL_OK;
472 }
473
474 /*
475 *--------------------------------------------------------------
476 *
477 * coordProc --
478 *
479 * This procedure is invoked to process the "coords" widget
480 * command on geoplace items. See the user documentation for
481 * details on what it does.
482 *
483 * Results:
484 * Returns TCL_OK or TCL_ERROR, and sets the interp's result.
485 *
486 * Side effects:
487 * The coordinates for the given item may be changed.
488 *
489 *--------------------------------------------------------------
490 */
491
492 static int
coordProc(interp,canvas,itemPtr,objc,objv)493 coordProc(interp, canvas, itemPtr, objc, objv)
494 Tcl_Interp *interp; /* Used for error reporting. */
495 Tk_Canvas canvas; /* Canvas containing item. */
496 Tk_Item *itemPtr; /* Item whose coordinates are to be
497 * read or modified. */
498 int objc; /* Number of coordinates supplied in
499 * objv. */
500 Tcl_Obj *CONST objv[]; /* Array of coordinates: x1, y1,
501 * x2, y2, ... */
502 {
503 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
504 double xRef, yRef;
505
506 if (objc == 0) {
507 /*
508 * Set result to item coordinates
509 */
510
511 Tcl_Obj *obj = Tcl_NewObj();
512 Tcl_Obj *subobj = Tcl_NewDoubleObj(plcItemPtr->xRef);
513 Tcl_ListObjAppendElement(interp, obj, subobj);
514 subobj = Tcl_NewDoubleObj(plcItemPtr->yRef);
515 Tcl_ListObjAppendElement(interp, obj, subobj);
516 Tcl_SetObjResult(interp, obj);
517 } else if (objc == 1) {
518 Tcl_Obj *rslt; /* Result */
519
520 if (strcmp(Tcl_GetString(objv[0]), "dump") == 0) {
521 /*
522 * User wants dump of canvas coordinates for the linearray.
523 */
524
525 updateCvs(plcItemPtr);
526 rslt = Tcl_NewObj();
527 Tcl_ListObjAppendElement(interp, rslt,
528 Tcl_NewDoubleObj(plcItemPtr->xPlc));
529 Tcl_ListObjAppendElement(interp, rslt,
530 Tcl_NewDoubleObj(plcItemPtr->yPlc));
531 Tcl_SetObjResult(interp, rslt);
532 return TCL_OK;
533 } else {
534 /*
535 * New coordinates given on command line in form
536 * "pathName coords {x y}"
537 */
538
539 Tcl_Obj **coordsPtr;
540 int n;
541
542 if (Tcl_ListObjGetElements(interp, objv[0], &n, &coordsPtr)
543 != TCL_OK || n != 2) {
544 Tcl_AppendResult(interp, "Could not split coords list\n", NULL);
545 return TCL_ERROR;
546 }
547 if ((Tk_CanvasGetCoordFromObj(interp, canvas, coordsPtr[0],
548 &xRef) != TCL_OK)
549 || (Tk_CanvasGetCoordFromObj(interp, canvas, coordsPtr[1],
550 &yRef) != TCL_OK)) {
551 return TCL_ERROR;
552 }
553 plcItemPtr->xRef = xRef;
554 plcItemPtr->yRef = yRef;
555 plcItemPtr->updateCvs = 1;
556 updateCvs(plcItemPtr);
557 }
558 } else if (objc == 2) {
559 /*
560 * New coordinates given on command line
561 */
562
563 if ((Tk_CanvasGetCoordFromObj(interp, canvas, objv[0],
564 &xRef) != TCL_OK)
565 || (Tk_CanvasGetCoordFromObj(interp, canvas, objv[1],
566 &yRef) != TCL_OK)) {
567 return TCL_ERROR;
568 }
569 plcItemPtr->xRef = xRef;
570 plcItemPtr->yRef = yRef;
571 plcItemPtr->updateCvs = 1;
572 updateCvs(plcItemPtr);
573 } else {
574 Tcl_AppendResult(interp,
575 "Coordinates must be specified as \"x y\" or \"{x y}\"", NULL);
576 return TCL_ERROR;
577 }
578 return TCL_OK;
579 }
580
581 /*
582 *--------------------------------------------------------------
583 *
584 * deleteProc --
585 *
586 * This procedure is called to clean up the data structure
587 * associated with a geoplace item.
588 *
589 * Results:
590 * None.
591 *
592 * Side effects:
593 * Resources associated with itemPtr are released.
594 *
595 *--------------------------------------------------------------
596 */
597
598 static void
deleteProc(canvas,itemPtr,display)599 deleteProc(canvas, itemPtr, display)
600 Tk_Canvas canvas; /* Info about overall canvas widget. */
601 Tk_Item *itemPtr; /* Item that is being deleted. */
602 Display *display; /* Display containing window for
603 * canvas. */
604 {
605 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
606
607 Tclgeomap_CnxProjUpdateTask(plcItemPtr->proj, plcItemPtr);
608 Tclgeomap_CnxProjDeleteTask(plcItemPtr->proj, plcItemPtr);
609 Tclgeomap_CnxPlaceUpdateTask(plcItemPtr->tclGeoPlace, plcItemPtr);
610 Tclgeomap_CnxPlaceDeleteTask(plcItemPtr->tclGeoPlace, plcItemPtr);
611 if (plcItemPtr->dotGC != None) {
612 Tk_FreeGC(display, plcItemPtr->dotGC);
613 }
614 if (plcItemPtr->bmGC != None) {
615 Tk_FreeGC(display, plcItemPtr->bmGC);
616 }
617 if (plcItemPtr->txtGC != None) {
618 Tk_FreeGC(display, plcItemPtr->txtGC);
619 }
620 if (plcItemPtr->arrowGC != None) {
621 Tk_FreeGC(display, plcItemPtr->arrowGC);
622 }
623 Tk_FreeOptions(geoPlaceType.configSpecs, (char *)plcItemPtr,
624 display, 0);
625 }
626
627 /*
628 *--------------------------------------------------------------
629 *
630 * forgetPlace --
631 *
632 * This procedure adjusts a place item if the place it is displaying
633 * is deleted.
634 *
635 * Results:
636 * None.
637 *
638 * Side effects:
639 * The item is removed from the display, although it continues to exist.
640 *
641 *--------------------------------------------------------------
642 */
643
644 static void
forgetPlace(clientData)645 forgetPlace(clientData)
646 ClientData clientData; /* Geoplace item */
647 {
648 PlaceItem *plcItemPtr = (PlaceItem *)clientData;
649 Tk_Canvas canvas = plcItemPtr->canvas;
650 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
651 Display *display = Tk_Display(tkwin);
652
653 plcItemPtr->tclGeoPlace = NULL;
654 plcItemPtr->mapPt = MapPtNowhere();
655 plcItemPtr->updateMap = 0;
656 if (plcItemPtr->dotGC != None) {
657 Tk_FreeGC(display, plcItemPtr->dotGC);
658 }
659 plcItemPtr->dotGC = None;
660 if (plcItemPtr->bmGC != None) {
661 Tk_FreeGC(display, plcItemPtr->bmGC);
662 }
663 plcItemPtr->bmGC = None;
664 if (plcItemPtr->txtGC != None) {
665 Tk_FreeGC(display, plcItemPtr->txtGC);
666 }
667 plcItemPtr->txtGC = None;
668 if (plcItemPtr->arrowGC != None) {
669 Tk_FreeGC(display, plcItemPtr->arrowGC);
670 }
671 plcItemPtr->arrowGC = None;
672 hide(plcItemPtr);
673 }
674
675 /*
676 *--------------------------------------------------------------
677 *
678 * forgetProj --
679 *
680 * This procedure adjusts a place item if the projection it is using
681 * is deleted.
682 *
683 * Results:
684 * None.
685 *
686 * Side effects:
687 * The item is removed from the display, although it continues to exist.
688 *
689 *--------------------------------------------------------------
690 */
691
692 static void
forgetProj(clientData)693 forgetProj(clientData)
694 ClientData clientData; /* Geoplace item */
695 {
696 PlaceItem *plcItemPtr = (PlaceItem *)clientData;
697
698 plcItemPtr->proj = NULL;
699 plcItemPtr->mapPt = MapPtNowhere();
700 plcItemPtr->updateMap = 0;
701 hide(plcItemPtr);
702 }
703
704 /*
705 *--------------------------------------------------------------
706 *
707 * hide --
708 *
709 * This procedure removes a geoplace from a display, although the geoplace
710 * item continues to exist.
711 *
712 * Results:
713 * None.
714 *
715 * Side effects:
716 * None.
717 *
718 *--------------------------------------------------------------
719 */
720
721 static void
hide(plcItemPtr)722 hide(plcItemPtr)
723 PlaceItem *plcItemPtr; /* Place to remove from the display */
724 {
725 Tk_CanvasEventuallyRedraw(plcItemPtr->canvas,
726 plcItemPtr->header.x1, plcItemPtr->header.y1,
727 plcItemPtr->header.x2, plcItemPtr->header.y2);
728 plcItemPtr->header.x1 = plcItemPtr->header.y1 = INT_MIN;
729 plcItemPtr->header.x2 = plcItemPtr->header.y2 = INT_MIN + 1;
730 plcItemPtr->updateCvs = 0;
731 }
732
733 /*
734 *--------------------------------------------------------------
735 *
736 * displayProc --
737 *
738 * This procedure is invoked to draw a geoplace item in a given
739 * drawable.
740 *
741 * Results:
742 * None.
743 *
744 * Side effects:
745 * ItemPtr is drawn in drawable using the transformation
746 * information in canvas.
747 *
748 *--------------------------------------------------------------
749 */
750
751 static void
displayProc(canvas,itemPtr,display,drawable,x,y,width,height)752 displayProc(canvas, itemPtr, display, drawable, x, y, width, height)
753 Tk_Canvas canvas; /* Canvas that contains item. */
754 Tk_Item *itemPtr; /* Item to be displayed. */
755 Display *display; /* Display on which to draw item. */
756 Drawable drawable; /* Pixmap or window in which to draw
757 * item. */
758 int x, y, width, height; /* Describes region of canvas that
759 * must be redisplayed (not used). */
760 {
761 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
762 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
763 int dotSize;
764 short dwX, dwY; /* Drawable (X) coordinates */
765 int spShift; /* Amount to shift to center large
766 * dot or bitmap */
767
768 if (!tkwin || !Tk_IsMapped(tkwin) || !plcItemPtr->tclGeoPlace) {
769 return;
770 }
771 if (plcItemPtr->updateMap) {
772 updateMap(plcItemPtr);
773 }
774 if (MapPtIsNowhere(plcItemPtr->mapPt)) {
775 return;
776 }
777 if (plcItemPtr->updateCvs) {
778 updateCvs(plcItemPtr);
779 }
780 Tk_CanvasDrawableCoords(canvas, plcItemPtr->xPlc, plcItemPtr->yPlc,
781 &dwX, &dwY);
782
783 /*
784 * Draw dot.
785 */
786
787 if (plcItemPtr->dotSize > 0 && plcItemPtr->dotColor != None) {
788 dotSize = plcItemPtr->dotSize;
789 if (dotSize == 1) {
790 XDrawPoint(display, drawable, plcItemPtr->dotGC, dwX, dwY);
791 } else {
792 spShift = dotSize / 2;
793 XFillArc(display, drawable, plcItemPtr->dotGC,
794 dwX - spShift, dwY - spShift,
795 (unsigned)dotSize, (unsigned)dotSize, 0, 23040);
796 }
797 }
798
799 /*
800 * Draw bitmap.
801 */
802
803 if (plcItemPtr->bitmap != None && plcItemPtr->bmColor != None) {
804 Pixmap bitmap = plcItemPtr->bitmap;
805 int bmWidth, bmHeight;
806
807 Tk_SizeOfBitmap(display, bitmap, &bmWidth, &bmHeight);
808 XSetClipOrigin(display, plcItemPtr->bmGC,
809 dwX - bmWidth / 2, dwY - bmHeight / 2);
810 XCopyPlane(display, bitmap, drawable, plcItemPtr->bmGC, 0, 0,
811 (unsigned)bmWidth, (unsigned)bmHeight,
812 dwX -bmWidth / 2, dwY -bmHeight / 2, 0x01);
813 XSetClipOrigin(display, plcItemPtr->bmGC, 0, 0);
814 }
815
816 /*
817 * Draw text.
818 */
819
820 if ( (strlen(plcItemPtr->text) > 0)
821 && (plcItemPtr->textColor != None)
822 && plcItemPtr->font
823 && plcItemPtr->layout ) {
824 Tk_DrawTextLayout(display, drawable, plcItemPtr->txtGC,
825 plcItemPtr->layout,
826 dwX + plcItemPtr->xTxt, dwY + plcItemPtr->yTxt, 0, -1);
827 }
828
829 /*
830 * Draw arrow.
831 */
832
833 if (plcItemPtr->arrow_len >= 1.0 && plcItemPtr->arrowColor != None) {
834 XPoint xPtsPtr[2];
835
836 /*
837 * Coordinates of the arrow head
838 */
839
840 xPtsPtr[0].x = dwX + plcItemPtr->arrow_head_x;
841 xPtsPtr[0].y = dwY + plcItemPtr->arrow_head_y;
842
843 /*
844 * Draw the shaft
845 */
846
847 xPtsPtr[1].x = dwX + plcItemPtr->arrow_base_x;
848 xPtsPtr[1].y = dwY + plcItemPtr->arrow_base_y;
849 XDrawLines(display, drawable, plcItemPtr->arrowGC, xPtsPtr, 2,
850 CoordModeOrigin);
851
852 /*
853 * Draw the left side of the arrow head
854 */
855
856 xPtsPtr[1].x = xPtsPtr[0].x + plcItemPtr->arrow_ltip_x;
857 xPtsPtr[1].y = xPtsPtr[0].y + plcItemPtr->arrow_ltip_y;
858 XDrawLines(display, drawable, plcItemPtr->arrowGC, xPtsPtr, 2,
859 CoordModeOrigin);
860
861 /*
862 * Draw the right side of the arrow head
863 */
864
865 xPtsPtr[1].x = xPtsPtr[0].x + plcItemPtr->arrow_rtip_x;
866 xPtsPtr[1].y = xPtsPtr[0].y + plcItemPtr->arrow_rtip_y;
867 XDrawLines(display, drawable, plcItemPtr->arrowGC, xPtsPtr, 2,
868 CoordModeOrigin);
869 }
870 }
871
872 /*
873 *--------------------------------------------------------------
874 *
875 * pointProc --
876 *
877 * Computes the distance from a given point to a given
878 * geoplace item, in canvas units.
879 *
880 * Results:
881 * The return value is 0.0 if the point whose x and y coordinates
882 * are coordPtr[0] and coordPtr[1] is inside the geoplace item. If the
883 * point isn't inside the geoplace item then the return value is the
884 * distance from the point to the geoplace.
885 *
886 * Side effects:
887 * None.
888 *
889 *--------------------------------------------------------------
890 */
891
892 static double
pointProc(canvas,itemPtr,pointPtr)893 pointProc(canvas, itemPtr, pointPtr)
894 Tk_Canvas canvas; /* Canvas containing item. */
895 Tk_Item *itemPtr; /* Item to check against point. */
896 double *pointPtr; /* Pointer to x and y coordinates. */
897 {
898 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
899 double x = pointPtr[0], y = pointPtr[1];
900
901 if (plcItemPtr->updateCvs) {
902 updateCvs(plcItemPtr);
903 }
904 return hypot(plcItemPtr->xPlc - x, plcItemPtr->yPlc - y);
905 }
906
907 /*
908 *--------------------------------------------------------------
909 *
910 * areaProc --
911 *
912 * This procedure is called to determine whether an item
913 * lies entirely inside, entirely outside, or overlapping
914 * a given rectangle.
915 *
916 * Results:
917 * -1 is returned if the item is entirely outside the area
918 * given by rectPtr, 0 if it overlaps, and 1 if it is entirely
919 * inside the given area.
920 *
921 * Side effects:
922 * None.
923 *
924 *--------------------------------------------------------------
925 */
926
927 static int
areaProc(canvas,itemPtr,rectPtr)928 areaProc(canvas, itemPtr, rectPtr)
929 Tk_Canvas canvas; /* Canvas containing item. */
930 Tk_Item *itemPtr; /* Item to check against rectangle. */
931 double *rectPtr; /* Pointer to array of four coordinates
932 * (x1, y1, x2, y2) describing rectangular
933 * area. */
934 {
935 PlaceItem *plcItemPtr = (PlaceItem *)itemPtr;
936 double x1i, y1i, x2i, y2i; /* Limits of item */
937 double x1r, y1r, x2r, y2r; /* Limits of rectPtr rectangle */
938
939 if (plcItemPtr->updateCvs) {
940 updateCvs(plcItemPtr);
941 }
942 x1i = itemPtr->x1;
943 y1i = itemPtr->y1;
944 x2i = itemPtr->x2;
945 y2i = itemPtr->y2;
946 x1r = rectPtr[0];
947 y1r = rectPtr[1];
948 x2r = rectPtr[2];
949 y2r = rectPtr[3];
950 if (x1i > x2r || x2i < x1r || y1i > y2r || y2i < y1r) {
951 return -1;
952 } else if (x1i > x1r && x2i < x2r && y1i > y1r && y2i < y2r) {
953 return 1;
954 } else {
955 return 0;
956 }
957 }
958
959 /*
960 *--------------------------------------------------------------
961 *
962 * postscriptProc --
963 *
964 * This procedure is called to generate Postscript for
965 * geoplace items.
966 *
967 * Results:
968 * The return value is a standard Tcl result. If an error
969 * occurs in generating Postscript then an error message is
970 * left in interp->result, replacing whatever used to be there.
971 * If no error occurs, then Postscript for the item is appended
972 * to the result.
973 *
974 * Side effects:
975 * None.
976 *
977 *--------------------------------------------------------------
978 */
979
980 static int
postscriptProc(interp,canvas,itemPtr,prepass)981 postscriptProc(interp, canvas, itemPtr, prepass)
982 Tcl_Interp *interp; /* Leave Postscript or error message
983 * here. */
984 Tk_Canvas canvas; /* Information about overall canvas. */
985 Tk_Item *itemPtr; /* Item for which Postscript is
986 * wanted. */
987 int prepass; /* 1 means this is a prepass to
988 * collect font information; 0 means
989 * final Postscript is being created. */
990 {
991 PlaceItem *plcItemPtr; /* Current geoplace item */
992 Tk_Window tkwin = Tk_CanvasTkwin(canvas);
993 char bytes[200]; /* Printing space */
994 double psX, psY; /* Postscript coordinates */
995 double cnr[8]; /* 4 corner points in canvas coord's */
996
997 plcItemPtr = (PlaceItem *)itemPtr;
998 if ( !plcItemPtr->tclGeoPlace ) {
999 return TCL_OK;
1000 } else {
1001 Tcl_AppendResult(interp, "% Drawing place ",
1002 Tclgeomap_PlaceName(plcItemPtr->tclGeoPlace), "\n", NULL);
1003 }
1004 if (plcItemPtr->updateMap) {
1005 updateMap(plcItemPtr);
1006 }
1007 if (MapPtIsNowhere(plcItemPtr->mapPt)) {
1008 return TCL_OK;
1009 }
1010 if (plcItemPtr->updateCvs) {
1011 updateCvs(plcItemPtr);
1012 }
1013 psX = plcItemPtr->xPlc;
1014 psY = Tk_CanvasPsY(canvas, plcItemPtr->yPlc);
1015
1016 /*
1017 * Create clipping region for item
1018 */
1019
1020 Tcl_AppendResult(interp, "%% Create clipping region for item\n", NULL);
1021 cnr[0] = 0;
1022 cnr[1] = 0;
1023 cnr[2] = Tk_Width(tkwin);
1024 cnr[3] = 0;
1025 cnr[4] = Tk_Width(tkwin);
1026 cnr[5] = Tk_Height(tkwin);
1027 cnr[6] = 0;
1028 cnr[7] = Tk_Height(tkwin);
1029 Tk_CanvasPsPath(interp, canvas, cnr, 4);
1030 Tcl_AppendResult(interp, "closepath clip\n", NULL);
1031
1032 /*
1033 * Draw dot.
1034 */
1035
1036 if (plcItemPtr->dotSize > 0 && plcItemPtr->dotColor != None) {
1037 Tk_CanvasPsColor(interp, canvas, plcItemPtr->dotColor);
1038 sprintf(bytes, "newpath %f %f %f", psX, psY, 0.5 * plcItemPtr->dotSize);
1039 Tcl_AppendResult(interp, bytes, " 0 360 arc fill\n", NULL);
1040 }
1041
1042 /*
1043 * Draw bitmap.
1044 */
1045
1046 if (plcItemPtr->bitmap != None && plcItemPtr->bmColor != None) {
1047 int bmWidth, bmHeight;
1048
1049 Tcl_AppendResult(interp, "gsave\n", NULL);
1050 Tk_CanvasPsColor(interp, canvas, plcItemPtr->bmColor);
1051 Tk_SizeOfBitmap(Tk_Display(Tk_CanvasTkwin(canvas)),
1052 plcItemPtr->bitmap, &bmWidth, &bmHeight);
1053 sprintf(bytes, "%f %f translate\n",
1054 psX - 0.5 * bmWidth, psY - 0.5 * bmHeight);
1055 Tcl_AppendResult(interp, bytes, NULL);
1056 sprintf(bytes, "%d %d scale\n", bmWidth, bmHeight);
1057 Tcl_AppendResult(interp, bytes, NULL);
1058 sprintf(bytes, "%d %d true [%d 0 0 %d 0 0]\n",
1059 bmWidth, bmHeight, bmWidth, bmHeight);
1060 Tcl_AppendResult(interp, bytes, NULL);
1061 Tk_CanvasPsBitmap(interp, canvas, plcItemPtr->bitmap,
1062 0, 0, bmWidth, bmHeight);
1063 Tcl_AppendResult(interp, " imagemask\ngrestore\n\n", NULL);
1064 }
1065
1066 /*
1067 * Draw text.
1068 */
1069
1070 if (plcItemPtr->text && strcmp(plcItemPtr->text, "") != 0
1071 && (plcItemPtr->textColor != None) && plcItemPtr->font
1072 && plcItemPtr->layout) {
1073 int xOffset = 0, yOffset = 0;
1074 Tk_FontMetrics fm;
1075 double justify = 0.0;
1076
1077 Tcl_AppendResult(interp, "gsave\n", NULL);
1078 if (Tk_CanvasPsColor(interp, canvas, plcItemPtr->textColor) != TCL_OK
1079 || Tk_CanvasPsFont(interp, canvas, plcItemPtr->font)
1080 != TCL_OK) {
1081 return TCL_ERROR;
1082 }
1083 switch (plcItemPtr->textAnchor) {
1084 case TK_ANCHOR_NW : xOffset = 0;
1085 yOffset = 0;
1086 justify = 0.0;
1087 break;
1088 case TK_ANCHOR_N : xOffset = 1;
1089 yOffset = 0;
1090 justify = 0.5;
1091 break;
1092 case TK_ANCHOR_NE : xOffset = 2;
1093 yOffset = 0;
1094 justify = 1.0;
1095 break;
1096 case TK_ANCHOR_E : xOffset = 2;
1097 yOffset = 1;
1098 justify = 1.0;
1099 break;
1100 case TK_ANCHOR_SE : xOffset = 2;
1101 yOffset = 2;
1102 justify = 1.0;
1103 break;
1104 case TK_ANCHOR_S : xOffset = 1;
1105 yOffset = 2;
1106 justify = 0.5;
1107 break;
1108 case TK_ANCHOR_SW : xOffset = 0;
1109 yOffset = 2;
1110 justify = 0.0;
1111 break;
1112 case TK_ANCHOR_W : xOffset = 0;
1113 yOffset = 1;
1114 justify = 0.0;
1115 break;
1116 case TK_ANCHOR_CENTER: xOffset = 1;
1117 yOffset = 1;
1118 justify = 0.5;
1119 break;
1120 }
1121 sprintf(bytes, "%.15g %.15g [\n", psX, psY);
1122 Tcl_AppendResult(interp, bytes, NULL);
1123 Tk_TextLayoutToPostscript(interp, plcItemPtr->layout);
1124 Tk_GetFontMetrics(plcItemPtr->font, &fm);
1125 sprintf(bytes, "] %d %g %g %g false DrawText\ngrestore\n",
1126 fm.linespace, xOffset / -2.0, yOffset / 2.0, justify);
1127 Tcl_AppendResult(interp, bytes, NULL);
1128 }
1129
1130 return TCL_OK;
1131 }
1132
1133 /*
1134 *--------------------------------------------------------------
1135 *
1136 * scaleProc --
1137 *
1138 * This function rescales a geoplace item. It should not be confused
1139 * with the "-scale" configuration option, which sets the cartographic
1140 * scale of the map containing the item.
1141 *
1142 * Results:
1143 * None.
1144 *
1145 * Side effects:
1146 * The reference point for a geoplace item is moved according to the
1147 * transformation:
1148 * xRef' = originX + scaleX*(xRef-originX)
1149 * yRef' = originY + scaleY*(yRef-originY)
1150 * The geoplace may or may not move.
1151 *
1152 *--------------------------------------------------------------
1153 */
1154
1155 static void
scaleProc(canvas,itemPtr,originX,originY,scaleX,scaleY)1156 scaleProc(canvas, itemPtr, originX, originY, scaleX, scaleY)
1157 Tk_Canvas canvas; /* Canvas containing rectangle. */
1158 Tk_Item *itemPtr; /* Rectangle to be scaled. */
1159 double originX, originY; /* Origin about which to scale rect. */
1160 double scaleX; /* Amount to scale in X direction. */
1161 double scaleY; /* Amount to scale in Y direction. */
1162 {
1163 PlaceItem *plcItemPtr = (PlaceItem *) itemPtr;
1164
1165 plcItemPtr->xRef = originX + scaleX * (plcItemPtr->xRef - originX);
1166 plcItemPtr->yRef = originY + scaleY * (plcItemPtr->yRef - originY);
1167 updateCvs(plcItemPtr);
1168 return;
1169 }
1170
1171 /*
1172 *--------------------------------------------------------------
1173 *
1174 * translateProc --
1175 *
1176 * This procedure is called to move an item by a given amount.
1177 *
1178 * Results:
1179 * None.
1180 *
1181 * Side effects:
1182 * The position of the item is offset by (xDelta, yDelta), and
1183 * the bounding box is updated in the generic part of the item
1184 * structure.
1185 *
1186 *--------------------------------------------------------------
1187 */
1188
1189 static void
translateProc(canvas,itemPtr,deltaX,deltaY)1190 translateProc(canvas, itemPtr, deltaX, deltaY)
1191 Tk_Canvas canvas; /* Canvas containing item. */
1192 Tk_Item *itemPtr; /* Item that is being moved. */
1193 double deltaX, deltaY; /* Amount by which item is to be
1194 * moved. */
1195 {
1196 PlaceItem *plcItemPtr = (PlaceItem *) itemPtr;
1197
1198 plcItemPtr->xRef += deltaX;
1199 plcItemPtr->yRef += deltaY;
1200 updateCvs(plcItemPtr);
1201 }
1202
1203 /*
1204 *------------------------------------------------------------------------
1205 *
1206 * parseGeoPlaceOption --
1207 *
1208 * This procedure is invoked during option processing to handle
1209 * the "-geoplace" option.
1210 *
1211 * Results:
1212 * A standard Tcl result.
1213 *
1214 * Side effects:
1215 * The state for a given item gets replaced by the state
1216 * indicated in the value argument.
1217 *
1218 *------------------------------------------------------------------------
1219 */
1220
1221 static int
parseGeoPlaceOption(clientData,interp,tkwin,value,widgRec,offset)1222 parseGeoPlaceOption(clientData, interp, tkwin, value, widgRec, offset)
1223 ClientData clientData; /* Not used */
1224 Tcl_Interp *interp; /* Current interpreter */
1225 Tk_Window tkwin; /* Window containing the geomap item */
1226 char *value; /* Value of the option */
1227 char *widgRec; /* Pointer to item record */
1228 int offset; /* Offset into widgRec */
1229 {
1230 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1231 char *plcNm = value;
1232 Tclgeomap_Place tclGeoPlace;
1233
1234 if ( strlen(value) > 0 ) {
1235 /*
1236 * User has requested that a geoplace be displayed in the item.
1237 */
1238
1239 tclGeoPlace = Tclgeomap_GetPlace(interp, plcNm);
1240 if ( !tclGeoPlace ) {
1241 Tcl_AppendResult(interp, "No geoplace named ", value, NULL);
1242 return TCL_ERROR;
1243 }
1244 if ( tclGeoPlace == plcItemPtr->tclGeoPlace ) {
1245 return TCL_OK;
1246 }
1247 Tclgeomap_CnxPlaceDeleteTask(plcItemPtr->tclGeoPlace, plcItemPtr);
1248 plcItemPtr->mapPt = MapPtNowhere();
1249 plcItemPtr->updateMap = 1;
1250 Tclgeomap_AddPlaceUpdateTask(tclGeoPlace, geoPlaceUpdate, plcItemPtr);
1251 Tclgeomap_AddPlaceDeleteTask(tclGeoPlace, forgetPlace, plcItemPtr);
1252 plcItemPtr->tclGeoPlace = tclGeoPlace;
1253 } else {
1254 /*
1255 * User has requested that NO geoplace be displayed in the item.
1256 */
1257
1258 if ( plcItemPtr->tclGeoPlace ) {
1259 Tclgeomap_CnxPlaceUpdateTask(plcItemPtr->tclGeoPlace, plcItemPtr);
1260 Tclgeomap_CnxPlaceDeleteTask(plcItemPtr->tclGeoPlace, plcItemPtr);
1261 plcItemPtr->mapPt = MapPtNowhere();
1262 plcItemPtr->updateMap = 0;
1263 }
1264 plcItemPtr->tclGeoPlace = NULL;
1265 }
1266 return TCL_OK;
1267 }
1268
1269 /*
1270 *------------------------------------------------------------------------
1271 *
1272 * printGeoPlaceOption --
1273 *
1274 * This procedure is invoked by the Tk configuration code
1275 * to produce a printable string for the "-refpoint" configuration
1276 * option.
1277 *
1278 * Results:
1279 * The return value is a string describing the state for
1280 * the item referred to by "widgRec". In addition, *freeProcPtr
1281 * is filled in with the address of a procedure to call to free
1282 * the result string when it's no longer needed.
1283 *
1284 * Side effects:
1285 * None.
1286 *
1287 *------------------------------------------------------------------------
1288 */
1289
1290 static char *
printGeoPlaceOption(clientData,tkwin,widgRec,offset,freeProc)1291 printGeoPlaceOption(clientData, tkwin, widgRec, offset, freeProc)
1292 ClientData clientData; /* Not used */
1293 Tk_Window tkwin; /* Window containing the geomap item */
1294 char *widgRec; /* Pointer to item record */
1295 int offset; /* Offset into widgRec */
1296 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
1297 * information about how to reclaim
1298 * storage for return string. */
1299 {
1300 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1301 CONST char *plcNm;
1302 char *rtn;
1303
1304 plcNm = plcItemPtr->tclGeoPlace
1305 ? Tclgeomap_PlaceName(plcItemPtr->tclGeoPlace)
1306 : "";
1307 rtn = Tcl_Alloc(strlen(plcNm) + 1);
1308 strcpy(rtn, plcNm);
1309 *freeProc = Tcl_Free;
1310 return rtn;
1311 }
1312
1313 /*
1314 *------------------------------------------------------------------------
1315 *
1316 * geoplaceUpdate --
1317 *
1318 * This function redraws a place. It should be called when a place moves.
1319 *
1320 * Results:
1321 * None.
1322 *
1323 * Side effects:
1324 * Part of a canvas may be redrawn.
1325 *
1326 *------------------------------------------------------------------------
1327 */
1328
1329 static void
geoPlaceUpdate(clientData)1330 geoPlaceUpdate(clientData)
1331 ClientData clientData; /* Item displaying the place */
1332 {
1333 PlaceItem *plcItemPtr = (PlaceItem *)clientData;
1334 updateMap(plcItemPtr);
1335 updateCvs(plcItemPtr);
1336 }
1337
1338 /*
1339 *------------------------------------------------------------------------
1340 *
1341 * parseRefPtOption --
1342 *
1343 * This procedure is invoked during option processing to handle
1344 * the "-refpoint" option.
1345 *
1346 * Results:
1347 * A standard Tcl result.
1348 *
1349 * Side effects:
1350 * The state for a given item gets replaced by the state
1351 * indicated in the value argument.
1352 *
1353 *------------------------------------------------------------------------
1354 */
1355
1356 static int
parseRefPtOption(clientData,interp,tkwin,value,widgRec,offset)1357 parseRefPtOption(clientData, interp, tkwin, value, widgRec, offset)
1358 ClientData clientData; /* Not used */
1359 Tcl_Interp *interp; /* Current interpreter */
1360 Tk_Window tkwin; /* Window containing the geomap item */
1361 char *value; /* Value of the option */
1362 char *widgRec; /* Pointer to item record */
1363 int offset; /* Offset into widgRec */
1364 {
1365
1366 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1367 double lat, lon;
1368
1369 if (sscanf(value, "%lf %lf", &lat, &lon) == 2) {
1370 plcItemPtr->refPt = GwchLonPt(GeoPtFmDeg(lat, lon));
1371 plcItemPtr->updateMap = plcItemPtr->updateCvs = 1;
1372 return TCL_OK;
1373 } else {
1374 Tcl_AppendResult(interp, "Expected {lat lon}, got ", value, NULL);
1375 return TCL_ERROR;
1376 }
1377 }
1378
1379 /*
1380 *------------------------------------------------------------------------
1381 *
1382 * printRefPtOption --
1383 *
1384 * This procedure is invoked by the Tk configuration code
1385 * to produce a printable string for the "-refpoint" configuration
1386 * option.
1387 *
1388 * Results:
1389 * The return value is a string describing the state for
1390 * the item referred to by "widgRec". In addition, *freeProcPtr
1391 * is filled in with the address of a procedure to call to free
1392 * the result string when it's no longer needed.
1393 *
1394 * Side effects:
1395 * None.
1396 *
1397 *------------------------------------------------------------------------
1398 */
1399
1400 static char *
printRefPtOption(clientData,tkwin,widgRec,offset,freeProc)1401 printRefPtOption(clientData, tkwin, widgRec, offset, freeProc)
1402 ClientData clientData; /* Not used */
1403 Tk_Window tkwin; /* Window containing the geomap item */
1404 char *widgRec; /* Pointer to item record */
1405 int offset; /* Offset into widgRec */
1406 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
1407 * information about how to reclaim
1408 * storage for return string. */
1409 {
1410 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1411 char lat[TCL_DOUBLE_SPACE], lon[TCL_DOUBLE_SPACE];
1412 char *coordPtr[2];
1413 double dLat, dLon;
1414
1415 coordPtr[0] = lat;
1416 coordPtr[1] = lon;
1417 *freeProc = Tcl_Free;
1418 GeoPtGetDeg(plcItemPtr->refPt, &dLat, &dLon);
1419 Tcl_PrintDouble(NULL, dLat, lat);
1420 Tcl_PrintDouble(NULL, dLon, lon);
1421 return Tcl_Merge(2, coordPtr);
1422 }
1423
1424 /*
1425 *------------------------------------------------------------------------
1426 *
1427 * parseProjOption --
1428 *
1429 * This procedure is invoked during option processing to handle
1430 * the "-projection" option.
1431 *
1432 * Results:
1433 * A standard Tcl result.
1434 *
1435 * Side effects:
1436 * The state for a given item gets replaced by the state
1437 * indicated in the value argument.
1438 *
1439 *------------------------------------------------------------------------
1440 */
1441
1442 static int
parseProjOption(clientData,interp,tkwin,value,widgRec,offset)1443 parseProjOption(clientData, interp, tkwin, value, widgRec, offset)
1444 ClientData clientData; /* Not used */
1445 Tcl_Interp *interp; /* Current interpreter */
1446 Tk_Window tkwin; /* Window containing the geomap item */
1447 char *value; /* Value of the option */
1448 char *widgRec; /* Pointer to item record */
1449 int offset; /* Offset into widgRec */
1450 {
1451 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1452 Tclgeomap_Proj proj;
1453
1454 if ( !value || (strcmp(value, "") == 0) ) {
1455 if (plcItemPtr->proj) {
1456 Tclgeomap_CnxProjUpdateTask(plcItemPtr->proj, plcItemPtr);
1457 Tclgeomap_CnxProjDeleteTask(plcItemPtr->proj, plcItemPtr);
1458 }
1459 plcItemPtr->proj = NULL;
1460 return TCL_OK;
1461 }
1462 if ( !(proj = Tclgeomap_GetProj(interp, value)) ) {
1463 Tcl_AppendResult(interp, "No projection named ", value, NULL);
1464 return TCL_ERROR;
1465 }
1466 if (plcItemPtr->proj) {
1467 Tclgeomap_CnxProjUpdateTask(plcItemPtr->proj, plcItemPtr);
1468 Tclgeomap_CnxProjDeleteTask(plcItemPtr->proj, plcItemPtr);
1469 }
1470 plcItemPtr->proj = proj;
1471 Tclgeomap_AddProjUpdateTask(plcItemPtr->proj, geoPlaceUpdate, plcItemPtr);
1472 Tclgeomap_AddProjDeleteTask(plcItemPtr->proj, forgetProj, plcItemPtr);
1473 plcItemPtr->updateMap = 1;
1474 return TCL_OK;
1475 }
1476
1477 /*
1478 *------------------------------------------------------------------------
1479 *
1480 * printProjOption --
1481 *
1482 * This procedure is invoked by the Tk configuration code
1483 * to produce a printable string for the "-projection" configuration
1484 * option.
1485 *
1486 * Results:
1487 * The return value is a string describing the state for
1488 * the item referred to by "widgRec". In addition, *freeProcPtr
1489 * is filled in with the address of a procedure to call to free
1490 * the result string when it's no longer needed.
1491 *
1492 * Side effects:
1493 * None.
1494 *
1495 *------------------------------------------------------------------------
1496 */
1497
1498 static char *
printProjOption(clientData,tkwin,widgRec,offset,freeProc)1499 printProjOption(clientData, tkwin, widgRec, offset, freeProc)
1500 ClientData clientData; /* Not used */
1501 Tk_Window tkwin; /* Window containing the geomap item */
1502 char *widgRec; /* Pointer to item record */
1503 int offset; /* Offset into widgRec */
1504 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
1505 * information about how to reclaim
1506 * storage for return string. */
1507 {
1508 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1509 CONST char *projNm;
1510 char *rtn;
1511
1512 projNm = plcItemPtr->proj ? Tclgeomap_ProjName(plcItemPtr->proj) : "";
1513 rtn = Tcl_Alloc(strlen(projNm) + 1);
1514 strcpy(rtn, projNm);
1515 *freeProc = Tcl_Free;
1516 return rtn;
1517 }
1518
1519 /*
1520 *--------------------------------------------------------------
1521 *
1522 * computeTextLayout --
1523 *
1524 * This procedure computes the text layout for a geoplace item.
1525 *
1526 * Results:
1527 * The text related fields in a geoplace item pointer are updated.
1528 * Side effects:
1529 * None.
1530 *
1531 *--------------------------------------------------------------
1532 */
1533
1534 static void
computeTextLayout(plcItemPtr)1535 computeTextLayout(plcItemPtr)
1536 PlaceItem *plcItemPtr; /* Geoplace item */
1537 {
1538 int txtWidth, txtHeight;
1539 Tk_TextLayout layout = NULL;
1540
1541 if ( !plcItemPtr ) {
1542 return;
1543 }
1544 if (plcItemPtr->layout) {
1545 Tk_FreeTextLayout(plcItemPtr->layout);
1546 }
1547 if ( !plcItemPtr->text || !plcItemPtr->font ) {
1548 plcItemPtr->layout = NULL;
1549 return;
1550 }
1551 switch (plcItemPtr->textAnchor) {
1552 case TK_ANCHOR_N:
1553 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1554 -1, -1, TK_JUSTIFY_CENTER, 0, &txtWidth, &txtHeight);
1555 plcItemPtr->xTxt = -txtWidth / 2;
1556 plcItemPtr->yTxt = 0;
1557 break;
1558 case TK_ANCHOR_NE:
1559 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1560 -1, -1, TK_JUSTIFY_RIGHT, 0, &txtWidth, &txtHeight);
1561 plcItemPtr->xTxt = -txtWidth;
1562 plcItemPtr->yTxt = 0;
1563 break;
1564 case TK_ANCHOR_E:
1565 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1566 -1, -1, TK_JUSTIFY_RIGHT, 0, &txtWidth, &txtHeight);
1567 plcItemPtr->xTxt = -txtWidth;
1568 plcItemPtr->yTxt = -txtHeight / 2;
1569 break;
1570 case TK_ANCHOR_SE:
1571 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1572 -1, -1, TK_JUSTIFY_RIGHT, 0, &txtWidth, &txtHeight);
1573 plcItemPtr->xTxt = -txtWidth;
1574 plcItemPtr->yTxt = -txtHeight;
1575 break;
1576 case TK_ANCHOR_S:
1577 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1578 -1, -1, TK_JUSTIFY_CENTER, 0, &txtWidth, &txtHeight);
1579 plcItemPtr->xTxt = -txtWidth / 2;
1580 plcItemPtr->yTxt = -txtHeight;
1581 break;
1582 case TK_ANCHOR_SW:
1583 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1584 -1, -1, TK_JUSTIFY_LEFT, 0, &txtWidth, &txtHeight);
1585 plcItemPtr->xTxt = 0;
1586 plcItemPtr->yTxt = -txtHeight;
1587 break;
1588 case TK_ANCHOR_W:
1589 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1590 -1, -1, TK_JUSTIFY_LEFT, 0, &txtWidth, &txtHeight);
1591 plcItemPtr->xTxt = 0;
1592 plcItemPtr->yTxt = -txtHeight / 2;
1593 break;
1594 case TK_ANCHOR_NW:
1595 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1596 -1, -1, TK_JUSTIFY_LEFT, 0, &txtWidth, &txtHeight);
1597 plcItemPtr->xTxt = 0;
1598 plcItemPtr->yTxt = 0;
1599 break;
1600 case TK_ANCHOR_CENTER:
1601 layout = Tk_ComputeTextLayout(plcItemPtr->font, plcItemPtr->text,
1602 -1, -1, TK_JUSTIFY_CENTER, 0, &txtWidth, &txtHeight);
1603 plcItemPtr->xTxt = -txtWidth / 2;
1604 plcItemPtr->yTxt = -txtHeight / 2;
1605 break;
1606 }
1607 plcItemPtr->layout = layout;
1608 plcItemPtr->txtWidth = txtWidth;
1609 plcItemPtr->txtHeight = txtHeight;
1610 }
1611
1612 /*
1613 *------------------------------------------------------------------------
1614 *
1615 * parseArrowOption --
1616 *
1617 * This procedure is invoked during option processing to handle
1618 * the "-arrow" option.
1619 *
1620 * Results:
1621 * A standard Tcl result.
1622 *
1623 * Side effects:
1624 * The state for a given item gets replaced by the state
1625 * indicated in the value argument.
1626 *
1627 *------------------------------------------------------------------------
1628 */
1629
1630 static int
parseArrowOption(clientData,interp,tkwin,value,widgRec,offset)1631 parseArrowOption(clientData, interp, tkwin, value, widgRec, offset)
1632 ClientData clientData; /* Not used */
1633 Tcl_Interp *interp; /* Current interpreter */
1634 Tk_Window tkwin; /* Window containing the geomap item */
1635 char *value; /* Value of the option */
1636 char *widgRec; /* Pointer to item record */
1637 int offset; /* Offset into widgRec */
1638 {
1639 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1640 double az, len, tip_sz;
1641
1642 if (sscanf(value, "%lf %lf %lf", &az, &len, &tip_sz) == 3) {
1643 plcItemPtr->arrow_az = AngleFmDeg(az);
1644 plcItemPtr->arrow_len = len;
1645 plcItemPtr->arrow_tip_sz = tip_sz;
1646 plcItemPtr->updateMap = 1;
1647 return TCL_OK;
1648 } else {
1649 Tcl_AppendResult(interp, "Arrow should be specified as "
1650 "{azimuth length tip_size}", NULL);
1651 return TCL_ERROR;
1652 }
1653 }
1654
1655 /*
1656 *------------------------------------------------------------------------
1657 *
1658 * printArrowOption --
1659 *
1660 * This procedure is invoked by the Tk configuration code
1661 * to produce a printable string for the "-arrow" configuration
1662 * option.
1663 *
1664 * Results:
1665 * The return value is a string describing the state for
1666 * the item referred to by "widgRec". In addition, *freeProcPtr
1667 * is filled in with the address of a procedure to call to free
1668 * the result string when it's no longer needed.
1669 *
1670 * Side effects:
1671 * None.
1672 *
1673 *------------------------------------------------------------------------
1674 */
1675
1676 static char *
printArrowOption(clientData,tkwin,widgRec,offset,freeProc)1677 printArrowOption(clientData, tkwin, widgRec, offset, freeProc)
1678 ClientData clientData; /* Not used */
1679 Tk_Window tkwin; /* Window containing the geomap item */
1680 char *widgRec; /* Pointer to item record */
1681 int offset; /* Offset into widgRec */
1682 Tcl_FreeProc **freeProc; /* Pointer to variable to fill in with
1683 * information about how to reclaim
1684 * storage for return string. */
1685 {
1686 PlaceItem *plcItemPtr = (PlaceItem *)(widgRec + offset);
1687 char az[TCL_DOUBLE_SPACE], len[TCL_INTEGER_SPACE], tip_sz[TCL_DOUBLE_SPACE];
1688 char *coordPtr[3];
1689
1690 coordPtr[0] = az;
1691 coordPtr[1] = len;
1692 coordPtr[2] = tip_sz;
1693 *freeProc = Tcl_Free;
1694 Tcl_PrintDouble(NULL, AngleToDeg(plcItemPtr->arrow_az), az);
1695 sprintf(len, "%lf", plcItemPtr->arrow_len);
1696 Tcl_PrintDouble(NULL, plcItemPtr->arrow_tip_sz, tip_sz);
1697 return Tcl_Merge(3, coordPtr);
1698 }
1699
1700 /*
1701 *------------------------------------------------------------------------
1702 *
1703 * updateMap --
1704 *
1705 * This procedure updates the mapPt member of a PlaceItem.
1706 *
1707 * Results:
1708 * None.
1709 * Side effects:
1710 * Members in item record that depend on projection are updated.
1711 *
1712 *------------------------------------------------------------------------
1713 */
1714
1715 static void
updateMap(clientData)1716 updateMap(clientData)
1717 ClientData clientData; /* Geoplace item in need of update */
1718 {
1719 PlaceItem *plcItemPtr = (PlaceItem *)clientData;
1720 Tclgeomap_Place geoPlace = plcItemPtr->tclGeoPlace;
1721 GeoProj proj = (GeoProj)plcItemPtr->proj;
1722 GeoPt geoPt;
1723 MapPt mapPt, step2;
1724
1725 if ( !geoPlace || !proj ) {
1726 plcItemPtr->mapPt = MapPtNowhere();
1727 plcItemPtr->updateMap = 0;
1728 hide(plcItemPtr);
1729 return;
1730 }
1731
1732 /*
1733 * Compute the new map coordinates of the place.
1734 */
1735
1736 plcItemPtr->mRefPt = LatLonToProj(plcItemPtr->refPt, proj);
1737 geoPt = Tclgeomap_PlaceLoc(geoPlace);
1738 mapPt = plcItemPtr->mapPt = LatLonToProj(geoPt, proj);
1739
1740 /*
1741 * If necessary, figure out which way the arrow should be pointing on
1742 * the map.
1743 */
1744
1745 if (plcItemPtr->arrow_len != 0 && plcItemPtr->arrowColor != None) {
1746 double arrow_len = plcItemPtr->arrow_len;
1747 double d_abs, d_ord, hypot;
1748 double sin_theta, cos_theta;
1749 double sin_alpha = sin(TKGEOMAP_PLACE_TIP_ANG * M_PI / 180.0);
1750 double cos_alpha = cos(TKGEOMAP_PLACE_TIP_ANG * M_PI / 180.0);
1751 double t = plcItemPtr->arrow_len * plcItemPtr->arrow_tip_sz;
1752 double cos_cos, cos_sin, sin_cos, sin_sin;
1753
1754 step2 = LatLonToProj(GeoStep(geoPt, plcItemPtr->arrow_az,
1755 AngleFmDeg(0.25)), proj);
1756 d_abs = step2.abs - mapPt.abs;
1757 d_ord = step2.ord - mapPt.ord;
1758 hypot = sqrt(d_abs * d_abs + d_ord * d_ord);
1759 cos_theta = d_abs / hypot;
1760 sin_theta = d_ord / hypot;
1761 cos_cos = cos_theta * cos_alpha;
1762 sin_sin = sin_theta * sin_alpha;
1763 sin_cos = sin_theta * cos_alpha;
1764 cos_sin = cos_theta * sin_alpha;
1765 plcItemPtr->arrow_base_x = -ceil(0.5 * arrow_len * cos_theta);
1766 plcItemPtr->arrow_base_y = ceil(0.5 * arrow_len * sin_theta);
1767 plcItemPtr->arrow_head_x = ceil(0.5 * arrow_len * cos_theta);
1768 plcItemPtr->arrow_head_y = -ceil(0.5 * arrow_len * sin_theta);
1769 plcItemPtr->arrow_ltip_x = - ceil(t * (cos_cos + sin_sin));
1770 plcItemPtr->arrow_ltip_y = ceil(t * (sin_cos - cos_sin));
1771 plcItemPtr->arrow_rtip_x = - ceil(t * (cos_cos - sin_sin));
1772 plcItemPtr->arrow_rtip_y = ceil(t * (sin_cos + cos_sin));
1773 }
1774
1775 plcItemPtr->updateMap = 0;
1776 plcItemPtr->updateCvs = 1;
1777 }
1778
1779 /*
1780 *------------------------------------------------------------------------
1781 *
1782 * updateCvs --
1783 *
1784 * This procedure updates the mapLnArr member of a geoplace item.
1785 *
1786 * Results:
1787 * None.
1788 *
1789 * Side effects:
1790 * The coords member and bounding box of the geoplace item are updated.
1791 *
1792 *------------------------------------------------------------------------
1793 */
1794
1795 static void
updateCvs(plcItemPtr)1796 updateCvs(plcItemPtr)
1797 PlaceItem *plcItemPtr; /* Geoplace item to update */
1798 {
1799 Tk_Canvas canvas; /* Canvas in which to render the item */
1800 Tk_Window tkwin; /* Window with canvas */
1801 double cvsPerM; /* Points per meter on canvas */
1802 double cvsPerMapM; /* Points per meter on projection plane */
1803 int x1_, x2_, y1_, y2_; /* Boundary limits for parts of the item */
1804 int x1, x2, y1, y2;
1805
1806 canvas = plcItemPtr->canvas;
1807 tkwin = Tk_CanvasTkwin(canvas);
1808 Tk_CanvasEventuallyRedraw(plcItemPtr->canvas,
1809 plcItemPtr->header.x1, plcItemPtr->header.y1,
1810 plcItemPtr->header.x2, plcItemPtr->header.y2);
1811 if ( !plcItemPtr->tclGeoPlace || !plcItemPtr->proj ) {
1812 plcItemPtr->mapPt = MapPtNowhere();
1813 plcItemPtr->updateMap = 0;
1814 hide(plcItemPtr);
1815 return;
1816 }
1817 if ( ( !plcItemPtr->dotColor || plcItemPtr->dotSize <= 0)
1818 && ( !plcItemPtr->bmColor || !plcItemPtr->bitmap)
1819 && ( !plcItemPtr->textColor || !plcItemPtr->text) ) {
1820 hide(plcItemPtr);
1821 return;
1822 }
1823 if (plcItemPtr->updateMap) {
1824 updateMap(plcItemPtr);
1825 }
1826 if (MapPtIsNowhere(plcItemPtr->mapPt)) {
1827 hide(plcItemPtr);
1828 return;
1829 }
1830 Tk_CanvasGetCoord(NULL, canvas, "100.0c", &cvsPerM);
1831 cvsPerMapM = cvsPerM * plcItemPtr->scale;
1832 plcItemPtr->xPlc = plcItemPtr->xRef
1833 + (plcItemPtr->mapPt.abs - plcItemPtr->mRefPt.abs) * cvsPerMapM;
1834 plcItemPtr->yPlc = plcItemPtr->yRef
1835 - (plcItemPtr->mapPt.ord - plcItemPtr->mRefPt.ord) * cvsPerMapM;
1836
1837 /*
1838 * Recompute bounding box
1839 */
1840
1841 x1 = plcItemPtr->xPlc - (plcItemPtr->dotSize + 1) / 2 - 1;
1842 x2 = plcItemPtr->xPlc + (plcItemPtr->dotSize + 1) / 2 + 1;
1843 y1 = plcItemPtr->yPlc - (plcItemPtr->dotSize + 1) / 2 - 1;
1844 y2 = plcItemPtr->yPlc + (plcItemPtr->dotSize + 1) / 2 + 1;
1845 if ( (plcItemPtr->bitmap != None) && (plcItemPtr->bmColor != None) ) {
1846 int w, h;
1847
1848 Tk_SizeOfBitmap(Tk_Display(tkwin), plcItemPtr->bitmap, &w, &h);
1849 x1_ = floor(plcItemPtr->xPlc - w / 2) - 1;
1850 x2_ = ceil(plcItemPtr->xPlc + w / 2) + 1;
1851 y1_ = floor(plcItemPtr->yPlc - h / 2) - 1;
1852 y2_ = ceil(plcItemPtr->yPlc + h / 2) + 1;
1853
1854 x1 = (x1 < x1_) ? x1 : x1_;
1855 x2 = (x2 > x2_) ? x2 : x2_;
1856 y1 = (y1 < y1_) ? y1 : y1_;
1857 y2 = (y2 > y2_) ? y2 : y2_;
1858 }
1859 if (plcItemPtr->text && (plcItemPtr->textColor != None)
1860 && plcItemPtr->layout ) {
1861
1862 x1_ = plcItemPtr->xPlc + plcItemPtr->xTxt;
1863 x2_ = x1_ + plcItemPtr->txtWidth;
1864 y1_ = plcItemPtr->yPlc + plcItemPtr->yTxt;
1865 y2_ = y1_ + plcItemPtr->txtHeight;
1866
1867 x1 = (x1 < x1_) ? x1 : x1_;
1868 x2 = (x2 > x2_) ? x2 : x2_;
1869 y1 = (y1 < y1_) ? y1 : y1_;
1870 y2 = (y2 > y2_) ? y2 : y2_;
1871 }
1872 if (plcItemPtr->arrow_len != 0) {
1873 int t = ceil(plcItemPtr->arrow_len * plcItemPtr->arrow_tip_sz);
1874 int arrow_len = plcItemPtr->arrow_len;
1875 x1_ = plcItemPtr->xPlc - (arrow_len + 1) / 2 - t - 1;
1876 x2_ = plcItemPtr->xPlc + (arrow_len + 1) / 2 + t + 1;
1877 y1_ = plcItemPtr->yPlc - (arrow_len + 1) / 2 - t - 1;
1878 y2_ = plcItemPtr->yPlc + (arrow_len + 1) / 2 + t + 1;
1879
1880 x1 = (x1 < x1_) ? x1 : x1_;
1881 x2 = (x2 > x2_) ? x2 : x2_;
1882 y1 = (y1 < y1_) ? y1 : y1_;
1883 y2 = (y2 > y2_) ? y2 : y2_;
1884 }
1885 if ( x1 >= x2 || y1 >= y2 ) {
1886 hide(plcItemPtr);
1887 return;
1888 }
1889 plcItemPtr->header.x1 = x1;
1890 plcItemPtr->header.x2 = x2;
1891 plcItemPtr->header.y1 = y1;
1892 plcItemPtr->header.y2 = y2;
1893 Tk_CanvasEventuallyRedraw(plcItemPtr->canvas,
1894 plcItemPtr->header.x1, plcItemPtr->header.y1,
1895 plcItemPtr->header.x2, plcItemPtr->header.y2);
1896
1897 plcItemPtr->updateCvs = 0;
1898 }
1899