/*
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1