Proceed to GeoCommunity Home Page


SpatialNewsGIS Data DepotGeoImaging ChannelGIS and MappingSoftwareGIS JobsGeoBids-RFPsGeoCommunity MarketplaceGIS Event Listings
HomeLoginAccountsAboutContactAdvertiseSearchFAQsForumsCartFree Newsletter

Sponsored by:


TOPICS
Today's News

Submit News

Feature Articles

Product Reviews

Education

News Affiliates

Discussions

Newsletters

Email Lists

Polls

Editor's Corner


SpatialNews Daily Newswire!
Subscribe now!

Latest Industry Headlines
3D Repo Brings Cloud Expertise to Government Funded Smart Infrastructure Project
EarthSense Computer Models Impact of Trees on Urban Air Pollution
SpatialTEQ Inc.'s Map Business Online Picked by Dow Jones for Delivery Operations Team Business Mapping
USDA Announces $6 Million to Aid Fire-Affected Farmers and Ranchers in Midwest
History of Abrupt Sinking of the Seal Beach Wetlands

Latest GeoBids-RFPs
Cartography Training-VA
A & E Services-OR
Remote Sensing-UT
Surveying and Mapping-WA
GPS Locators-MN

Recent Job Opportunities

Recent Discussions
LiDAR-derived DEM
space syntax
DEM data for Israel
3D modeling Consultant
AVP to Style

Latitude/Longitude Classes

Article Supplied by George Chastain, August 10, 2001


I had developed two control classes that would provide for the consistent entry and display of latitude and longitude values. Recently I developed a powerful abstract (pure virtual) class for a new category of edit controls I refer to as Multi-Field Edit Controls. That class, CGCMultiFieldEdit, has proven to be very popular. I have also found the class to be very useful in creating new controls and exceptionally easy in adding new behavior and styles to existing controls derived from it. I wanted to take advantage of this new versatile class in the implementation of my popular latitude and longitude control classes. Therefore, I have redesigned my Latitude and Longitude control classes to use CGCMultiFieldEdit. In addition, I have added a set of styles that may be applied to the Latitude and Longitude controls to make them more versatile.

The demo program, shown below, illustrates the capabilities of these classes.


Click here for larger image

Reflections on Design

I had a difficult time deciding just what would be the best way to redesign the Latitude (CGCLatitudeCtrl) and Longitude (CGCLongitudeCtrl) classes. I had developed my original CGCLatitudeCtrl and CGCLongitudeCtrl classes in a hurry and they duplicated most of the code in the classes. I wanted to eliminate that duplication and make them more "object oriented." If I were to be a fanatical OOP purist, I should put the code specific to the latitude control in the CGCLatitudeCtrl class and the code specific to the longitude control in the CGCLongitudeCtrl class. However, the differences in implementation between the two are only a few lines of code. The maximum value of the degree field and the way in which you represent the hemisphere for certain styles are the only differences. And, since it is extremely unlikely that you would ever have a need for JUST a latitude or JUST a longitude control, you should make sure that both controls always use consistent formats and behavior. In order to emphasize the need for consistency across both control classes, and due to the small difference between their implementations, I opted to develop an abstract (pure virtual) class, CGCLatLongAbstractBase, that would pull the implementation for both controls together into a single class. I would then provide two control classes, CGCLatitudeCtrl and CGCLongitudeCtrl derived from the new abstract class, that would provide only specialized input validation for their methods and maybe a few methods to make better use of the abstract class' methods. This arrangement allowed me to provide the tight relationship needed in their implementation (to ensure consistency) while emphasizing the fact that they are still logically different, albeit related, entities.

When creating Multi-Field Edit Controls such as CGCLatitudeCtrl and CGCLongitudeCtrl using the CGCMultiFieldEdit class, the implementation is typically fairly compact. However, if your control needs to support a number of different styles for different customer needs as this implementation required, then the implementation can become more complicated. But then that's what happens when deriving a new class from an existing one. As the class requires more functionality, it can become more complicated.

The implementation file for CGCLatLongAbstractBase is long. For better manageability, it should be broken up into smaller files. However, I wanted to make incorporating it into a new project as easy as possible so I put all the code in one file.

I had a lot of positive feedback on the last design and I hope that you will view this one in a positive manner as well.

The class hierarchy for the Latitude and Longitude classes is illustrated in the following figure:


Click here for larger image

The figure above also shows that I indirectly derived the latitude and longitude controls from my CGCColorEdit class to provide a means for controlling the colors and fonts used in the controls. Since there are already articles available on how to control color and fonts in edit controls, I will not dwell on the use of that class. However, you may find my implementation of CGCColorEdit to be very versatile.

