CS-Map Overview

As one programmer to another, I present this Overview Section as the manual for people who, like myself, don't read the manual (until something doesn't work). This section contains all of the information you'll need to get started quickly, and the specific information you'll need to stay out of trouble. Please read this section before attempting to use CS-MAP. Refer to the remainder of the guide as necessary.

Deferring the details to subsequent sections, it is helpful to consider CS-MAP as consisting of a Coordinate System Dictionary and a set of functions which use the information in the dictionary to accomplish the desired task. All coordinate systems used by CS-MAP reside in the dictionary and are given a name, which we refer to as a key name, much like we give names to files. CS-MAP, then, performs coordinate system conversion based on the names of the coordinate systems provided. This technique eliminates the need to have your users process through a long list of parameters which they (usually) don't understand whenever a conversion is necessary. All they need provide are the names of the appropriate coordinate systems.

Initialization

CS-MAP needs to be initialized. Initialization consists of providing CS-MAP with the directory in which the dictionary files reside. This is accomplished by calling the CS_altdr function. This function takes a single argument, a character string which is the path to the appropriate directory. Calling CS_altdr with a NULL pointer as an argument will cause the value of the environmental variable named CS_MAP_DIR to be used as the data directory. CS_altdr returns and integer zero if the initialization was successful, -1 if not.

This was not a requirement in the past, thus the rather strange name for this initialization function.

Important Note 1: Whenever CS-MAP needs to go to disk to find something, that something often needs to reside in the directory specified by this function call.

Important Note 2: Failing to call this function successfully prior to using CS-MAP almost always results in an memory addressing fault.

High Level Interface

Given the name of the source and target coordinate systems, conversion of coordinate data from one to the other is as simple as a single function call. The following example would cause the coordinate in the array of three doubles named coordinate to be converted from NAD27 based UTM Zone 13 coordinates to NAD83 based Colorado State Plane, Central Zone, coordinates:

status = CS_cnvrt("UTM27-13","CO83-C", coordinate);

It's that simple. The simplicity of this hides several important features. First, note that the datum shift implied by the coordinate systems, NAD27 to NAD83 in this case, is automatically applied. Second, you would hardly ever code an application with hard coded coordinate system names as was done in this example. Simple character arrays that are passed by argument, providing data entered by the user from a choice list, or providing data obtained from a database, whatever, all work just fine. These are just very simple, case insensitive, null terminated strings. Third, the application programmer has no need to know which projections, datums, and/or ellipsoids are involved. Fourth, the source and/or target coordinate systems could just as easily be Latitude and Longitude coordinates, based on any of several units, and referenced to any prime meridian.

Similarly, should your application need to know the grid scale factor at a specific point, all you need code is a function call similar to the following:

grid_scale = CS_scale("CO83-C", coordinate);

Coordinate in this case must be geographic, i.e. the latitude and longitude of the point at which the grid scale is to be determined. Again, it is unlikely that the name of the coordinate system would be hard coded as was done in this example. Need the convergence angle? You have probably figured it out already:

convergence = CS_cnvrg("CO83-C", coordinate);

Concerned about performance? Originally, the above interface was designed as a means by which applications written in languages other than 'C' could access CS-MAP; i.e. no pointers required. However, due to its design and the high speed processors with on-board caches which are common today, this interface provides amazing levels of performance. It is now the interface which we recommend for all simple applications.

Several other features are made available in what we call the High Level Interface; that is features which are available without the use of pointers. The details of all such features are provided in the topic named High Level Interface.

Coordinate System Dictionary

The coordinate system is the heart of the CS-MAP package. The CS-MAP distribution includes the definition of more than 5,000 coordinate systems. Each definition includes the projection to be used, the projection parameters, the datum or ellipsoid to which the coordinate system is referenced, and the unit to be used. Admittedly, many of the coordinate system definitions provided are very similar to others, differing only in the system unit or datum referenced. However, we believe your users will appreciate the simplicity of having only to remember and enter an easy to remember name or two to get what they need. The default feature described elsewhere in this manual can be used in those cases where this design becomes inconvenient.

Coordinate system definitions are stored in a file we refer to as the Coordinate System Dictionary. This file is a simple fixed length record file containing binary data. It is maintained in sorted order by coordinate system name and is accessed using a binary search technique. This provides portability to almost any environment without having to license any other software. Your application will need to provide the CS-MAP functions with the location of the directory in which the Coordinate System Dictionary resides (see CS_altdr). Once CS-MAP locates the Coordinate System Dictionary, it expects to find all most other data files in the same directory.

CS-MAP distributions include an ASCII file which defines all of the coordinate systems included in the distribution. This file is usually committed to version control and treated has a highly valuable source file. A compiler included with CS-MAP can convert this ASCII file into the binary form used by the system.

Important Note: The first four bytes of a binary coordinate system dictionary file is a "magic number". This sequence of bytes are used to identify that the file is indeed a coordinate system dictionary file. The revision level of the dictionary format is also encoded into this "magic number".

Other Interfaces

It is probably obvious to you that the interface described above can not be the most efficient interface possible. Applications which require the absolute highest performance, may want to use the High Performance Interface. This interface requires the knowledge of as many as ten functions. It also requires the use of pointers to structures and, therefore, is usable only from languages such as C, C++, or Pascal which can handle pointers appropriately. It does, however, provide the application programmer with the highest performance level possible, while still insulating your application from changes to the internals of CS-MAP. Using this interface, performance levels of 1,000,000 non-trivial conversions per second are routinely observed.

Applications which are hard coded around specific projections can use the Low Level Interface to obtain high performance solutions which do not require a Coordinate System Dictionary or, for that matter, any other supporting data. That is, at this level, the application programmer has access to the specific code for each projection. Similarly, applications can use the low level interface to access any of the 12 or so datum shift techniques supported by the library.

The High Performance and Low Level Interfaces are described in detail in the remaining chapters of this guide.

Other Dictionaries

Like coordinate systems, datums are many and varied. (The term datum is widely used to refer to a Horizontal Geodetic Reference System. Although this usage is not technically incorrect, we will go along with the crowd and use the simpler term.) While several datum conversion techniques are hard coded into CS-MAP, the actual definitions are not. As you might suspect, there exists a Datum Dictionary which contains the definition of all datums known to the system and provides a name by which they can be accessed (i.e. key name). Coordinate systems are referenced to a datum by including the datum key name in the coordinate system definition. Thus, when converting from one coordinate system to another, CS-MAP can automatically activate the appropriate datum shifts necessary by examining the datum references in the coordinate system definitions. While full support is provided, application programmers rarely, if ever, access the Datum Dictionary directly.

All datum definitions must include a reference to an ellipsoid; coordinate system definitions can include a reference to an ellipsoid. Again, there are many ellipsoid definitions and these are not hard coded into CS-MAP. You guessed it! There is an Ellipsoid Dictionary:

Important Note: Datum and Ellipsoid dictionaries include a "magic number" as the first four bytes of the binary file. These "magic numbers" identify the type of the file in addition to the file format revision level.

Cartographic vs. Geodetic Referencing of Coordinate Systems

While coordinate system definitions can be referenced to a datum, they can also be referenced directly to an ellipsoid. In this manual, we will use the term geodetically referenced coordinate system to refer to the former case, and cartographically referenced coordinate system to refer to the latter. When both the source and target coordinate systems involved in a conversion are geodetically referenced, CS- MAP can automatically perform the necessary datum shift without any additional information required from the user, or any additional code required by the application programmer. When either or both coordinate system definitions are cartographically referenced, the datum shift feature is effectively disabled. That is, CS-MAP cannot calculate a datum shift it does not know both the source and target datums.

In many cases, the datums upon which coordinates are based are known. In these cases, coordinate system definitions are usually geodetically referenced and CS-MAP can, therefore, include the appropriate datum shift automatically whenever appropriate. In other cases, the datum upon which a coordinate system is based is not known and the coordinate system should be cartographically referenced to an ellipsoid. CS-MAP's automatic datum shift feature is then disabled whenever this coordinate system is involved in a coordinate conversion. Therefore, while the individual maintaining the coordinate system definitions may need to understand the distinctions between geodetic and cartographic references, the typical end user is not usually concerned.

Cartographically referenced coordinate systems can be a great convenience to both user and application programmer. For example, the LL coordinate system which you will find in the CS-MAP distribution is cartographically referenced to the WGS84 ellipsoid (not the WGS84 datum). This means that using the LL coordinate system as the target in any conversion produces geographic coordinates which are always based on the same datum as the source coordinate system. This is often very convenient indeed.

Latitudes and Longitudes

Coordinate systems can be defined to be geographic, i.e. consist of latitude and longitude coordinates. This is achieved through the use of a pseudo projection we call the Unity projection. The Unity Projection is simply a projection which does nothing, the results being geographic coordinates. Since the definitions of a latitude and longitude coordinate systems are included in the Coordinate System Dictionary, they can, and indeed do, have datum references, origin longitudes, and units specifications. Thus, several latitude and longitude definitions appear in the coordinate system dictionary. As with any other coordinate system definition, these definitions are either geodetically or cartographically referenced, have a unit specification, and have an origin longitude. In this context, the units are the angular units of measure to be used (e.g. degrees, minutes, seconds, grads, etc.) and the origin longitude is the prime meridian (i.e. Greenwich, Meridian of Paris, etc.). Thus, latitude and longitude coordinates are fully supported by the system, and the application programmer is not required to write any special code to process them.

The distribution Coordinate System Dictionary contains a geographic coordinate system simply named LL. This is a cartographically referenced latitude and longitude coordinate system which is referenced to the Greenwich Prime Meridian, using units of degrees. Thus, LL should be considered to be the generic latitude and longitude coordinate system, and can be used as such. For example, to obtain the grid scale factor of a coordinate system using cartesian coordinates (as opposed to the geographic coordinates required by the CS_scale function) one could simply write as follows:

status = CS_cnvrt("CO83-C", "LL", coordinate);
grid_scale = CS_scale("CO83-C", coordinate);

Note, that due to the generic nature of the LL coordinate system (i.e. cartographically referenced, thereby disabling datum shifts), the intermediary latitude and longitude results will be always be based on the same datum as that of the source coordinate system. Also, the LL coordinate system is defined to match the specific definition of latitude and longitude used internally within CS-MAP. That is, in those few cases where CS-MAP specifically requires a coordinate in terms of latitude and longitude:

  1. the coordinates must be in degrees,
  2. referenced to the Greenwich Prime Meridian, and
  3. west longitude and south latitude must be negative values.

Coordinate Arrays

As is common in the industry, cartesian coordinates are passed in arrays of doubles. The X coordinate is always the first element in the array, the Y coordinate being the second element, and the Z coordinate being the third element. When performing a two dimensional conversion, CS-MAP often ignores the Z coordinate. Obviously, when performing a three dimensional conversion, a valid Z coordinate is required. To simplify use of the library, all coordinate arrays should be dimensioned at three. Typically, a Z value of zero is provided when performing a two dimensional conversion.

