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