The CGCLatLongAbstractBase class also makes use of a new class that I created to ease the implementation of the context menus for the controls. This new class, CGCContextMenu, provides some wrappers for convenience. Feel free to add to this class as you wish.

Preprocessor Flags and Compiler Switches

The latitude and longitude controls now support several styles to be described below. Among these is a style that supports the display and entry of a decimal degrees value. The implementation makes use of a preprocessor constant "GCDD" to conditionally compile support for the decimal degrees style. If you will not need to support the display/entry of decimal degrees, do not define GCDD. That code will then be left out upon compilation. However, if you need support for decimal degrees, be sure to define GCDD in your compile options. There is no way to compile only decimal degrees support. You will always get support for degrees-minutes-seconds regardless of compiler options.

An alternative to this approach would have been to derive extended CGCLatitudeCtrl and CGCLongitudeCtrl classes from the existing ones that would have added the decimal degrees functionality. Using a preprocessor flag was just the choice I went with so I wouldn't have to keep track of as many classes.

Because of the use of logically different field support classes in the implementation of the controls, some dynamic casting was used to access the appropriate methods for the different field support objects. This requires that the project using these classes be compiled with the /GR switch to enable Run-Time Type Information (RTTI).

Behaviour

The CGCLatitudeCtrl and CGCLongitudeCtrl classes are very simple to use. Each control divides its display into different fields. The user can navigate between fields within the control using the left and right arrow keys. Navigation to the right may also be achieved using the space bar. When the user navigates to a particular field within the control, that field is selected and highlighted. Actions taken by the user will affect that field. The up and down arrow keys may be used to increment or decrement, respectively, the currently selected field. In addition, the user may enter values for that field directly using the number keys on the keyboard. The user may also select a specific field within the control by clicking on it with the left mouse button. The user can reset the currently-selected field by pressing the backspace key.

A context menu is even provided. When the user clicks over the control that has focus using the right mouse button, a context menu is displayed. It allows the user to reset the entire control setting or to reset only the currently-selected field. There are even "hot keys" defined for the controls.

Styles

The new implementation provide several styles that may be applied to allow the developer to tailor these controls to most needs. The controls provide the following styles:
GC_COLON_DELIM_STYLE  (DEFAULT)

This style specifies that colons are to be used to separate the fields in both controls.

GC_SPACE_DELIM_STYLE

This style specifies that a single white space is to be used to separate the fields in both controls.

GC_TRADITIONAL_DELIM_STYLE

This style specifies that both controls are to use a contemporary format in the representation of a latitude or longitude. In this style, the raised "degree symbol" is used after the degree field, a single quote is used after the minutes field and a double quote is used after the seconds field. A single white space is used to separate the hemisphere field from the latitude or longitude value.

GC_CUSTOM_DELIM_STYLE

This style allows the client to specify that strings obtained from the string resource table are to be used after each field. The string resources used are identified as IDS_CUSTOM_HEM_DELIM, IDS_CUSTOM_DEG_DELIM, IDS_CUSTOM_MIN_DELIM and IDS_CUSTOM_SEC_DELIM. For further details, see "STRING RESOURCES" below.

GC_HEM_INDICATOR_STYLE (DEFAULT)

This syle states that the string resources IDS_NHEM_TXT and IDS_SHEM_TXT are to be used to indicate the hemisphere in the Latitude Control and the string resources IDS_EHEM_TXT and IDS_WHEM_TXT are to be used to indicate the hemisphere in the Longitude Control. For further details regarding these resources, see "STRING RESOURCES" below.

GC_SIGN_INDICATOR_STYLE

This style states that the string resources IDS_POSHEM_TXT and IDS_NEGHEM_TXT are to be used to indicate the hemisphere in both controls. For further details on these resources, see "STRING RESOURCES" below.

GC_FLOAT_SECONDS_STYLE  (DEFAULT)

Use a floating point seconds field in both controls. The seconds field represents seconds to the thousandths.

GC_INTEGER_SECONDS_STYLE

Use a simple integer seconds field for both controls.

GC_LEADING_ZEROS_STYLE  (DEFAULT)

Specifies that leading zeros be used in all numeric fields in both controls.

GC_NOLEADING_ZEROS_STYLE

Specifies that no leading zeros be used in any field in both controls.

GC_LEADING_HEM_STYLE  (DEFAULT)

Specifies that the hemisphere indicator is to be displayed on the left of the control.

GC_TRAILING_HEM_STYLE

Specifies that the hemisphere indicator is to be displayed on the right.