In the case of cartesian coordinates, coordinates must be ordered as described above; specifically X, Y, and then Z. While it is common usage to refer to geographic coordinates as latitude and longitude, and it is also common to give the latitude first and the longitude second, CS-MAP requires that the first element of a geographic coordinate be the longitude, the second element be the latitude, and the third element the height. While negative values are usually used to indicate west longitude and south latitude, geographic coordinate systems can be defined where the opposite sign convention is used.

It is important to note that there is a significant difference between coordinates returned to the user which may just happen to be geographic, and the geographic coordinates required by certain CS-MAP functions. The conventions used in "user" coordinates are determined by the coordinate system definition. Thus, in a "user" geographic coordinate, as returned by CS_cs2ll for example, the prime meridian may be other than Greenwich and the unit other than degrees. Users can also define geographic coordinate systems where west longitude is positive and/or the order of the coordinates is swapped.

However, wherever a CS-MAP function specifically requires a geographic coordinate, the values provided must:

  1. be given in degrees,
  2. be referenced to the Greenwich Prime Meridian, and
  3. west longitude and south latitude be given as negative values.

Selected Source Code

For historical reasons, most all global data definitions are coded in distinct modules. This has been very convenient over the years. Many of the features of CS-MAP can be adjusted to better fit into your application by tweaking one of these source modules. Four of these modules are worth mention in this overview: CSdata, CSdataU, CSdataPJ, and CS_error. In CSdata you will find the definition of many global constants used throughout CS-MAP. While you obviously don't want to change the definition of π, there are several other aspects of CS-MAP which are controlled by global variables defined in this module. Make the modifications which you need, recompile, and re-link your application.

CSdataU contains the unit table which CS-MAP uses. To add (or remove) a unit, simply modify the table and recompile.

CSdataPJ contains CS-MAP's projection table. To remove a projection (to reduce the size of your executable, for example), simply remove the projection's entry in the table an all object code references to the projection will be removed.

CS_error contains the text of all error messages.

All data which may be language related is contained in these four modules. To translate the entire system to another language, only these four modules, and perhaps the help file, need attention.

Naming Conventions

Originally, the names of global variables, manifest constants (i.e. defines), structures, and functions used in CS-MAP adhered to a very definitive naming convention. Much of the library still adheres to this convention. This convention was developed with three purposes in mind. First, and foremost, it is necessary to insure that the probability of a name collision with existing application code is kept to a minimum. Second, to enable programmers to quickly determine the type of entity being referenced by a name and to quickly determine where the definition of such can be found. Third, provide an efficient means by which the libraries and other components of CS-MAP can be efficiently maintained and manufactured.

In later developments of the library, such as the inclusion of some C++ elements and the planned porting of the entire library to C++, there are several modules no longer adhere to the original naming convention.

Name Collisions

All names whose scope extends outside the specific file in which is it is defined will start with the two character sequence CS. As described below, this initial sequence may be in upper or lower case. Additionally, every such name will contain at least one upper case character and at least one lower case character. In this way, the possibility of a CS-MAP global name being the same as a name already used in your application is virtually nil.

Function Names

All function names begin with an upper case CS sequence. If the function is expected to be accessed by modules outside of the CS-MAP library in normal use, the initial CS sequence is followed by an underscore character. The remainder of the function name follows, the first of which will be lower case if it is an alphabetic character.

Structure Tags

Structure tags begin with a lower case cs sequence. If the structure is expected to be accessed by modules outside of the CS-MAP library in normal use, the initial sequence is followed by an underscore character. The remainder of the structure tag follows, the first character of which will always be uppercase. Finally, the last character of all structure tags will be the underscore character.

Global Variable Names

Global variable names begin with a lower case cs sequence. If the global variable is expected to be accessed by modules outside of the CS-MAP library in normal use, the initial sequence is followed by an underscore character. The remainder of the global variable name follows, the first character of which will always be an upper case letter. A global variable name will never end with the underscore character. A global variable which is a definition of a structure, or a pointer to same, will usually have the same name as the structure tag, sans the trailing underscore.

Manifest contents

Manifest constant names, e.g. include file define's, begin with a lower case cs sequence. If the constant being defined is expected to be used by modules outside of the CS-MAP library, the initial sequence is followed by an underscore character. The remainder of the constant name follows and will be all upper case.

Naming Convention Examples

The table below shows several examples of the naming convention;

Name Type Comment
CS_csloc Function, external Name of a function expected to be called from outside of the CS-MAP library.
CSnad283 Function, internal Name of a function not expected to be called from outside of the CS-MAP library.
cs_Csdef_ Structure tag, external Structure tag name for a structure expected to be referenced by modules outside of the CS-MAP library.
csNaddir_ Structure tag, internal Structure tag name for a structure not expected to be accessed outside of the CS-MAP library.
cs_Dir Global Variable, external Global variable name expected to be accessed outside of the CS-MAP library
csErrlng Global Variable, internal Global variable name not expected to be accessed outside of the CS-MAP library.
cs_NO_MEM Manifest Constant, external Manifest constant expected to be referenced by modules outside of the CS-MAP library.
csGRF_MAX_ACTIVE Manifest Constant, internal Manifest constant not expected to be referenced by modules outside of the CS-MAP library.

Projection Code Names

Each of the thirty eight projections has a five character code name which is used in all structure tags and function names associated with the specific projection. The table below lists each projection, the five character code value, the structure tag name, and setup function name associated with each as examples of how this code value is used to identify the projection each is associated with. All code elements which are specifically related to specific projection are named in a similar manner.

Projection Code Structure Tag Setup Function
Transverse Mercator trmer cs_Trmer_ CStrmerS
Lambert Conformal Conic lmbrt cs_Lmbrt_ CSlmbrtS
Hotine Oblique Mercator oblqm cs_Oblqm_ CSoblqmS
Alber's Equal Area alber cs_Alber_ CSalberS
Mercator mrcat cs_Mrcat_ CSmrcatS
Miller Cylindrical millr cs_Millr_ CSmillrS
Lambert Equidistant Azimuthal azmed cs_Azmed_ CSazmedS
Lambert Equal Area Azimuthal azmea cs_Azmea_ CSazmeaS
Polar Stereographic pstro cs_Pstro_ CSpstroS
Oblique Stereographic ostro cs_Ostro_ CSostroS
Snyder's Oblique Stereographic sstro cs_Sstro_ CSsstroS
Equidistant Conic edcnc cs_Edcnc_ CsedcncS
Sinusoidal sinus cs_Sinus_ CSsinusS
American Polyconic plycn cs_Plycn_ CSplycnS
Modified Polyconic modpc cs_Modpc_ CsmodpcS
Lambert Tangential lmtan cs_Lmtan_ CSlmtanS
Van der Grinten vdgrn cs_Vdgrn_ CSvdgrnS
Orthographic ortho cs_Ortho_ CSorthoS
Gnomonic gnomc cs_Gnomc_ CsgnomcS
Equidistant Cylindrical edcyl cs_Edcyl_ CSedcylS
Cassini csini cs_Csini_ CScsiniS
Modified Stereographic mstro cs_Mstro_ CSmstroS
New Zealand National Grid nzlnd cs_Nzlnd_ CSnzlndS
Robinson Cylindrical robin cs_Robin_ CSrobinS
Bonne bonne cs_Bonne_ CsbonneS
Equal Area (Authalic) Cylindrical, Normal Aspect nacyl cs_Nacyl_ CSnacylS
Equal Area (Authalic) Cylindrical, Transverse Aspect tacyl cs_Tacyl_ CStacylS
Mollweide molwd cs_Molwd_ CsmolwdS
Eckert IV ekrt4 cs_Ekrt4_ CSekrt4S
Eckert VI ekrt6 cs_Ekrt6_ CSekrt6S
Goode Homolosine hmlsn cs_Hmlsn_ CShmlsnS
Bipolar Oblique Conformal Conic bpcnc cs_Bpcnc_ CSbpcncS
Oblique Cylindrical swiss cs_Swiss_ CSswissS
Snyder Transverse Mercator trmrs cs_Trmrs_ CStrmrsS
Krovak Oblique Conformal Conic krovk cs_Krovk_ CSkrovkS
Non-georeferenced Coordinates nerth cs_Nerth_ CSnerthS
Danish System 34 sys34 cs_Sys34_ CSsys34S
Unity Pseudo Projection unity cs_Unity_ CSunityS

High Level Interface

Functions are provided which can convert a coordinate from one coordinate system to another with a single function call. This set of functions was originally developed specifically for the application programmer who is coding in BASIC, FORTRAN, APL, or other language (other than C or Pascal) which can make simple function calls. It does not use structure pointers of any sort. Since the affect on performance is small (about a 20% reduction), it is now the recommended interface for most applications. Most of the functions described in this section use CSbcclu and CSbdclu to cache coordinate system and datum conversion definitions. Therefore the performance penalty of these functions is reduced to a search of a linked list for the coordinate system names involved. These cache functions are smart enough to keep the most recently accessed items at the front of the list to further minimize the performance penalty. The information presented in this section is intended only to associate a function name with a specific capability.

Basic Coordinate Conversion -- CS_cnvrt

Given a coordinate as an array of three doubles, and the names of two coordinate systems as two character arrays, CS_cnvrt converts the coordinate from one system to another. It's that simple. Where cartesian coordinates are provided and returned, the X coordinate is the first element of the array, the Y coordinate is the second, and the Z is the third element of the array. Where geographic coordinates are provided, the first element in the array must contain the longitude, the second the latitude, and the third element must contain the height. In either case, the manner in which the values are interpreted depends upon the coordinate systems involved. For example, if the source coordinate system definition specifies the unit to be meters, the X, Y, and Z coordinates are considered to be in meters. Similarly, if the target coordinate system is defined as a latitude and longitude system with an angular unit of grads, the returned latitude and longitude coordinates will be in units of grads.

The status value returned by CS_cnvrt informs the calling application of the validity of the results. A zero return value indicates that the requested conversion was completed without complication and the results now occupy the coordinate array. A negative status return value indicates a hard error occurred and that the contents of the coordinate array remain unchanged. A positive, non-zero return status indicates that the conversion was performed, but an abnormality was encountered during the conversion. In this case, the results returned in the coordinate array may not be exactly what the user expects.

In all cases of a negative status return, the values in the provided coordinate array will remain unchanged. Taking the absolute value of the returned status value will often produce the CS-MAP error code for the specific condition causing the hard error. The numeric error code which defines the specific cause of the problem will also be stored in the cs_Error global variable, and a textual description of the error condition can be obtained by calling the CS_errmsg function before calling any other CS-MAP function. Typically, when applications detect a negative status return, the application informs the user using the textual description obtained from CS_errmsg and terminates the current operation.

