/* * tclgeomapProj.c -- * * This file defines structures and functions that add the ability to * convert between geographic (lat-lon) and map coordinates in Tcl. * * @(#) $Id: tclgeomapProj.c,v 1.7 2007/06/27 18:38:56 tkgeomap Exp $ * */ #include "tclgeomap.h" #include "tclgeomapInt.h" /* * Forward declarations. */ static int set_proj _ANSI_ARGS_((GeoProj proj, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int geoProjCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int new _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int set _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int rotation _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static void deleteProc _ANSI_ARGS_((ClientData clientData)); static int info _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int fmLatLon _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); static int toLatLon _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])); /* * This table keeps a list of available projections. Keys are Tclgeomap_Proj * structures, which are also clientData's of the corresponding commands. * Values are not used. */ static Tcl_HashTable projections; /* *------------------------------------------------------------------------ * * TclgeomapProjInit -- * * This procedure extends Tcl with the ability to define and use * certain geographic projections. * * Results: * A standard Tcl result. * * Side effects: * The "geomap::projection" command is added to the interpreter. * *------------------------------------------------------------------------ */ int TclgeomapProjInit(interp) Tcl_Interp *interp; /* Current Tcl interpreter */ { static int loaded; /* Tell if package already loaded */ if (loaded) { return TCL_OK; } #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { return TCL_ERROR; } #endif Tcl_InitHashTable(&projections, TCL_ONE_WORD_KEYS); Tcl_CreateObjCommand(interp, "::geomap::projection", new, NULL, NULL); loaded = 1; return TCL_OK; } /* *------------------------------------------------------------------------ * * Tclgeomap_GetProj -- * * This procedure finds a GeoProj given the name of its command in Tcl. * * Results: * See the user documentation. * * Side effects: * None. * *------------------------------------------------------------------------ */ struct Tclgeomap_Proj* Tclgeomap_GetProj(interp, name) Tcl_Interp *interp; /* Current interpreter */ char *name; /* Name of a Tcl command used to access a * projection */ { Tcl_CmdInfo info; if (Tcl_GetCommandInfo(interp, name, &info)) { return info.objClientData; } else { return NULL; } } /* *------------------------------------------------------------------------ * * set_proj -- * * This procedure modifies an existing projection. * * Results: * A standard Tcl result. * * Side effects: * The fields of a Tclgeomap_Proj structure are modified in accordance * with options given on the command line. * *------------------------------------------------------------------------ */ int set_proj(proj, interp, objc, objv) GeoProj proj; /* The projection to modify */ Tcl_Interp *interp; /* Current interpreter, for error messages */ int objc; /* Number of arguments in command line chunk */ Tcl_Obj *CONST objv[]; /* Argument objects in command line chunk */ { double rLatDeg, rLonDeg; /* Reference latitude and longitude (degrees) */ Angle rLat, rLon; /* Reference latitude and longitude */ GeoPt refPt; /* Reference point*/ static char *projections[] = { "CylEqDist", "Mercator", "CylEqArea", "LambertConfConic", "LambertEqArea", "Stereographic", "PolarStereographic", "Orthographic", NULL }; /* Projection names */ enum index { CYL_EQ_DIST, MERCATOR, CYL_EQ_AREA, LAMBERT_CONF_CONIC, LAMBERT_EQ_AREA, STEREOGRAPHIC, POLAR_STEREOGRAPHIC, ORTHOGRAPHIC }; /* Indices in projections array */ int idx; /* Index for projection name given * on command line */ char *nsStr; /* "N" or "S" for Polar Stereographic */ Angle d90 = AngleFmDeg(90.0); if (objc < 1) { Tcl_AppendResult(interp, "Projection specifier must " "have at least projection type\n", NULL); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[0], projections, "projection", 0, &idx) != TCL_OK) { return TCL_ERROR; } switch ((enum index)idx) { case CYL_EQ_DIST: if (objc == 2) { if (Tclgeomap_GetGeoPtFromObj(interp, objv[1], &refPt) != TCL_OK) { return TCL_ERROR; } GeoPtGetDeg(refPt, &rLatDeg, &rLonDeg); } else if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLatDeg) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[2], &rLonDeg) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "Cylindrical Equidistant must have refPoint OR" " refLat and refLon. ", NULL); return TCL_ERROR; } SetCylEqDist(proj, AngleFmDeg(rLatDeg), AngleFmDeg(rLonDeg)); break; case MERCATOR: if (objc == 2) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLonDeg) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "Mercator must have reflon. ", NULL); return TCL_ERROR; } SetMercator(proj, AngleFmDeg(rLonDeg)); break; case CYL_EQ_AREA: if (objc == 2) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLonDeg) != TCL_OK) { return TCL_ERROR; } } else { Tcl_AppendResult(interp, "CylEqArea must have reflon. ", NULL); return TCL_ERROR; } SetCylEqArea(proj, AngleFmDeg(rLonDeg)); break; case LAMBERT_CONF_CONIC: if (objc == 2) { if (Tclgeomap_GetGeoPtFromObj(interp, objv[1], &refPt) != TCL_OK) { return TCL_ERROR; } rLat = refPt.lat; rLon = refPt.lon; } else if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLatDeg) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[2], &rLonDeg) != TCL_OK) { return TCL_ERROR; } rLat = AngleFmDeg(rLatDeg); rLon = AngleFmDeg(rLonDeg); } else { Tcl_AppendResult(interp, "LambertConfConic must have refPoint OR" " refLat and refLon. ", NULL); return TCL_ERROR; } if (AngleCmp(rLat, 0) == 0) { /* * Lambert Conformal Conic with reference latitude 0.0 is * equivalent to Mercator. */ SetMercator(proj, rLon); } else if (AngleCmp(rLat, d90) == 0) { /* * Lambert conformal conic with reference latitude 90.0 is * equivalent to North Polar Stereographic. */ SetStereographic(proj, refPt); } else if (AngleCmp(rLat, -d90) == 0) { /* * Lambert conformal conic with reference latitude 90.0 is * equivalent to South Polar Stereographic. */ SetStereographic(proj, refPt); } else { SetLambertConfConic(proj, rLat, rLon); } break; case LAMBERT_EQ_AREA: if (objc == 2) { if (Tclgeomap_GetGeoPtFromObj(interp, objv[1], &refPt) != TCL_OK) { return TCL_ERROR; } } else if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLatDeg) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[2], &rLonDeg) != TCL_OK) { return TCL_ERROR; } refPt = GeoPtFmDeg(rLatDeg, rLonDeg); } else { Tcl_AppendResult(interp, "LambertEqArea must have refPoint or " "refLat and refLon. ", NULL); return TCL_ERROR; } SetLambertEqArea(proj, refPt); break; case STEREOGRAPHIC: if (objc == 2) { if (Tclgeomap_GetGeoPtFromObj(interp, objv[1], &refPt) != TCL_OK) { return TCL_ERROR; } } else if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLatDeg) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[2], &rLonDeg) != TCL_OK) { return TCL_ERROR; } refPt = GeoPtFmDeg(rLatDeg, rLonDeg); } else { Tcl_AppendResult(interp, "Stereographic must have refPoint or " "{refLat refLon}. ", NULL); return TCL_ERROR; } SetStereographic(proj, refPt); break; case POLAR_STEREOGRAPHIC: if (objc != 2) { Tcl_AppendResult(interp, "Must indicate N or S for PolarStereographic. ", NULL); return TCL_ERROR; } nsStr = Tcl_GetString(objv[1]); if (strcmp("N", nsStr) == 0) { /* * Set Arctic polar stereographic with Prime Meridian * vertical on map. */ refPt.lat = d90; refPt.lon = 0; } else if (strcmp("S", nsStr) == 0) { /* * Set Antarctic polar stereographic with Prime Meridian * vertical on map */ refPt.lat = -d90; refPt.lon = 0; } else { Tcl_AppendResult(interp, "PolarStereographic requires \"N\" or \"S\". ", NULL); return TCL_ERROR; } SetStereographic(proj, refPt); break; case ORTHOGRAPHIC: if (objc == 2) { if (Tclgeomap_GetGeoPtFromObj(interp, objv[1], &refPt) != TCL_OK) { return TCL_ERROR; } } else if (objc == 3) { if (Tcl_GetDoubleFromObj(interp, objv[1], &rLatDeg) != TCL_OK || Tcl_GetDoubleFromObj(interp, objv[2], &rLonDeg) != TCL_OK) { return TCL_ERROR; } refPt = GeoPtFmDeg(rLatDeg, rLonDeg); } else { Tcl_AppendResult(interp, "Orthographic must have refPoint or " "refLat and refLon. ", NULL); return TCL_ERROR; } SetOrthographic(proj, refPt); } return TCL_OK; } /* *------------------------------------------------------------------------ * * Tclgeomap_ProjName -- * * This procedure returns the name of a projection. * * Results: * See the user documentation. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ CONST char * Tclgeomap_ProjName(projPtr) struct Tclgeomap_Proj *projPtr; { return Tcl_GetCommandName(projPtr->interp, projPtr->cmd); } /* *------------------------------------------------------------------------ * * new -- * * This is the callback for the "geomap::projection ..." command. See the * user documentation for usage details. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ static int new(clientData, interp, objc, objv) ClientData clientData; /* Not used */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { struct Tclgeomap_Proj *projPtr; /* New projection */ static int cnt; /* Counter used to make projection identifier */ static Tcl_Obj *cntObj; /* Object that holds cnt */ Tcl_Obj *rslt; /* Command result */ int n; if (objc < 2) { Tcl_WrongNumArgs(interp, 2, objv, "projectionName [options ...]"); return TCL_ERROR; } if ( !cntObj ) { cntObj = Tcl_NewObj(); } projPtr = (struct Tclgeomap_Proj *)CKALLOC(sizeof(*projPtr)); GeoProjInit((GeoProj)projPtr); if (set_proj((GeoProj)projPtr, interp, objc - 1, objv + 1) != TCL_OK) { Tcl_AppendResult(interp, "Could not set values for new projection. ", NULL); GeoProjFree((GeoProj)projPtr); CKFREE((char *)projPtr); return TCL_ERROR; } Tcl_InitHashTable(&projPtr->updateTasks, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&projPtr->deleteTasks, TCL_ONE_WORD_KEYS); Tcl_CreateHashEntry(&projections, (ClientData)projPtr, &n); rslt = Tcl_GetObjResult(interp); Tcl_SetStringObj(rslt, "::geomap::proj", -1); Tcl_SetIntObj(cntObj, cnt); Tcl_AppendObjToObj(rslt, cntObj); cnt++; projPtr->interp = interp; projPtr->cmd = Tcl_CreateObjCommand(interp, Tcl_GetString(rslt), geoProjCmd, projPtr, deleteProc); Tcl_SetObjResult(interp, rslt); return TCL_OK; } /* *------------------------------------------------------------------------ * * geoProjCmd -- * * This is the callback for the Tcl commands created by the * "geomap::projection" command. * * Results: * A standard Tcl result. * * Side effects: * The procedure corresponding to the second word on the command line * is called. * *------------------------------------------------------------------------ */ static int geoProjCmd(clientData, interp, objc, objv) ClientData clientData; /* Projection managed by the command */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { static char *subCmdNms[] = { "set", "rotation", "info", "fmlatlon", "tolatlon", NULL }; Tcl_ObjCmdProc *subCmdProcPtr[] = { set, rotation, info, fmLatLon, toLatLon }; int i; if (objc == 1) { Tcl_WrongNumArgs(interp, 1, objv, "subcommand"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], subCmdNms, "subcommand", 0, &i) != TCL_OK) { return TCL_ERROR; }; return (subCmdProcPtr[i])(clientData, interp, objc, objv); } /* *------------------------------------------------------------------------ * * set -- * * This is the callback for the "projName set ..." command. * * Results: * A standard Tcl result. * * Side effects: * Fields in a Tclgeomap_Proj structure are modified in accordance with * options given on the command line. * The updateTasks for the projection are run. * *------------------------------------------------------------------------ */ static int set(clientData, interp, objc, objv) ClientData clientData; /* Projection to set */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { struct Tclgeomap_Proj *projPtr; /* Projection to set */ Tcl_HashEntry *entry; /* GeoProj entry */ Tcl_HashSearch search; /* Update loop parameter */ ClientData cd; /* ClientData for an update proc */ Tclgeomap_ProjUpdateProc *updateProc; /* Update procedure */ if (objc < 4) { Tcl_WrongNumArgs(interp, 2, objv, "?option ...?"); return TCL_ERROR; } projPtr = (struct Tclgeomap_Proj *)clientData; if (set_proj((GeoProj)projPtr, interp, objc - 2, objv + 2) != TCL_OK) { Tcl_AppendResult(interp, "Could not set values for projection", NULL); return TCL_ERROR; } for (entry = Tcl_FirstHashEntry(&projPtr->updateTasks, &search); entry != NULL; entry = Tcl_NextHashEntry(&search)) { cd = (ClientData)Tcl_GetHashKey(&projPtr->updateTasks, entry); updateProc = (Tclgeomap_ProjUpdateProc *)Tcl_GetHashValue(entry); (*updateProc)(cd); } return TCL_OK; } /* *------------------------------------------------------------------------ * * rotation -- * * This is the callback for the "projName rotation ..." command. * * Results: * A standard Tcl result. * * Side effects: * Fields in a Tclgeomap_Proj structure are modified in accordance with * options given on the command line. * The updateTasks for the projection are run. * *------------------------------------------------------------------------ */ static int rotation(clientData, interp, objc, objv) ClientData clientData; /* Projection to set */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { struct Tclgeomap_Proj *projPtr; /* Projection to set */ GeoProj proj; Tcl_HashEntry *entry; /* GeoProj entry */ Tcl_HashSearch search; /* Update loop parameter */ ClientData cd; /* ClientData for an update proc */ Tclgeomap_ProjUpdateProc *updateProc; /* Update procedure */ projPtr = (struct Tclgeomap_Proj *)clientData; proj = (GeoProj)projPtr; if (objc == 2) { struct GeoProjInfo info = GeoProjGetInfo(proj); Tcl_SetObjResult(interp, Tcl_NewDoubleObj(AngleToDeg(info.rotation))); return TCL_OK; } else if (objc == 3) { double a; int i; /* Index returned by Tcl_GetIndexFromObj */ static char *brgNms[] = { "north", "nneast", "neast", "eneast", "east", "eseast", "seast", "sseast", "south", "sswest", "swest", "wswest", "west", "wnwest", "nwest", "nnwest", NULL }; /* Bearing names */ static double brgs[] = { 0.0, -22.5, -45.0, -67.5, -90.0, -112.5, -135.0, -157.5, 180.0, 157.5, 135.0, 112.5, 90.0, 67.5, 45.0, 22.5 }; /* Angles corresponding to bearing names */ if (Tcl_GetIndexFromObj(NULL, objv[2], brgNms, "", 0, &i) == TCL_OK) { a = AngleFmDeg(brgs[i]); } else if (Tcl_GetDoubleFromObj(NULL, objv[2], &a) == TCL_OK) { a = GwchLon(AngleFmDeg(a)); } else { Tcl_AppendResult(interp, " Rotation should be a float-point number ", "of one of: north, nneast, neast, eneast, east, eseast, " "seast, sseast, south, sswest, swest, wswest, west, wnwest, " "nwest, or nnwest", NULL); return TCL_ERROR; } GeoProjSetRotation(proj, a); for (entry = Tcl_FirstHashEntry(&projPtr->updateTasks, &search); entry != NULL; entry = Tcl_NextHashEntry(&search)) { cd = (ClientData)Tcl_GetHashKey(&projPtr->updateTasks, entry); updateProc = (Tclgeomap_ProjUpdateProc *)Tcl_GetHashValue(entry); (*updateProc)(cd); } } else { Tcl_WrongNumArgs(interp, 2, objv, "?rotation_angle?"); return TCL_ERROR; } return TCL_OK; } /* *------------------------------------------------------------------------ * * info -- * * This is the callback for the "projName info ..." command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ static int info(clientData, interp, objc, objv) ClientData clientData; /* Projection to get info about */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { char *descr; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); return TCL_ERROR; } descr = GeoProjDescriptor((GeoProj)clientData); Tcl_SetObjResult(interp, Tcl_NewStringObj(descr, -1)); return TCL_OK; } /* *------------------------------------------------------------------------ * * deleteProc -- * * This procedure is called when the command associated with a projection * is deleted. * * Results: * A standard Tcl result. * * Side effects: * A Tclgeomap_Proj structure and its contents are freed. * *------------------------------------------------------------------------ */ static void deleteProc(clientData) ClientData clientData; /* Projection being deleted */ { struct Tclgeomap_Proj *projPtr; /* Tclgeomap_Proj from hash table */ Tcl_HashEntry *entry; /* Entry for projPtr->updateTasks */ Tcl_HashSearch search; ClientData cd; /* Clientdata in a deletion task */ Tclgeomap_ProjDeleteProc *deleteProc; projPtr = (struct Tclgeomap_Proj *)clientData; for (entry = Tcl_FirstHashEntry(&projPtr->deleteTasks, &search); entry != NULL; entry = Tcl_NextHashEntry(&search)) { cd = (ClientData)Tcl_GetHashKey(&projPtr->deleteTasks, entry); deleteProc = (Tclgeomap_ProjDeleteProc *)Tcl_GetHashValue(entry); (*deleteProc)(cd); } entry = Tcl_FindHashEntry(&projections, (ClientData)projPtr); Tcl_DeleteHashEntry(entry); GeoProjFree((GeoProj)projPtr); Tcl_DeleteHashTable(&projPtr->updateTasks); Tcl_DeleteHashTable(&projPtr->deleteTasks); CKFREE((char *)projPtr); } /* *------------------------------------------------------------------------ * * fmLatLon -- * * This is the callback for the "projName fmLatLon ..." command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ static int fmLatLon(clientData, interp, objc, objv) ClientData clientData; /* Projection */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { GeoProj proj; /* Projection for making conversion */ GeoPt geoPt; /* Input point from command line */ MapPt mapPt; /* Result */ if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "{lat lon}"); return TCL_ERROR; } proj = (GeoProj)clientData; if (Tclgeomap_GetGeoPtFromObj(interp, objv[2], &geoPt) != TCL_OK) { return TCL_ERROR; } mapPt = LatLonToProj(geoPt, proj); if (MapPtIsSomewhere(mapPt)) { Tcl_SetObjResult(interp, Tclgeomap_NewMapPtObj(mapPt)); return TCL_OK; } else { double lat, lon; char lats[TCL_DOUBLE_SPACE], lons[TCL_DOUBLE_SPACE]; GeoPtGetDeg(geoPt, &lat, &lon); Tcl_PrintDouble(NULL, lat, lats); Tcl_PrintDouble(NULL, lon, lons); Tcl_AppendResult(interp, "Could not get map point for {", lats, " ", lons, "}", NULL); return TCL_ERROR; } } /* *------------------------------------------------------------------------ * * toLatLon -- * * This is the callback for the "projName toLatLon ..." command. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ static int toLatLon(clientData, interp, objc, objv) ClientData clientData; /* Projection */ Tcl_Interp *interp; /* Current interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const objv[]; /* Argument objects */ { GeoProj proj; /* Projection for making conversion */ MapPt projPt; /* Input point from command line */ GeoPt geoPt; /* Result */ if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "{abs ord}"); return TCL_ERROR; } proj = (GeoProj)clientData; if (Tclgeomap_GetMapPtFromObj(interp, objv[2], &projPt) != TCL_OK) { return TCL_ERROR; } geoPt = ProjToLatLon(projPt, proj); if (GeoPtIsSomewhere(geoPt)) { Tcl_SetObjResult(interp, Tclgeomap_NewGeoPtObj(geoPt)); return TCL_OK; } else { double lat, lon; char lats[TCL_DOUBLE_SPACE], lons[TCL_DOUBLE_SPACE]; GeoPtGetDeg(geoPt, &lat, &lon); Tcl_PrintDouble(NULL, lat, lats); Tcl_PrintDouble(NULL, lon, lons); Tcl_AppendResult(interp, "Could not get geographic point for {", lats, " ", lons, "} for projection ", GeoProjDescriptor(proj), NULL); return TCL_ERROR; } } /* *------------------------------------------------------------------------ * * Tclgeomap_AddProjUpdateTask -- * * This procedure arranges for a given action to be taken when a * projection changes. * * Results: * None. * * Side effects: * An entry is added to the updateTasks table of a Tclgeomap_Proj structure. * It can be removed with a call to Tclgeomap_CnxProjUpdateTask. * *------------------------------------------------------------------------ */ void Tclgeomap_AddProjUpdateTask(projPtr, updateProc, clientData) struct Tclgeomap_Proj *projPtr; Tclgeomap_ProjUpdateProc updateProc;/* Procedure to call when the * projection changes */ ClientData clientData; /* Additional information provided to * updateProc, and identifier for * this task in subsequent call to * Tclgeomap_CnxProjUpdateTask. */ { Tcl_HashEntry *entry; int n; if ( !updateProc || !clientData || !Tcl_FindHashEntry(&projections, (ClientData)projPtr) ) { return; } entry = Tcl_CreateHashEntry(&projPtr->updateTasks, (char *)clientData, &n); Tcl_SetHashValue(entry, updateProc); return; } /* *------------------------------------------------------------------------ * * Tclgeomap_CnxProjUpdateTask -- * * This procedure cancels an update task created by an earlier call to * Tclgeomap_AddProjUpdateTask. * * Results: * None. * * Side effects: * An entry is removed from the updateTasks table of a Tclgeomap_Proj * structure. * *------------------------------------------------------------------------ */ void Tclgeomap_CnxProjUpdateTask(projPtr, clientData) struct Tclgeomap_Proj *projPtr; ClientData clientData; /* clientData argument from earlier call to * Tclgeomap_AddProjUpdateTask.*/ { Tcl_HashEntry *entry; if ( !projPtr || !(entry = Tcl_FindHashEntry(&projPtr->updateTasks, (char *)clientData)) ) { return; } Tcl_DeleteHashEntry(entry); } /* *------------------------------------------------------------------------ * * Tclgeomap_AddProjDeleteTask -- * * Results: * None. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ void Tclgeomap_AddProjDeleteTask(projPtr, proc, clientData) Tclgeomap_Proj projPtr; Tclgeomap_ProjDeleteProc proc; ClientData clientData; { int n; Tcl_HashEntry *entry; if ( !projPtr || ! proc || !clientData || !Tcl_FindHashEntry(&projections, (ClientData)projPtr) ) { return; } entry = Tcl_CreateHashEntry(&projPtr->deleteTasks, clientData, &n); Tcl_SetHashValue(entry, (ClientData)proc); } /* *------------------------------------------------------------------------ * * Tclgeomap_CnxProjDeleteTask -- * * This procedure cancels a callback added by Tclgeomap_AddProjDeleteTask. * * Results: * None. * * Side effects: * See the user documentation. * *------------------------------------------------------------------------ */ void Tclgeomap_CnxProjDeleteTask(projPtr, clientData) Tclgeomap_Proj projPtr; ClientData clientData; { Tcl_HashEntry *entry; if ( !projPtr || !clientData ) { return; } if ( !(entry = Tcl_FindHashEntry(&projPtr->deleteTasks, (char *)clientData)) ) { return; } Tcl_DeleteHashEntry(entry); }