GC_FULL_STYLE  (DEFAULT)

Specifies that the control display the latitude/longitude as separate hemisphere, degrees, minutes and seconds values.

GC_DECIMAL_DEGREES_STYLE

Specifies that the control display the latitude/longitude using the hemisphere and the decimal degrees value as two separate fields. This style is not defined if the code is not compiled with "GCDD" defined.

GC_DEFAULT_DMS_STYLE  (DEFAULT)

Equivalent to OR'ing the GC_COLON_DELIM_STYLE, GC_HEM_INDICATOR_STYLE, GC_FLOAT_SECONDS_STYLE, GC_LEADING_ZEROS_STYLE, GC_FULL_STYLE and GC_LEADING_HEM_STYLE styles.

GC_DEFAULT_DD_STYLE

Equivalent to OR'ing the GC_COLON_DELIM_STYLE, GC_HEM_INDICATOR_STYLE, GC_LEADING_ZEROS_STYLE GC_DECIMAL_DEGREES_STYLE and GC_LEADING_HEM_STYLE styles. This style is not defined if the code is not compiled with "GCDD" defined.

In this demo, the client sets the background and text colors, as well as selecting a non- proportional (fixed pitch) font using methods provided by the CGCColorEdit class. I find that Multi-Field Edit Controls, such as CGCLatitudeCtrl and CGCLongitudeCtrl look better when using a non-proportional font.

Methods

There are several methods defined for each class in addition to those inherited from their ancestor classes. These are:
BOOL SetStyle(const STYLE_TYPE Style);

The SetStyle() method is used to set the controls to the style(s) defined above. The method allows the client to specify only the style to be set without the client needing to OR all desired styles together.

UINT GetStyle();
Returns the current style of the control.
BOOL Set(const CString& hsph,   
         const UINT Degrees,           
         const UINT Minutes,           
         const float Seconds);         

The method Set() allows the application to initialize the control to any setting valid for that type of control (latitude or longitude). With this method, the client may specify the latitude or longitude using separate hemisphere, degrees, minutes and seconds values. The method returns TRUE if successful and FALSE if any parameter is outside the valid range for that parameter. This method may be for controls with either the GC_FULL_STYLE or the GC_DECIMAL_DEGREES_STYLE.

void Get(CString& hsph, UINT& Degrees, UINT& Minutes, float& Seconds) const; 

The method Get() allows the application to obtain the current setting as separate values. This is usually called from within an EN_CHANGE handler. This method may be called for controls with either the GC_FULL_STYLE or the GC_DECIMAL_DEGREES_STYLE.

double GetDecimalDegrees() const;

The method GetDecimalDegrees() allows the client to obtain the current setting in decimal degrees. Like method Get(), this method would typically be called from an EN_CHANGE handler. This method may be called for controls with either the GC_FULL_STYLE or the GC_DECIMAL_DEGREES_STYLE.

BOOL SetDecimalDegrees(const double Degrees);

The SetDecimalDegrees() method allows the client to initialize the control by specifying a decimal degree value. Returns TRUE if if the call succeeds or FALSE if the call fails due to an invalid input parameter. This method may be called for controls with either the GC_FULL_STYLE or the GC_DECIMAL_DEGREES_STYLE.

For further details on these methods and others that the control classes inherit, please refer to the extensive comments supplied in the source code of the demo project.

String Resources

The CGCLatLongAbstractBase class makes use of string resources to facilitate modifications for different languages and for custom needs.

There are 6 string resources used to support two different styles controlling the use of the hemisphere field. These are:
RESOURCE ID VALUE USED BY STYLE
IDS_NHEM_TXT "N" GC_HEM_INDICATOR_STYLE
IDS_SHEM_TXT "S" GC_HEM_INDICATOR_STYLE
IDS_EHEM_TXT "E" GC_HEM_INDICATOR_STYLE
IDS_WHEM_TXT "W" GC_HEM_INDICATOR_STYLE
IDS_POSHEM_TXT "+" GC_HEM_SIGN_STYLE
IDS_NEGHEM_TXT "-" GC_HEM_SIGN_STYLE