CS_cnvrt returns a positive non-zero status value whenever it encounters something suspicious, but not something that precludes a conversion. Positive non-zero return values are usually caused by coordinate systems and coordinates which are incompatible, or specific values which are singularity points for the projection(s) involved. A common cause of a positive non-zero return value is the conversion of a point at either pole. CS-MAP will return a positive non-zero value in these cases as longitude is undefined at the poles, and reversing the calculation is unlikely to reproduce the initial value. Another common cause of a positive non-zero status return is providing, say, UTM coordinates when the source coordinate system is given as "LL". UTM coordinates, usually, will not be in the normal range of geographic coordinates and CS-MAP will consider this to be suspicious. A positive return value will also be returned if, for example, it is requested to convert a geographic coordinate in Europe from NAD27 to NAD83.

When a positive non-zero return value from CS_cnvrt is encountered, the typical application issues a warning message to the user and continues. These abnormal, but not necessarily fatal, conditions are often the result the user desires. It should be left the user to decide. For performance reasons, CS- MAP does not automatically generate a textual message for these conditions. However, application programs can analyze the returned status value in order to present a more specific warning message to the end user.

Grid Scale Factor -- CS_scale

Given a coordinate system name and a location in the form of a geographic coordinate, CS_scale will return the grid scale factor of the coordinate system at the specified location. CS_scale returns a negative one in the event of an error condition. In such cases, the cause of the error can be determined by examining cs_Error which will contain the CS-MAP numeric error code of the condition which caused the error. CS_errmsg can be used to obtain a textual description of the error condition. An error caused by the location being outside of the domain of the coordinate system will be indicated by a cs_Error value of zero. In this case, no textual description will be available.

Note that the coordinate provided as the second argument must be a geographic coordinate, i.e. latitude and longitude in degrees referenced to the Greenwich prime meridian. Longitude is the first element in the array, latitude is the second. (The third element is not currently used for grid scale calculations, but may be in the future.) As always for internal geographic coordinates, use negative values for west longitude and south latitude.

Convergence Angle -- CS_cnvrg

Given a coordinate system name and a location in the form of a geographic coordinate, CS_cnvrg will return the convergence angle of the coordinate system at the specified location, in degrees east of north. CS_cnvrg returns a negative 360 (i.e. -360) value in the event of an error condition. In such cases, the cause of the error can be determined by examining cs_Error which will contain the CS- MAP numeric error code of the condition which caused the error. CS_errmsg can then be used to obtain a textual description of the error condition. An error caused by the location being outside of the domain of the coordinate system will be indicated by a cs_Error value of zero. In this case, no textual description will be available.

Note that the coordinate provided as the second argument must be a geographic coordinate, i.e. latitude and longitude in degrees referenced to the Greenwich prime meridian. Longitude is the first element in the array, latitude is the second. (The third element is not used for convergence calculations.) As always, use negative values for west longitude and south latitude.

Data Directory -- CS_altdr

In order to operate correctly, CS-MAP needs to access to several data files, the most important of which is the Coordinate System Dictionary. CS_altdr can be used to provide CS-MAP with the path to the directory it should look in for all of its data files. The single argument should contain the full path to the directory containing all of CS-MAP's supporting data files. You can instruct CS_altdr to use the value of the CS_MAP_DIR environmental variable by setting the argument to the NULL pointer. Should the argument point to the null string, CS-MAP will consider the current directory on the current drive as the directory in which to search for data file.

In all cases, CS_altdr will return a -1 if a valid Coordinate System Dictionary file could not be located in the indicated directory, for whatever reason.

Important Note: Failure to successfully call this function prior to calling any other CS-MAP function is likely to cause a fatal addressing error and the host application to crash.

Recover System Resources -- CS_recvr

Use this function to recover any and all system resources, such as file descriptors and heap memory, which CS-MAP may have allocated due to calls to CS_cnvrt, CS_scale, and CS_cnvrg functions.

Get Error Message Text -- CS_errmsg

CS_errmsg returns in the buffer supplied by the calling module a null terminated string which is suitable for reporting the last error condition detected by CS-MAP. This function should be used only after any CS-MAP function returns a negative status. It should be called prior to any other CS-MAP function call.

Compute Azimuth and Distance -- CS_llazdd

CS_llazdd is a utility function which is a part of the High Level Interface. Use this function to compute the azimuth from one geographic coordinate to another. It also returns the distance between the two points. These calculations take full account of the ellipsoid, and ellipsoid parameters are part of the calling sequence.

Unit Lookup -- CS_unitlu

Use CS_unitlu function to obtain the conversion constant for any of the unit systems understood by CS- MAP. CS_unitlu will return a zero if the supplied unit name is not valid.

Coordinate System Name Verification – CS_csIsValid

Use the CS_csIsValid function to determine if a coordinate system key name is that of an existing coordinate system defined in the currently active Coordinate System Dictionary without any side affects.

Datum Name Verification – CS_dtIsValid

Use the CS_dtIsValid function to determine if a datum key name is that of an existing datum defined in the currently active Datum Dictionary without any side affects.

Ellipsoid Name Verification – CS_elIsValid

Use the CS_elIsValid function to determine if a ellipsoid key name is that of an existing ellipsoid defined in the currently active Ellipsoid Dictionary without any side affects.

Low Level Functions

While the use of the High Level or the High Performance Interfaces described above is highly recommended, certain applications may require the use of the lower level functions. The sub-sections of this section organize these functions into three major groups:

  1. cartographic projection functions,
  2. geodetic datum shift functions, and
  3. general mapping/geodetic functions.

Cartographic Projections

For each projection supported, there exist eight, possibly nine, functions which comprise the full implementation of a projection. The brief description of these functions is given below. These descriptions will be important to those adding a new projection as well.

Those adding projections to the system only need to add an entry to the projection table cs_Prjtab. Doing so, you will need to add a pointer to the Definition Check and the Setup functions. To activate the proper parameter settings in the MFC dialog, you will also need to add the projection to the cs_PrjprmMap table. It is unlikely, but if your new projection uses a new type of parameter, you may need to add a new entry to the cs_Prjprm table. All of these tables are defined in the CSdataPJ.c module.

Definition Check Functions

For each projection there exists a function which verifies that a coordinate system definition adheres to the requirements of the projection. These functions are named in a manner similar to all other projection functions, but the distinguishing final character is Q. To prevent large scale duplication of code, each Q function checks only those elements of a coordinate system definition which are specific to the projection. The generalized check function, CS_cschk, checks those elements which are common to all coordinate systems (e.g. datum, ellipsoid, and units).

CS_csloc calls this function prior to calling the setup function, thus providing the setup function with data known to be valid for the given projection. This also implies that the pointer to the Q function for each projection must reside in the projection table.

Setup Function

The setup function for each projection has two basic responsibilities. It should perform all of the one- time calculations which can be performed independent of the specific coordinates which are to be converted and insert in the cs_Csprm_ structure pointers to the nine functions required for coordinate conversion. It is the setup function which is the primary repository for all knowledge about a specific projection. Therefore, it is one of the five elements required in the projection table other than the name of the projection. (C++ users would use the term constructor for the setup function. The design of CS- MAP predates the availability of C++ compilers on personal computers.)

This function is always supplied with a pointer to a cs_Csprm_ structure. This single argument supplies the setup function with the information required to perform the setup via the csdef and datum elements and the repository for the results of the setup by way of the ll2cs, cs2ll, cs_csscl, cs_cscnv, cs_cssck, cs_cssch, llchk, xychk, and prj_prmselements. Note that the prj_prms element of the cs_Csprm_ structure is a union of all the pre-processed projection parameter structures, thus providing a repository for setup parameters regardless of the projection in use.

Also note that in order to reduce the amount of duplicated code necessary to support the large number of projection variations now supported, the prj_code element of the cs_Csprm_structure must be filled in as well prior to calling the setup function.

Forward Functions

For each supported projection, there exists a forward function. It is responsible for converting latitudes and longitudes to the appropriate coordinates given a pointer to the projection parameters for the specific projection. A pointer to such function is inserted into the ll2cs element of the cs_Csprm_ structure by the setup function. These functions require that they be given a pointer to the projection parameters calculated by the setup function, e.g. a pointer to a element of the prj_prms union in the cs_Csprm_ structure.

Setup Function Forward Function Inverse Function Projection
CstrmerS CStrmerF CStrmerI Transverse Mercator
CSlmbrtS CSlmbrtF CSlmbrtI Lambert Conformal Conic
CsoblqmS CSoblqmF CSoblqmI Hotine Oblique Mercator
CSalberS CSalberF CSalberI Alber’s Equal Area Conic
CSmrcatS CSmrcatF CSmrcatI Mercator
CSmillrS CSmillrF CSmillrI Miller Cylindrical
CsazmedS CSazmedF CSazmedI Lambert Equidistant Azimuthal
CsazmeaS CSazmeaF CSazmeaI Lambert Equal Area Azimuthal
CSpstroS CSpstroF CSpstroI Polar Stereographic
CSostroS CSostroF CsostroI Oblique Stereographic
CSsstroS CSsstroF CSsstroI Snyder’s Oblique Stereographic
CsedcncS CSedcncF CSedcncI Equidistant Conic
CSsinusS CSsinusF CSsinusI Sinusoidal
CSplycnS CSplycnF CSplycnI American Polyconic
CsmodpcS CSmodpcF CSmodpcI Modified Polyconic
CSlmtanS CSlmtanF CSlmtanI Lambert Tangential
CSvdgrnS CSvdgrnF CSvdgrnI Van der Grinten
CSorthoS CSorthoF CSorthoI Orthographic
CsgnomcS CSgnomcF CSgnomcI Gnomonic
CSedcylS CSedcylF CSedcylI Equidistant Cylindrical
CScsiniS CScsiniF CScsiniI Cassini
CSmstroS CSmstroF CSmstroI Modified Stereographic
CSnzlndS CSnzlndF CSnzlndI New Zealand National Grid
CSrobinS CSrobinF CSrobinI Robinson
CSbonneS CSbonneF CSbonneI Bonne
CSnacylS CSnacylF CSnacylI Normal Aspect, Equal Area (Authalic) Cylindrical
CStacylS CStacylF CSnacylI Transverse Aspect, Equal Area (Authalic) Cylindrical
CsmolwdS CSmolwdF CSmolwdI Mollweide
CSekrt4S CSekrt4F CSekrt4I Eckert IV
CSekrt6S CSekrt6F CSekrt6I Eckert VII
CShmlsnS CShmlsnF CShmlsnI Goode Homolosine
CSbpcncS CSbpcncF CSbpcncI Bipolar Oblique Conformal Conic
CSswissS CSswissF CSswissI Oblique Cylindrical
CStrmrsS CStrmrsF CStrmrsI Transverse Mercator ala Snyder
CSkrovkS CSkrovkF CSkrovkI Krovak Oblique Conformal Conic
CSnerthS CSnerthF CSnerthI Non-georeferenced coordinate system
CSsys34S CSsys34F CSsys34I Danish System 34
CSunityS CSunityF CSunityI Unity (pseudo projection)

