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