They are defined to the typical characters one would expect to use when indicating/specifying a hemisphere. However, you are not restricted to using single-character strings. You could, for example, specify "NORTH" for IDS_NHEM_TXT and "SOUTH" for IDS_SHEM_TXT. However, the design of the CGCMultiFieldEdit class imposes a field width constraint on the contents of a given field via parameters specified in the CGCMultiFieldEdit::Format() method call. As the field changes value, its width stays the same. Therefore, you should ensure that the strings you specify for IDS_NHEM_TXT and IDS_SHEM_TXT are the same length. Further, you should ensure that the strings for IDS_EHEM_TXT and IDS_WHEM_TXT are the same size and the same is true for IDS_POSHEM_TXT and IDS_NEGHEM_TXT. For example, if you wished to do something silly like use "UP" to represent the Northern hemisphere and "DOWN" to represent the Southern hemisphere, then you should define IDS_NHEM_TXT as "UP " and IDS_NHEM_TXT as "DOWN". Otherwise, "DOWN" will likely be displayed as "DO"! For further details on the use of the CGCMultiFieldEdit class, please see my article "Multi-Field Edit Controls - A Whole New Class of Edit Controls".

There are 6 string resources that are defined for use in the control context menus. These are:
RESOURCE ID Value
IDS_DEFLATOPT "Reset Latitude"
IDS_DEFLONOPT "Reset Longitude"
IDS_RESETHEM "Reset Hemisphere"
IDS_RESETDEG "Reset Degrees"
IDS_RESETMIN "Reset Minutes"
IDS_RESETSEC "Reset Seconds"

These allow the developer to change the strings used for these menu options if needed. A private method of CGCLatLongAbstractBase, LoadStringResource() provides a convenient location for modifications should you need to change how the menu options are defined/obtained.

There are 4 string resources defined to support the GC_CUSTOM_DELIM_STYLE style. These are labeled as follows:
RESOURCE ID VALUE RESOURCE USE
IDS_CUSTOM_HEM_DELIM " h " Displayed following the
IDS_CUSTOM_DEG_DELIM " d " Displayed following degress field
IDS_CUSTOM_MIN_DELIM " m " Displayed following minutes field
IDS_CUSTOM_SEC_DELIM " s " Displayed following seconds field

The strings provided in the resource table for these resource IDs are examples only. If you wish to use the GC_CUSTOM_DELIM_STYLE, you may change the definitions of these resources to whatever you wish. These string resources are provide to allow you to customize a style for the controls.

The Demo

The demo supplied provides you with controls to apply the different styles to the Latitude and Longitude controls. You can combine the different styles and see how they interact. The demo also illustrates a possible use for the CGCColorEdit class functionality for your latitude and longitude controls. In this demo, the background color changes according to the hemisphere being displayed! You probably will not want this but it illustrates one use of the CGCColorEdit class. The primary reason for using CGCColorEdit is to select a non-proportional (fixed pitch) font for the controls. Such a font makes the controls look better when changing the field values because the fields do not shift left and right as different width characters are displayed.

How to Use

Here are the steps to place a latitude control and a longitude control in your user interface:
  1. Add CGCColorEdit class to your project.
  2. Add CGCMultiFieldEdit class to your project.
  3. Add CGCLatLongAbstractBase class to your project.
  4. Add CGCLatitudeCtrl class to your project.
  5. Add CGCLongitudeCtrl class to your project.
  6. Add CGCContextMenu class to your project.
  7. Place an edit box using the Resource Editor to be used for your latitude control.
  8. Place an edit box using the Resource Editor to be used for your longitude control.
  9. Use ClassWizard, create a member variable of type CGCLatitudeCtrl for one of the new edit boxes.
  10. Use ClassWizard to create a member variable of type CGCLongitudeCtrl for the other new edit box.
  11. Add an EN_CHANGE handler for each of the new edit boxes to your parent window to handle when the controls change as you would any other control class.

Also see my related article "UTM Coordinate Control" on a control for entering and displaying Universal Transverse Mercator coordinates.

I hope that these classes will continue to prove useful to someone on future projects.

Downloads

Download self extracting demo and source code - 304 Kb

Comments:


About the Author

George Chastain is a Software Consultant based in Huntsville, Alabama. He performs software requirements analysis and definition, software design and coding for government and defense projects. An experienced developer in C/C++, Ada 83, Ada 95, and more on Windows and Unix platforms, George has worked on many projects including a GIS system for the US Government. His experience covers user-interface development and real-time and safety-critical systems software development. When not at work, George can often be found developing a useful piece of code at home.

George maintains a personal web site providing resources and information to all team members working government and defense software development projects. The site may be visited at the following URL: http://home.hiwaay.net/~georgech/

More Features

Article (c) 2001, George Chastain. Distribution or retransmission is strictly prohibited

Sponsored by:

For information
regarding
advertising rates
Click Here!

Copyright© 1995-2014 MindSites Group / Privacy Policy

GeoCommunity™, Wireless Developer Network™, GIS Data Depot®, and Spatial News™
including all logos and other service marks
are registered trademarks and trade communities of
MindSites Group