Inverse Functions

Similarly, there exists for each projection an inverse function, responsible for converting coordinate system coordinates to latitudes and longitudes. A pointer to such function is inserted into the cs2ll element of the cs_Csprm_ structure by the setup function, and these functions require a pointer to the setup parameters calculated by the setup function.

Scale Funcions

The Coordinate System Mapping Package also includes the ability to determine the grid scale factor of a coordinate system at any point. In many cases there is an analytical formula which produces the desired results. Since analytical formulas for the grid scale factor for all thirty eight projections could not be found, the grid scale factor is determined empirically for some projections using the latitude/longitude azimuth and distance calculation function CS_llazdd.

K Scale Function H Scale Function Convergence Function Projection
CStrmerK <none> CStrmerC Transverse Mercator
CSlmbrtK <none> CSlmbrtC Lambert Conformal Conic
CSoblqmK <none> CSoblqmC Hotine Oblique Mercator
CSalberK CSalberH CSalberC Alber's Equal Area Conic
CSmrcatK <none> CSmrcatC Mercator
CSmillrK CSmillrH CSmillrC Miller Cylindrical
CSazmedK CSazmedH CSazmedC Lambert Equidistant Azimuthal
CSazmeaK CSazmeaH CSazmeaC Lambert Equal Area Azimuthal
CSpstroK <none> CSpstroC Polar Stereographic
CSostroK <none> CSostroC Oblique Stereographic
CSsstroK <none> CSsstroC Snyder's Oblique Stereographic
CsedcncK CSedcncH CSedcncC Equidistant Conic
CSsinusK CSsinusH CSsinusC Sinusoidal
CSplycnK CSplycnH CSplycnC American Polyconic
CsmodpcK CSmodpcH CSmodpcC Modified Polyconic
CSlmtanK CSlmtanH CSlmtanC Lambert Tangential
CSvdgrnK CSvdgrnH CSvdgrnC Van der Grinten
CSorthoK CSorthoH CSorthoC Orthographic
CsgnomcK CSgnomcH CSgnomcC Gnomonic
CSedcylK CSedcylH CSedcylC Equidistant Cylindrical
CScsiniK CScsiniH CScsiniC Cassini
CSmstroK <none> CSmstroC Modified Stereographic
CSnzlndK <none> CSnzlndC New Zealand National Grid
CSrobinK CSrobinH CSrobinC Robinson
CsbonneK CSbonneH CSbonneC Bonne
CSnacylK CSnacylH CSnacylC Normal Aspect, Equal Area (Authalic) Cylindrical
CStacylK CStacylH CSnacylC Transverse Aspect, Equal Area (Authalic) Cylindrical
CsmolwdK CSmolwdH CSmolwdC Mollweide
CSekrt4K CSekrt4H CSekrt4C Eckert IV
CSekrt6K CSekrt6H CSekrt6C Eckert VII
CShmlsnK CShmlsnH CShmlsnC Goode Homolosine
CSbpcncK <none> CSbpcncC Bipolar Oblique Conformal Conic
CSswissK <none> CSswissC Swiss Oblique Cylindrical
CStrmrsK <none> CStrmrsC Transverse Mercator ala Snyder
CSkrovkK <none> CSkrovkC Krovak Oblique Conformal Conic
CSnerthK <none> CSnerthC Non-georeferenced coordinate system; scale is always 1.0, convergence is always zero.
CSsys34K <none> CSsys34C Danish System 34 (believed to be conformal, but this is not a sure thing)
CSunityK <none> CSunityC Unity

As mentioned above, for non-conformal projections, there are two scale factors, K and H. Therefore, for all thirty eight projections, there exists a K function, and for all non-conformal projections there exists an H function. A pointer to the appropriate function is inserted into the cs_Csprm_ structure by the setup function and, as you might expect, each of these functions requires a pointer to the projection parameters as calculated by the setup function.

Refer to the table above for the names of the K scale functions, i.e. grid scale factor along a parallel, and the H scale functions (i.e. scale along a meridian) for all thirty five projections currently supported. The name of the H function is given as for conformal projections. In these cases, the H scale factor is the same as the K scale factor.

Convergence Functions

For each projection there exists a function which computes the convergence angle for any point given a coordinate system definition. Refer to the table above for the names of the convergence angle functions for all thirty one projections currently supported. Again, analytical formulas for the convergence angle have not been located for all projections. Therefore, for some projections the convergence angle is determined empirically using the CS_llazdd function.

Geographic Limits Check Functions

For each projection, there exists a function which determines if a given geographic coordinate, great circle, or region is entirely within the mathematical domain of a coordinate system. These functions are named in a manner similar to all other projection functions, but the distinguishing final character is L.

For performance reasons, the actual conversion functions of CS-MAP check the coordinate data they are provided only to the extent necessary to prevent floating point exceptions. The geographic limits function of each projection can be used prior to a conversion to determine if a specific geographic coordinate, great circle defined by two geographic coordinates, or a closed region defined by four or more geographic coordinates is entirely within the mathematical domain of the projection. It is not unusual for applications to know the extents of the data set which is to be converted, and thus the extents only, not each individual coordinate, need be checked. This can provide significant performance advantages.

Cartographic Limits Check Functions

For each projection, there exists a function which determines if a given cartesian coordinate, line segment, or region is entirely within the mathematical domain of a coordinate system. These functions are named in a manner similar to all other projection functions, but the distinguishing final character is X.

For performance reasons, the actual conversion functions of CS-MAP check the coordinate data they are provided only to the extent necessary to prevent floating point exceptions. The cartesian limits function of each projection can be used prior to a conversion to determine if a specific cartesian coordinate, line defined by two cartesian coordinates, or a closed region defined by four or more cartesian coordinates are entirely within the mathematical domain of the projection. It is not unusual for applications to know the extents of the data set which is to be converted, and thus the extents only, not each individual coordinate, need be checked. This can provide significant performance advantages.

Geodetic Datum Shift Functions

The methods/functions associated with geodetic datum shifts are not nearly as well organized as those of cartographic projections. This is the result of many different governmental agencies solving the problem independently and relying on different data sets and calculation techniques. However, the basic functions involved in the most generalized techniques are described in the following sub- sections.

NADCON Emulation Functions

Four lower level functions can be used to perform NAD27 to NAD83 conversions. Use CSnadInit to initialize the system, and CSnadCls to release all resources absorbed by CS_nadinit.

Once CSnadInit has been called, CSnad27ToNad83 can be called to convert geographic coordinates from NAD27 to NAD83. CSnad83ToNad27 can be used to convert NAD83 to NAD27. Its that simple.

Datum Conversion Functions

The basic technique used for NAD83 and HARN described in previous sections is used for several other datums now defined worldwide. In the descriptions given below, you will see how this technique applies to AGD66; the Geodetic Datum of Australia of 1966. A similar pattern exists for the following datums and descriptions of these inidividual sets of functions will not be repeated in this section of the manual. In the future, there are likely to be a lot more of these.

Abbreviated Name Full Name
AGD66 Australian Geodetic Datum of 1966
AGD84 Australian Geodetic Datum of 1984
GDA94 Geocentric Datum of Australia, 1994
NZGD49 New Zealand Geodetic Datum of 1949
NZGD2K New Zealand Geocentric Datum of 2000
ATS77 Average Terrestrial System of 1977
CSRS Canadian Spatial Reference System

Four lower level functions can be used to convert coordinates from AGD66 to GDA94. Use CSagd66Init to initialize the system, and CSagd66Cls to release all resources absorbed by CSagd66Init.

Once CSagd66Init has been successfully called, CSagd66ToGda94 can be used to convert geographic coordinates from AGD66 to GDA94. Similarly, CSgda94ToAgd66 can be used to convert geographic coordinates from GDA94 to AGD66.

General Utility Functions

Supporting the generalized coordinate conversions described in the previous sections, are several functions which perform calculations which are quite useful to the GIS/GPS/Mapping application programmer. Several (but probably not all) of these are described in the following sub-sections.

GEOID Height Functions

This facility enables applications to calculate and use, as appropriate, the geoid height (or geoid separation if you prefer) at locations for which data is available. Record the data files available, and desired to be used, in the Geodetic Data Catalog file named GeoidHeight.gdc.

This implementation emulates C++, but is written in ANSI compliant C. The functions are named: CSnewGeoidHeight, CSdeleteGeoidHeight, and CScalcGeoidHeight; and are defined in the module named cs_GeoidHeight.c. Code specific to geoid height file formats can be found in modules named: CS_geoid96.c, CS_geoid99.c, CS_bynFile.c, and CS_osgm91.c. Low level applications may wish to access the functions defined in these modules directly.

Note there is no inverse function, as it is unnecessary. To obtain orthometric height at a given location, add the geoid height returned by CScalcGeoidHeight to the ellipsoid height. To calculate the ellipsoid height, subtract the geoid height returned by CScalcGeoidHeight from the orthometric height.

Geocentric Coordinates

Converting between geographic and geocentric coordinates has been inside of CS-MAP for many years. However, this capability has been hidden inside of the datum conversion functions. In this release, this capability is now explicitly available in functions named CS_llhToXyz and CS_xyzToLlh which are defined in the CS_dtCalc.c module.

Note that each of these functions requires the definition of the ellipsoid in use, expressed as two separate double arguments: equatorial radius and eccentricity squared.

MGRS Implementation

Release 11.01 includes a series of new functions that provide the ability to generate MGRS designations from geographic coordinates, and vice versa. This implementation consists of 6 functions designed for application programmer use, and two supporting functions. The support functions may be of interest as they provide the ability to convert between geographic and UTM coordinates/zone number where the rather strange stuff which goes on in northern Europe (i.e. southern Norway and the Svaldberg Islands) is appropriately accounted for.

While written in 'C' to be consistent with the rest of CS-MAP, the implementation of the MGRS capability has a definite C++ structure to it. That is, there exists a structure definition, three constructors, a destructor, two public functions and two private functions (i.e. the supporting functions).

MGRS Constructors

Construction of a cs_Mgrs_ object (i.e. allocation and initialization of a a cs_Mgrs_ structure) requires knowledge of the ellipsoid definition to be used and if the alternative lettering sequence (i.e. Bessel) is to be used. Thus, the three constructors simply provide three different ways of specifying the ellipsoid which is to be used:

 struct cs_Mgrs_ *CSnewMgrs (double e_rad,double e_sq,short bessel);
 struct cs_Mgrs_ *CSnewMgrsE (const char *elKeyName,short bessel);
 struct cs_Mgrs_ *CSnewMgrsD (const char *dtKeyName,short bessel);

where the elKeyname argument can be used to specify the ellipsoid by key name. Alternatively, application programmers can specify a datum name (the dtKeyName argument) and the calculations will be based on the ellipsoid upon which the datum is referenced. Of course, the application programmer can use the e_rad and e_sq version to specify the equatorial radius and square of eccentricity directly. In all cases, the bessel argument is zero to indicate the normal lettering scheme. +1 to indicate the alternative lettering scheme.

All constructors return the null pointer in the event of an error. Use CS_errmsg to obtain a string that describes the nature of the error.

MGRS Destructor

Use CSdeleteMgrs to delete a cs_Mgrs_ object constructed by one of the constructors. Currently, a call of CS_free will accomplish the same thing, but maybe not in the future.

void CSdeleteMgsr (struct cs_Mgrs_ * __This);

Like it's C++ equivalent, this function is smart enough not to attempt to free a null pointer.

MGRS Public Functions

Naturally enough, two conversion functions exists. Given a properly initialized cs_Mgrs_ object (i.e. structure) and a geographic coordinate, CScalcMgrsFromLl will return the appropriate MGRS designation. CScalcLlFromMgrs reverses the process. In both cases, a return value of zero indicates success, non-zero indicates failure. Use CS_errmsg to obtain a description of the cause of failure.

int CScalcMgrsFromLl (struct cs_Mgrs_ *__This, char *result, int size, double latLng [2], int prec);
int CScalcLlFromMgrs (struct cs_Mgrs_ *__This,double latLng [2], Const char *mgrsString);

In these prototypes, the first argument is a pointer to an initialized cs_Mgrs_ object obtained from one of the constructors described above. The latLng argument refers to an array of at least two doubles which contain the longitude and latitude (in that order) in degrees. The prec argument indicates the number of digits to be included in the resulting MGRS designation. Valid values range from 0 to 5. Note, that a value of 5 indicates that 5 easting, and 5 northing digits will be included in the resulting string. Of course, CScalcMgrsFromLl will never write more than size characters to the result array, and (assuming size is greater than zero) will cause result to be null terminated.

MGRS Private Functions

Two "private" functions, i.e. internal support functions, exist which convert geographic coordinates to UTM/UPS coordinates and zone number. These functions are aware of the missing/widened zones in the northern Europe region. They are also capable of switching between UTM and UPS (Universal Polar Stereographic) coordinates as appropriate. These functions use a utmZone variable which carries the UTM zone number where: 1) northern UTM zones are positive numbers between 1 and 60 inclusive, 2) southern UTM zones are negative numbers between –1 and –60 inclusive, 3) +61 refers to the North Pole UPS zone, 4) –61 refers to the South Pole UPS Zone,, and 5) the value zero is invalid and used to indicate an error condition.

int CScalcUtmUps (struct cs_Mgrs_ *__This,double utmUps [2], const double latLng [2]);
int CScalcLatLng (struct cs_Mgrs_ *__This,double latLng [2], const double utmUps [2], int utmZone);

Given a geographic coordinate, CScalcUtmUps calculates the appropriate UTM/UPS coordinates and returns the appropriate utmZone value. Given a UTM/UPS coordinate and utmZone value, CScalcLatLng returns the appropriate geographic coordinate. CScalcLatLng returns zero on success, non-zero on failure. In all cases, the calculation is based on the ellipsoid used to construct the cs_Mgrs_ argument to the function.

Forward/Inverse Functions

The term Forward/Inverse is a common way of referring to what is also known as the basic geodesy problem. That is, given a geodetic latitude/longitude, calculate the a new position given an azimuth and distance. This may sound pretty simple, but the calculation must be carried out on the ellipsoid. Thus the calculation is rather complex.

Forward refers to the calculation of a new geodetic position given an azimuth and a distance. Inverse refers to the calculation of an azimuth and distance given two geodetic positions.

CS_llazdd performs the forward calculation, and CS_azddll performs the inverse calculation.

Error Handling

Having it origins in the 'C' language, error reporting in the CS-MAP library is implemented using the return status methodology. That is, functions which can detect abnormal situations will return an integer status value to indicate the success of the operation intended, Status returns are of two types.

With the exceptions described below, all CS-MAP functions which can detect an abnormal situation will return a zero for success. A negative value will be returned for a failure which is considered fatal, and a non-zero positive value is returned for a warning or providing information about a remarkable condition.

While fatal errors can and do occur during the setup phase of a conversion/transformation combination, it is an important part of the design of CS-MAP that fatal errors cannot occur with conversion and transformation functions. Thus, any function involved in the creation and/or initialization of a conversion or transformation can be expected to return a negative status value. Functions which actually perform the conversion and/or transformation calculations can be expected to never return a negative status.

In the event of a negative status return, applications should immediately call the CS_errmsg function which will return an (8 bit character, English only) textual description of the cause of the problem. This description will often include, when appropriate, contextual information such as file names etc.

Status return values from calculation functions are always positive and non-zero values usually indicate that the coordinate to be converted is:

In any case, the calculation function will indeed return a rational value. In many cases, this rational value will be produced by what is called a fallback technique.

In the experience of the developers of CS-MAP, once a conversion/transformation operation has been successfully constructed (i.e. setup), applications should at most simply count the number of non-zero positive status values returned by the calculation functions and report this number to the user (assuming it is non-zero) upon completion of the conversion. That is, a non-zero status return from any and all calculation functions should be considered as information only. Otherwise, your application will be bogged down and end user's can easily come to the conclusion that your application has crashed.

Also note, that to keep performance levels high, a non-zero positive status return value does not cause the generation of a descriptive error message and calling CS_errmsg after encountering a positive status return will produce misleading information, is anything at all.

Exception

There are several functions in CS-MAP whose function in life is to enumerate a list of entries in internal lists or dictionaries. These functions tend to return a positive 1 value to indicate success. A zero is returned to indicate that the end of the sequence has been encounters. (Of course, a negative return value indicates a fatal error of some sort. This convention was chosen so as to make obtaining such a list or enumeration rather easy to code in a robust manner:

int index;
char elpName [cs_KEEN_DEC};
.
.
.
index = 0;
while (CS_elEnum (index++,eleVate) > 0)
{
  /* Do something with this name */
  .
  .
  .
}

Data Structures

Discussions which follow refer to the primary data structures of CS-MAP. Twelve such data structures are described. These structure provide the basis for the operation of the Coordinate System Mapping Package. All structure definitions are found in the cs_map.h header file.

Ellipsoid Definition Structure

The Ellipsoid Definition structure, cs_Eldef_, carries the two principal data elements (among others) which define an ellipsoid for our purposes. These are the equatorial radius and the eccentricity of the ellipsoid. Among the other items contained in the structure is a key name, which is used to distinguish one ellipsoid definition from another.

Datum Definition Structure

The Datum Definition structure, cs_Dtdef_, carries the eight principal data elements (among others) which define a datum for our purposes. These are the key name of the ellipsoid definition upon which the datum is based, the X, Y, and Z components of the vector from the geocenter of the datum being defined to the geocenter of the WGS84 ellipsoid, the three rotation components of the transformation, and the scale component of the transformation. Among the other elements contained in this structure is a datum key name which is used to distinguish one datum definition from another.

Datum Composite Structure

The Datum Composite structure, cs_Datum_, carries the contents of both the Datum Definition structure and the Ellipsoid Definition structure in an composite form. This structure is never written to disk and is used internally as a programming convenience.

Coordinate System Definition Structure

The Coordinate System Definition structure, cs_Csdef_, carries all the elements required to define a coordinate system. Twenty four of these elements are referred to as projection parameters as their use depends upon the projection in use (which is one of the other data elements). Therefore, it is difficult to describe their use without delving into the specifics of each projection.

For our purposes here, let it be said that the cs_Csdef_ structure is capable of carrying the definition of any coordinate system based on any one of the thirty eight projections supported by CS-MAP and (hopefully) any others which may be added in the future. This includes the parameters specific to the projection, the projection origin, the coordinate system units, the coordinate system scale, the false easting, the false northing, etc.

Preprocessed Projection Structures

There exists one structure for each of the thirty eight projections which carry the definition of a coordinate system based on the respective projection in a preprocessed form. That is, once the specific projection parameters applicable to a specific coordinate system are established, there are many calculations which can be performed independent of the specific coordinates to be converted. The results of these calculations are stored in these structures. The thirty five structure names are shown in Table III. It is the content of these structures which actually control the conversion of cartesian coordinates to and from latitudes and longitudes.

Coordinate System Parameter Structure

The Coordinate System Parameter Structure, cs_Csprm_, is used to carry a complete definition of a coordinate system and is the single structure used throughout the development of a coordinate conversion. It contains a copy of the cs_Csdef_ structure of the coordinate system being used, a copy of the cs_Datum_ structure which the coordinate system definition references, and the coordinate system in its pre-processed form as a union of the thirty eight pre-processed parameter structures described above. It also contains pointers to the functions which are capable of performing the forward and inverse coordinate conversions. Pointers are also included for grid scale and convergence angle functions. cs_Csprm_ also includes information about the specific projection in use, as well as the limits of the coordinate system, both in cartesian and geographic form. While CS-MAP is designed such that the application should not need to know anything about the projection, there are instances (such as our own test program) where some knowledge of the projection in use, or its specific features, is helpful.

As a result, this single structure represents a complete definition of a coordinate system which can be easily passed around by pointer. Through the use of pointers to the appropriate coordinate conversion functions contain in this structure, modules which receive a pointer to this structure do not ever have to know exactly which projection is in use in order to perform coordinate conversions.

Projection Name Table Structure

The Projection Name Table Structure, cs_Prjtab_, is used solely to create a table of the projections known to the system. It primarily associates a name with a projection code and a setup function. To add new projections to the system, one need only create an entry in this table and reference the code which, of course, must also be written. You can also add additional names for existing projections by simply making additions to this table.

More importantly, to remove a projection from the system (in order to reduce the size of the text space within an executable, for example), one need simply remove (or comment out) the projection's entry in this table.

In developing a coordinate system parameter structure, the name of the projection is extracted from the coordinate system definition. This name is located in the projection table. The projection setup function associated with the selected named entry is then called and given a pointer to the union of pre- processed structures. The setup function initializes the union as if it were the pre-processed structure associated with the projection under construction. Of course, CS-MAP does all of this, mostly in the function named CS_csloc.

The Projection Name Table includes a fully descriptive name of each projection as well as a bit map of the features of the projection. Refer to CSdataPJ.

Datum Shift Definition Structure

The Datum Shift Definition structure, cs_Dtcprm_, carries all of the information necessary to perform a datum shift on geographic coordinates (i.e. latitude and longitude). The information contained in this structure includes the definition of the source and target datums and a road map of the various conversions necessary to get, in the most accurate form, from the source datum to the target datum. This structure is allocated upon request given the definitions of the source and target coordinate systems. Once properly allocated, a pointer to this structure is all that the datum shift function needs in order to calculate datum shifts.

Thus, applications do not need to have any knowledge of what datums or how many different conversions are necessary to get from one datum to the next. In fact, quite often the conversion is the null conversion which implies that the source latitude and longitude are simply copied to the target array. Again, in this case, the application has no need to know of this situation.

The above is possible only because CS-MAP (to a large extent) requires that all datum definitions define how to convert a specific datum to/from WGS84. Thus, by "going through" WGS84 CS-MAP can convert any coordinate system/datum to any other. There are certain exceptions to this basic theme.

The Data Dictionaries

The Coordinate System Mapping Package includes the definition of more than 1,000 commonly used coordinate systems, more than 130 datum definitions, and 37 commonly referenced ellipsoids. These definitions are carried in the Coordinate System Dictionary (a file usually named Coordsys), the Datum Dictionary (a file usually named Datums), and the Ellipsoid Dictionary (a file usually named Elipsoid) respectively. These files are normally expected to reside in the C:\MAPPING directory (/usr/MAPPING under UNIX). The location of these files can be modified to suit your requirements at compile time (see CSdata) or at run time (see CS_altdr). The names of these files can be changed either at run time (see CS_csfnm, CS_dtfnm, and CS_elfnm) or compile time (see cs_map.h).

The Coordinate System Dictionary

The Coordinate System Dictionary is a fixed length record file of cs_Csdef_ structures, maintained in sorted order by the key_nm element, i.e. the coordinate system key name. Entries in this file are located through the use of the binary search technique, therefore it is important that this file remain in sorted order. The file has a magic number in the first four bytes. This is a sequence of bytes which identify the file as being a Coordinate System Dictionary file and is defined by the cs_CSDEF_MAGIC manifest constant in cs_map.h. This value is checked each time the file is opened to make sure that the file is indeed a Coordinate System Dictionary and that it has not been seriously corrupted. The specific value of the magic number is changed each time the format of the cs_Csdef_ structure is changed.

Functions are provided to access and maintain this file as a Coordinate System Dictionary. CS_csopn will open the file, verify its magic number, and return a file descriptor (or handle). CS_csrd and CS_cswr will perform sequential reads from and writes to a file of this type, handling encryption appropriately. CS_cscmp compares records in the file for sorting and searching purposes. CS_csdef will extract a particular record from the dictionary for you. CS_csupd will update an existing entry or add a new entry to the Coordinate System Dictionary, assuring that the file remains in sorted order. Finally, CS_csdel can be used to delete a record from the dictionary.

Coordinate system definitions are verified for validity before they are written to the Coordinate System Dictionary through the use of the CS_cschk function. CS_csloc (described below) also checks each definition before it is actually used to create the active form of a coordinate system.

The Datum Dictionary

The Datum Dictionary is a fixed length record file of cs_Dtdef_ structures, maintained in sorted order by the key_nm element, i.e. the datum key name. Entries in this file are located through the use of the binary search technique, therefore it is important that this file remain in sorted order. The file has a magic number in the first four bytes of the file and is defined by the cs_DTDEF_MAGIC manifest constant in cs_map.h. This is a sequence of bytes which identify the file as being a Datum Dictionary file. This value is checked each time the file is opened to make sure that the file is indeed a Datum Dictionary and that it has not been seriously corrupted. The specific value of the magic number is changed each time the format of the cs_Dtdef_ structure is changed.

Functions are provided to access and maintain this file as a Datum Dictionary. CS_dtopn will open the file, verify its magic number, and return a file descriptor (or handle). CS_dtrd and CS_dtwr will perform sequential reads from and writes to a file of this type, handling encryption appropriately. CS_dtcmp compares Datum Dictionary entries for sorting and searching purposes. CS_dtdef will extract a particular record from the dictionary for you. CS_dtupd will update an existing entry or add a new entry to the Datum Dictionary, assuring that the file remains in sorted order. Finally, CS_dtdel can be used to delete a record from the dictionary.

The Ellipsoid Dictionary

The Ellipsoid Dictionary is a fixed length record file of cs_Eldef_ structures, maintained in sorted order by the key_nm element, i.e. the ellipsoid name. Entries in this file are located through the use of the binary search technique, therefore it is important that this file remain in sorted order. The file has a magic number in the first four bytes of the file and is defined by the cs_ELDEF_MAGIC manifest constant in cs_map.h. This is a sequence of bytes which identify the file as being a Ellipsoid Dictionary file. This value is checked each time the file is opened to make sure that the file is indeed an Ellipsoid Dictionary and that it has not been seriously corrupted. The specific value of the magic number is changed each time the format of the cs_Eldef_ structure is changed.

Functions are provided to access and maintain this file as a Ellipsoid Dictionary. CS_elopn will open the file, verify its magic number, and return a file descriptor (or handle). CS_elrd and CS_elwr will perform sequential reads from and writes to a file of this type, handling encryption appropriately. CS_elcmp compares Ellipsoid Dictionary entries for sorting and searching purposes. CS_eldef will extract a particular record from the dictionary for you. CS_elupd will update an existing entry or add a new entry to the Ellipsoid Dictionary, assuring that the file remains in sorted order. Finally, CS_eldel can be used to delete a record from the dictionary.

Dictionary Encryption

The definitions of coordinate systems, datums, and ellipsoids can represent a significant investment on the part of the application developer. Under certain circumstances, a demonstration disk for example, the application developer may not wish to provide this information in a form from which this valuable data can be easily extracted. As a result, CS-MAP fully supports a means by which dictionary data can be encrypted. All CS-MAP functions will work equally as well with encrypted dictionaries as with normal versions. Dictionary compilers normally produce dictionaries in encrypted form. An option is provided to produce unencrypted dictionaries.

Dictionary Definition Protection

Dictionary entries are normally protected. That is, changes to coordinate system, datum, and ellipsoid definitions are controlled. This reduces technical support calls significantly. Application programmers can control the extent of protection, or turn it off altogether. How this system works is described below.

In normal operation, CS-MAP will not allow end users to change definitions distributed with the application. More specifically, definitions created by the Dictionary Compiler are marked as to be protected. End users can, and often do, create new coordinate system definitions. Therefore, rather than change a coordinate system as distributed with the application, users would typically create a new definition which is modified as necessary to achieve the desired results.

Definitions created by end users, and which remain unchanged for 60 days, are also protected. This is done under the assumption that a definition which remains unchanged for 60 days will have been used and judged satisfactory, and therefore should be preserved as a means of recording the actual definition used to produce the results.

Finally, CS-MAP normally requires that the key names for all user defined definitions contain the colon character. By adopting this convention, application updates can include coordinate system updates without the possibility of the update overwriting a valid and valuable user defined definition. (This, of course, assumes that the distribution will never contain a coordinate system definition with a key name containing a colon character.)

Application programmers can control to what degree the protection system is active by simply setting the value of either, or both, of two global variables, either at compile time (see CSdata.c) or at run time.

char cs_Unique; In the CS-MAP distribution, the value of this global variable is set to the colon. Set the value of this variable to the null character to turn the user definition key name protection feature described above off. You can select a character other than the colon by simply setting this variable to the desired character.

short cs_Protect; Use this variable to control the protect applied to dictionary definitions. A positive, non-zero value is the number of days associated with the user defined definition protection described above. For example, in the CS-MAP distribution, this value is set to 60, indicating that after a user defined definition remains unchanged for 60 days, it automatically becomes protected. Set cs_Protect to zero to maintain distribution coordinate system protection, but disable all user defined definition protection. Set cs_Protect to a negative value to disable all dictionary definition protection.

Programmer Note: Dictionary definitions include a short which controls the protection of the definition. If this value is set to zero, the dictionary entry is permanently unprotected. If this value is set to one, the entry is permanently protected. Otherwise, this value is set to the date at which the definition was last modified expressed as the number of days since January 1, 1990. Thus, changing the value of cs_Protect will change the protection of user defined definitions in a dynamic manner

Byte Ordering

All three dictionary files described in this section contain data in binary form, thus byte ordering becomes a serious issue when using CS-MAP on different platforms. Beginning with Release 6.0 of CS-MAP, dictionaries are expected to be in little endian byte order regardless of the platform in use. A byte swapping function, CS_bswap, is called immediately after each read from any of these dictionaries, and immediately before the write of any data to any of the dictionaries. CS_bswap is programmed to automatically determine if byte swapping is required based on a compile time constant. Thus, a single copy of these dictionaries can be distributed for use on all platforms.

The term "all platforms" is perhaps misleading. CS_bswap will only swap between little endian and big endian byte orders. The rather odd byte orderings of some older DEC machines is not supported at the current time.

The automatic byte ordering feature is easy to disable if so desired. Refer to CS_bswap for more information.

The automatic byte ordering feature also applies to all other binary data files upon which CS-MAP relies. That is, automatic byte swapping is applied to all reads from NADCON database files, Multiple Regression data files, Canadian National Transformation files, and all HPGN database files. The choice of using little endian byte ordering was natural as these files are generally distributed by their sources in this form.

Dictionary Compiler

ASCII versions of the three dictionaries are provided in the distribution. The names of these files are COORDSYS.ASC, DATUMS.ASC, and ELIPSOID.ASC. Binary versions of the dictionary files can be produced by using the dictionary compiler program CS_COMP. This enables the definition files to be committed to version control procedures and the dictionaries remade as part of your product manufacturing process.

Originally, the ASCII files and the compilers were provided as a means of overcoming the byte order problem on different platforms. Now that CS-MAP has been modified to process little endian files on all platforms, this purpose is now obsolete. The version control purpose of these files remains valid.

Multiple Regression Datum Transformation Files

The compiler referred to above will also compile a fourth ASCII source file named MREG.ASC which is also supplied in the distribution. MREG.ASC contains in an ASCII, version controllable form, the definition of all multiple regression transformations known to the system. Compiling this file produces the .MRT files which CS-MAP accesses, as necessary, when performing datum conversions. Your application distribution should include the .MRT files produced by compiling the MREG.ASC file.

Default Datums, Ellipsoids, and Units

CS-MAP supports the concept of default datums, ellipsoids, and/or units. Defaults represent a convenient way to switch a coordinate system definition between different datums, ellipsoids, and/or units without having to change the Coordinate System Dictionary. How this feature applies to datums is described first; and this description is then extended to ellipsoids and units.

A datum reference in a coordinate system definition may be marked as "defaultable" by enclosing the name in square brackets. The actual datum name provided must be a valid datum reference as this reference will be used whenever the default feature is not active. This also implies that the default feature need not be active for the coordinate system definition to be valid and usable.

Upon activation of a coordinate system, regardless of the interface used, CS-MAP will check to see if the datum specified is "defaultable". If so, it examines the current default datum setting. If a valid default datum has been specified, the "defaultable" datum reference is replaced by the current default setting and coordinate system setup continues. If there is no current default setting, the "defaultable" datum is used as is. Thus, in the absence of a default specification, the coordinate system definition operates as defined. Whenever a default replacement is performed, the replaced datum name in the cs_Csdef_ element of the cs_Csprm_ structure will be enclosed in parenthesis to indicate that a default replacement has occurred.

Use the CS_dtdflt function to define a default datum. It will return the status and the name of any previous default. It will not allow an invalid default setting to be made. Calling CS_dtdflt with the NULL pointer as its argument can be used to determine if the datum default feature is active and, if so, what the current default setting is. Call CS_dtdflt with a pointer to the null string to disable the datum default feature. Until CS_dtdflt is called with a valid datum reference, the datum default feature remains disabled.

Cartographically referenced coordinate systems, and datum definitions, can contain "defaultable" ellipsoid references. Use CS_eldflt to enable and disable the "defaultable" ellipsoid feature.

Coordinate system unit specifications can also be "defaultable". Separate default values are maintained for linear and angular units. Use CS_ludflt to control the state of linear unit defaults, and CS_audflt to control the state of angular unit defaults.

You can completely ignore this concept of default datums, ellipsoids, and units by simply not calling (or even referencing) any of the default functions mentioned above. Default processing is off by default, and by never calling any of these functions, it never gets turned on. This is how most users deal with the default feature.

High Performance Interface

The High Performance Interface to the Coordinate System Mapping Package consists of thirteen functions. By virtue of the data structures described above, use of these functions is independent of the actual coordinate systems, projections, or datums in use. This represents the most efficient means to use CS-MAP to convert coordinates from one coordinate system to another. It also insulates your applications from most changes which could be made to the CS-MAP in the future. This basic API has not changed since 1992. This interface requires the use of structure pointers and, therefore, may not be appropriate for use with some languages. Therefore, use this interface wherever high performance is a top priority and the application is written in a language which can handle pointers such as C, C++, or Pascal.

These functions make use of the Coordinate System Dictionary, the Datum Dictionary, the Ellipsoid Dictionary, and the functions which access them. This need not be of concern to the application programmer using the High Performance Interface as it all goes on "behind the scenes".

In this section, our intent is to associate function names with capabilities and features.

The Functions

The thirteen functions which comprise the High Performance Interface are CS_csloc, CS_dtcsu, CS_ll2cs, CS_dtcvt, CS_cs2ll, CS_dtcls, CS_csscl, CS_cnvrg, CS_cssch, CS_cssck, CS_llchk, CS_xychk, and CS_free. The typical coordinate conversion application uses only seven of these function.

Refer to the major sections following this to see how the use of these functions is combined to produced generalized coordinate conversion capabilities.

Coordinate System Locate

Given the key name of a coordinate system defined in the Coordinate System Dictionary, CS_csloc returns a pointer to a fully initialized cs_Csprm_ structure. This initialization includes all of the "one- time" calculations and the establishment of pointers to the appropriate coordinate conversion functions. This structure is malloc'ed from dynamic memory. Therefore, you may have several such definitions active at any given time. Also, you should release these structures when your application no longer has need of them; use CS_free.

Datum Conversion Setup

Given pointers to the both the source and target coordinate systems as returned by CS_csloc, CS_dtcsu returns a pointer to a malloc'ed cs_Dtcprm_ structure which is a required argument to the CS_dtcvt function which actually calculates datum shifts. As its name implies, CS_dtcsu "sets up" a datum conversion by allocating and initializing a cs_Dtcprm_ structure. Since datum conversions often require the use of file descriptors, grid cell caches, and the like, do not use free or CS_free to release the cs_Dtcprm_ structure returned by CS_dtcsu. The sixth function of this interface, CS_dtcls must be used instead to prevent memory and file descriptor leaks in your application. Note, when appropriate, CS_dtcsu returns a pointer to a null datum conversion; a conversion which does nothing successfully and rapidly.

Coordinate System to Lat/Long Conversion

Given a pointer to an initialized cs_Csprm_ structure which describes the coordinate system in use, the CS_cs2ll function will convert a cartesian coordinate to geographic form in terms of latitude and longitude in internal form. The resulting geographic coordinate will be based on the same datum as the coordinate system defined in the provided cs_Csprm_ structure.

The conversion function pointers inserted into the cs_Csprm_ structure by CS_csloc are used to select the proper code for the conversion. The application has no need to know what projection is in use or, for that matter, anything else about the coordinate system in use

Datum Conversion

Given a pointer to an initialized datum conversion parameter structure, cs_Dtcprm_, as returned by CS_dtcsu, the CS_dtcvt function will convert the supplied geographic coordinates from the source datum to the target datum.

Lat/Long to Coordinate System Conversion

Given a pointer to an initialized cs_Csprm_ structure, the CS_ll2cs function will convert a geographic coordinate specified in terms of latitude and longitude (in degrees) to the coordinates of the coordinate system defined by the cs_Csprm_ structure.

The conversion function pointers inserted into the cs_Csprm_ structure by CS_csloc are used to select the proper code for the conversion. The application has no need to know what projection is in use or, for that matter, anything else about the coordinate system in use.

Close Datum Conversion

Given a pointer to an initialized datum conversion parameter structure, as returned by the CS_dtcsu function, CS_dtcls will release all system resources allocated for the specific datum conversion. Note, that since several datum conversions may be initialized and operative at any given time, CS_dtcls does not necessarily release all resources associated with certain datum transformations until such time as the last datum conversion parameter block referencing such resources is closed.

Grid Scale Factor

Given a pointer to an initialized cs_Csprm_ structure as returned by the CS_csloc function, CS_csscl will return the grid scale factor for the coordinate system at a location indicated by a geographic coordinate. It is important to note that the concept of Grid Scale as a single number applies only to coordinate systems based on conformal projections such as the Transverse Mercator, Lambert Conformal Conic, and the Oblique Mercator. Other projections, such as equal area projections, will have two such scale factors. In the case of equidistant projections, there are two such scale factors but one of them will usually be one. In the case on non-conformal projections, CS_csscl will return what the designers of CS-MAP consider the more interesting of the two scale factors for the specific projection involved.

Scale Along a Parallel

The two scale factors mentioned above consist of the scale along a parallel, often referred to as 'k', and the scale along a meridian, referred to as 'h'. Given a pointer to an initialized cs_Csprm_ structure as returned by CS_csloc, CS_cssck will always return the scale factor along a parallel at the location provided.

The nomenclature referred to here is that used by J. P. Snyder in Map Projections - A Working Manual. Other authors use different symbology. In his later work, Map Projections - A Reference Manual, Snyder uses the more common notation. CS-MAP, whose origins date back to 1987, uses the original Snyder notation.

Scale Along a Meridian

Given a pointer to an initialized cs_Csprm_ structure, CS_cssch returns the scale along a meridian, often referred to as 'h', at the location given by its second argument which must be a geographic coordinate.

Convergence Angle

Given a pointer to an initialized cs_Csprm_ structure as returned by CS_csloc, CS_cnvrg returns the convergence angle of the coordinate system, at the location indicated by the second argument which must be a geographic coordinate. The return value is in degrees; positive is east of north.

Check Limits, Geographic

Given a pointer to an initialized cs_Csprm_ structure as returned by CS_csloc, CS_llchk will determine if all coordinates in the list provided are within the mathematical domain of the coordinate system and/or with the useful range of the coordinate system. In the case where the provided list contains two or more points, the determination applies to each coordinate on each great circle arc formed by consecutive geographic coordinates. In those cases where the provided coordinate list consists of four or more geographic coordinates which define a closed region, the determination applies to all coordinates enclosed within the region, or which reside the provided boundary.

Check Limits, Cartesian

Given a pointer to an initialized cs_Csprm_ structure as returned by CS_csloc, CS_xychk will determine if all coordinates in the list provided are within the mathematical domain of the coordinate system and/or with the useful range of the coordinate system. In the case where the provided list contains two or more points, the determination applies to each coordinate on each line segment formed by consecutive cartesian coordinates. In those cases where the provided coordinate list consists of four or more cartesian coordinates which define a closed region, the determination applies to all coordinates enclosed within the region, or which reside on the provided boundary.

Free Coordinate System Parameters

Use CS_free to free memory allocated by the any CS-MAP functions. This function is to be used, for example, to free the coordinate system parameter block returned by CS_csloc. It is important that CS_free be used as in certain environments (a Windows DLL for example), the heap used by the library is not necessarily the same as the heap used by the application. Thus, if CS-MAP allocated the memory, it is best if CS-MAP releases it also.

Coordinate System to Coordinate System

In order to convert from one coordinate system to another, one simply obtains, from the CS_csloc function, a definition of the two coordinate systems of concern. The inverse function, CS_cs2ll, is used to convert the source coordinates to latitude and longitude and the forward function, CS_ll2cs, is used to convert to the target coordinate system. The sample code segment shown is, for example, all the code necessary to convert a file of NAD27 based UTM Zone 13 (UTM27-13) coordinates to NAD27 based Colorado State Plane, Southern Zone (CO-S). To change the conversion to use other coordinate systems, only the names provided to the CS_csloc function need be changed. Of course, these strings are rarely hard coded as has been done in this example.

int input, output;
double xy [2], ll [2];
struct cs_Csprm_ *utm, *co_s;
utm = CS_csloc ("UTM27-13");
co_s = CS_csloc ("CO-S");
while (read (input, xy, sizeof (xy)) != 0)
{
   CS_cs2ll (utm,ll,xy);
   CS_ll2cs (co_s,xy,ll);
   write (output,xy,sizeof (xy));
}
CS_free (utm);
CS_free (co_s);

The LL Coordinate System

Many products will use the above scheme to provide the ability to convert from any coordinate system to any another. This scheme is completely general, supporting any combination of coordinate systems. Sometimes, however, it is desirable to convert from or to geographic coordinates. The LL coordinate system and the Unity projection accommodate this within the general scheme of things described above. That is, the LL coordinate system is simply a coordinate system in which the coordinates are latitudes and longitudes, and the Unity projection is simply a set of conversion functions which do little other than possible units and prime meridian conversion.

Therefore, supplying a coordinate system name of LL, for example, for either the input or output coordinate system will produce the desired results without the application program having to know about this specific situation. (Please note that LL is a cartographically referenced coordinate system. Coordinate systems LL27 and LL83 are usually used in practice.)

Latitude and longitude coordinates in different units or referenced to a prime meridian other than Greenwich are possible by defining different LL type coordinate systems. These definitions, all based on the Unity pseudo-projection, can include a units specification and a specification of a prime meridian other than zero (i.e. Greenwich).

Multiple Conversions

Please note, that since coordinate system definitions (as returned by CS_csloc) reside in "heap" memory, there is no practical limit as to the number of definitions which can be active at any given time. Therefore, using the three functions described above, several different coordinate conversions can be active at the same time.

Adding Datum Conversions to the Interface

Datum conversions can be added to the basic scheme described above by adding calls to the datum conversion functions. Refer to the code given below for an example, paying special attention to the emphasized code. Once the two coordinate system definitions have been initialized, they are passed to CS_dtcsu. By examining both the source and target coordinate system definitions, CS_dtcsu is able to determine which, if any, datum transformation techniques need to be applied to accomplish the desired conversion. CS_dtcsu will select one or more datum conversions as necessary to accomplish the desired conversion. For example, to convert from NAD27 to WGS72, three conversions are actually setup:

  1. from NAD27 to NAD83 via the NADCON technique
  2. NAD83 to WGS84 (which is currently a null conversion), and finally
  3. WGS84 to WGS72 using a hard coded formula.

CS_dtcsu assures that all preparations necessary for these conversions are initialized, and saves the results in the cs_Dtcprm_ structure to which it returns a pointer.

In the actual coordinate conversion loop, CS_dtcvt is called for each coordinate once its geographic form has been obtained from CS_cs2ll. Note that if CS_dtcsu determined that no datum conversion was required, the information contained in the cs_Dtcprm_ structure which it returns causes CS_dtcvt to simply copy the source geographic coordinates to the target array. Finally, when the conversion process is complete, CS_dtcls is used to release any system resources which were allocated for the datum conversion and which are no longer needed.

int input, output;
double xy [2], ll [2];
struct cs_Csprm_ *utm, *co83_s;
struct cs_Dtcprm_ *dtc_ptr;
.
.
utm = CS_csloc ("UTM27-13");
co83_s = CS_csloc ("CO83-S");
dtc_prm = CS_dtcsu (utm,co83_s,dat_err,blk_err);

while (read (input,xy,sizeof (xy)) != 0)
{
   CS_cs2ll (utm,ll,xy);
   CS_dtcvt (dtc_prm,ll,ll);
   CS_ll2cs (co83_s,xy,ll);
   write (output,xy,sizeof (xy));
}

CS_dtcls (dtc_prm);
CS_free (utm);
CS_free (co_s);

Geodetically Referenced Coordinate Systems

In the normal case, CS-MAP converts from one geodetically referenced system to another. In the sample code segment in the previous topic, for example, UTM27-13 is referenced to NAD27 and CO83-C is referenced to NAD83. The need for NAD27 to NAD83 conversion is unambiguous and performed automatically by CS-MAP's High Performance Interface without the application having to know of this situation. However, there are circumstances where a coordinate system cannot be referenced to a specific datum. For example, what datum should UTM zone 25 (middle of the Atlantic Ocean) be referenced to?

For various reasons, it is not always possible or convenient to reference a coordinate system to a specific datum. To handle such cases, CS-MAP supports the concept of a cartographically referenced coordinate system.

Cartographically Referenced Coordinate Systems

The cs_Csdef_ structure, which carries the definition of all coordinate systems, has an ellipsoid key name element as well as a datum key name element. If the datum key name element is not the null string, the coordinate system is said to be geodetically referenced. If the datum key name element is the null string, the ellipsoid key name element must then carry the key name of an ellipsoid definition in the ellipsoid dictionary. In this case, the coordinate system is said to be cartographically referenced. (If both elements are not the null string, the ellipsoid key name field is ignored.)

The example shown previously in this section showed how conversions are performed between two geodetically referenced systems. If either of the two coordinate systems involved is cartographically referenced, or if both are cartographically referenced, CS_dtcsu simply returns the null datum conversion. Thus, for example, when the target coordinate system is cartographically referenced, the resulting coordinates are based on the source datum, whatever it may happen to be. Similarly, if the source is cartographically referenced and the target is geodetically referenced, there is an implied assumption that the source coordinates are based on the datum of the target. If both coordinate systems are cartographically referenced, we have no knowledge of the datums in either case and the conversion is strictly cartographic, hence the semantic convention adopted here.

Examination of the COORDSYS.ASC file will produce several cartographically referenced coordinate systems. Many of these are UTM zones in areas other than the US and Canada. (In the US and Canada, UTM zones can be reliably said to be based on either NAD27 or NAD83.) Perhaps the most important cartographically referenced coordinate system is that which is named LL. This enables us to use the LL coordinate system to convert generic Lat/Long's to any coordinate system, or convert any coordinate system to Lat/Long's based on the same datum as the source, what ever it might be.

Cartographic Projections

For each projection supported, there exist eight, possibly nine, functions which comprise the full implementation of a projection. The brief description of these functions is given below. These descriptions will be important to those adding a new projection as well.

Those adding projections to the system only need to add an entry to the projection table cs_Prjtab. Doing so, you will need to add a pointer to the Definition Check and the Setup functions. To activate the proper parameter settings in the MFC dialog, you will also need to add the projection to the cs_PrjprmMap table. It is unlikely, but if your new projection uses a new type of parameter, you may need to add a new entry to the cs_Prjprm table. All of these tables are defined in the CSdataPJ.c module.

Program Environments

Portability to a large variety of program environments is a major feature of CS-MAP. Thus, programmers accustomed to a single environment may consider some of the code and design of CS- MAP rather awkward or old fashioned. Nevertheless, by keeping things very basic and simple (e.g. binary searching a sorted fixed length record file), CS-MAP ports to just about any other environment without change and without requiring any additional software beyond the contents of a normal C runtime library.

However, simplicity is insufficient to cover the entire range of issues. In this section we discuss features and aspects of CS-MAP which are specifically intended for differing program environments.

Multi-Threaded Programming

Beginning with release 8.0, CS-MAP is fully compatible with multi-threaded Windows environments. Threads are different from processes in that not only do they share their parents code space, the data space is also shared. Since CS-MAP uses several global variables, this presents a problem.

This problem is addressed by declaring each of the several dynamically used (i.e. non-constant) global variables to be (using the Microsoft vernacular) __declspec (thread). (In the Borland vernacular, its __thread.) This causes each new thread to have it's own copy of these variables; but the initialization of these variables upon starting a new thread is unclear. In any case, we do count on the operating system being able to give us a separate copy of all of these variables for each new thread instance which is started.

In order to insure that each of these variables is properly initialized, we have provided the function named CS_init. It should be called in each new thread just once, prior to any other CS-MAP function call in the thread. If the parent thread's value of the global cs_Dir and cs_DirP variables are valid, these values are preserved. If not they are initialized. In the case of several other variables, such as defaults, the application programmer may specify if these are to be inherited from the parent thread. Variables dealing with NAD27 to NAD83 datum conversions and the like are always initialized to the NULL state.

Thus, each thread will have its own set of NADCON data file buffers. In certain applications, this may be wasteful, but in most cases this provides the highest performance. Otherwise, we would be wasting considerable resources with resource locks etc.

UNIX users need not fear. All declarations and definitions in the CS-MAP code where the __declspec (thread) or __thread are appropriate are accomplished using the manifest constant Thread defined in the CS-MAP header file. This constant is defined to be nothing in most cases. Only in the event that compiler pre-defined constants indicate a multi-thread environment (i.e. _MT), is Thread defined to be something other than nothing. None of this applies if you are building a DLL. In a DLL, there is a single data segment, and multi-threading has no effect.

GUI Considerations

CS-MAP supports a graphic user interface based on Microsoft's MFC library. This is, admittedly, non portable but does provide useful product capability for a large percentage of our clients. Use of these functions requires that you include the csmap.rc file into your projects resources. This can be accomplished by adding an include csmap.rc statement to your project's .rc2 file. Please note that the use of these functions implies that your application activates the basic infrastructure of the MFC library. Accessing the functions in an isolated application does not work without special effort. Also note, that MFC is a multi-threaded environment. You will need to compile the CS-MAP library using the multi-threaded options to eliminate frustrations generated by the Microsoft linker.

The CS_csEditor function causes activation of the coordinate system editor. Similarly, the CS_dtEditor and CS_ellEditor functions cause the activation of the datum and ellipsoid editors respectively. In all three cases, the functions require a single input and return a single result. The input is the key name of the definition which is to be initially displayed. The result is the key name that was displayed when the user caused the dialog to exit. All other user activity is recorded in the appropriate dictionary.

The CS_csBrowser function activates a coordinate system browser and can be used to obtain a coordinate system key name from the user. The CS_csDataDr function displays a dialog which enables the user to specify the directory in which the mapping data files reside.

Customization

Some users will, no doubt, require modification to the basic capabilities of the Coordinate System Mapping Library as provided by OSGeo. The following sections describe how some of the more common requirements can be accomplished with a minimum of effort.

Tuning the Protection System

As distributed, CS-MAP will not allow users to modify or delete a dictionary definition which is produced by the dictionary compiler; i.e. a distribution definition. Further, CS-MAP will not permit modification or deletion of a user defined coordinate system after such definition has remained unaltered for 60 days. The behavior of this feature is controlled by the cs_Protect global variable, an int defined in the CSdata module. You can change the value of this variable in CSdata and recompile, or at run time.

Setting cs_Protect to a negative value disables all of the above described protection features. Setting cs_Protect to zero enables distribution coordinate system protection, but disables the user defined protection system. Setting cs_Protect to a positive value enables the user definition protection feature, and also specifies the number of days which must elapse from the last modification before the definition is protected.

Turning of Unique Names

As distributed, CS-MAP requires that a colon appear in all dictionary definition key names. By doing so, CS-MAP guarantees that the names of all user definitions will be different from any definition which may be contained in a future distribution of CS-MAP. You can disable this feature of CS-MAP by setting the global char variable named cs_Unique to the null character (i.e. '\0'). Alternatively, you can enable this feature using a different character by setting the value of cs_Unique to that character. cs_Unique is defined in the CSdata module and be set at compile time or run time.

Eliminating a Projection

If you do not have a need for all thirty eight supported projections, you can simply remove from the projection table (defined in CSdataPJ) the entry which references any projection which you do not need. Doing so will eliminate all references to the code for a specific projection and reduce the code size of your executable.

Data Dictionary Directory

The directory in which CS_csdef, CS_dtdef, and CS_eldef look for their respective dictionary files is defined in the CSdata.c module. You must use the CS_altdr function to initialize this variable to point to the directory which contains all data files. CS_altdr will use the value of an environmental variable when called with a NULL pointer as an argument. The name of this environmental variable, CS_MAP_DIR by default, is established in cs_map.h as a manifest constant.

Dictionary File Names

The names assigned to the three dictionary files are defined as manifest constants in the cs_map.h header file, declared and initialized in the CSdata module. They can also be modified at run time by using the CS_csfnm, CS_dtfnm, and CS_elfnm function.

Adding Units

The units which are recognized by the Coordinate System Mapping Package are defined in the CSdataU module. You can add or delete as necessary. Note that this table has provisions for an abbreviation in addition to the full name. Use the code as provided as an example of how to incorporate a new unit. Also note that the factor is the multiplier required to change the new unit to meters, or degrees, by multiplication depending upon the type of unit.

Language Translation

Textual descriptions of all error conditions are provided in the CSerpt module. All language oriented text is located either in the cs_map.h header file, one of the three data modules: CSdata, CSdataU, CSdataPJ, or in the ASCII form of the dictionary files (COORDSYS.ASC, DATUMS.ASC, and ELIPSOID.ASC). Language translations efforts need only address these eight files (MFC dialogs excepted).