Opened 17 years ago

Last modified 13 years ago

#2031 new enhancement

Draw labels at angles relative to true geographic north regardless of projection.

Reported by: sroberts@… Owned by: sdlime
Priority: high Milestone:
Component: MapServer C Library Version: unspecified
Severity: minor Keywords:
Cc: dmorissette

Description (last modified by dmorissette)

As far as I can tell Mapserver lacks the ability to draw symbols or labels at
angles relative to true geographic north regardless of the map projection being
used. All angles are only relative to the top of the image in the image
coordinate system, not the map coordinate system. Having the ability to draw
symbols/labels relative to true north is essential for some applications. For
example, drawing the symbol of a ship pointed in the actual direction the ship
is going on a polar stereographic map.

The following is a proposed enhancement to the Mapfile LABEL object to support
this capability. (I assume it should be fairly straightforward to make the same
enhancements to the Mapfile STYLE object.)

A) Create a new boolean directive for "LABEL" called something like
"ANGLETRUENORTH". When set to false or absent LABEL angles should be treated as
before. However if "ANGLETRUENORTH TRUE" is present in LABEL then an angle
specified via "ANGLE" or "LABELANGLEITEM" should be drawn at the angle relative
to geographic north where angle is given in degrees clockwise from 0 at the top
where 0 = North, 90 = East, 180 = South, 270 = West. (I found it necessary to
reverse the direction of the drawing angle from counter-clockwise to clockwise
since the standard for these types of applications is clockwise.)

B) Create a subroutine to offset the angle correctly. The following code will
do this. Probably the logical place to put this would be in mapproject.c?:

------------------------------begin code----------------------------------
/************************************************************************/
/*                          msProjectAngle()                            */
/*                                                                      */
/* Shifts "angle" by the correct amount to keep it relative to the      */
/* geographic north pole regardless of map projection and location      */
/* on map.                                                              */
/*                                                                      */
/* "angle" is relative to geographic north where angle is given in      */
/* degrees clockwise from 0 at the top (0 = North, 90 = East,           */
/* 180 = South, 270 = West).                                            */
/*                                                                      */
/*  "mappoint" has been projected to the map projection and is the      */
/*  location of "angle" on map.                                         */
/************************************************************************/
int msProjectAngle(mapObj *map, pointObj *mappoint, double *angle)
{
#ifdef USE_PROJ
    double angle_offset;
    pointObj mappoint2;

    /* Only transform angle if out proj is not latlong */
    if(!pj_is_latlong(map->projection.proj)) {
       /* Make a copy of the first point */
       mappoint2.x = mappoint->x;
       mappoint2.y = mappoint->y;

       /* convert to latlong */
       if( msProjectPoint(&map->projection, &map->latlon, &mappoint2) ==
MS_FAILURE )
             return MS_FAILURE;
       /* apply a slight offset(~100 meters) south of the original point */
       mappoint2.y -= 3.0/(60.0*60.0);
       /* convert the offset point back to map projection */
       if( msProjectPoint( &map->latlon, &map->projection, &mappoint2) ==
MS_FAILURE )
             return MS_FAILURE;

      /* Calculate angle between these two points. This will be the angle offset
         relative to true north for the map projection. */
      angle_offset = MS_RAD_TO_DEG*asin((mappoint->x -
mappoint2.x)/sqrt(pow((mappoint->x - mappoint2.x),2.0) + pow((mappoint->y -
mappoint2.y),2.0)));
      if((mappoint->y - mappoint2.y) < 0) angle_offset = 180 - angle_offset;
      *angle += angle_offset;
  }
  /* Change from counterclockwise to clockwise */
  *angle = - *angle;
  return(MS_SUCCESS);
#else
  msSetError(MS_PROJERR, "Projection support is not available.",
"msProjectAngle()");
  return(MS_FAILURE);
#endif
}
-------------------------------end code-----------------------------------


C) Modifiy mapdraw.c to include a call to the above subroutine where it draws
the point labels if it detects the "ANGLETRUENORTH" directive. Attached is a
proposed patch for mapdraw.c.

Does the above seem like a reasonable approach? Would it be possible to include
some variation of this in the next release?

-Steve

Attachments (2)

mapdraw.c.patch (1.9 KB ) - added by sroberts@… 17 years ago.
Proposed patch for mapdraw.c
test_files.tar.gz (21.6 KB ) - added by sroberts@… 17 years ago.
A couple of map files and symbol fonts for testing

Download all attachments as: .zip

Change History (13)

by sroberts@…, 17 years ago

Attachment: mapdraw.c.patch added

Proposed patch for mapdraw.c

by sroberts@…, 17 years ago

Attachment: test_files.tar.gz added

A couple of map files and symbol fonts for testing

comment:1 by sdlime, 17 years ago

Cc: warmerdam@… dmorissette@… added
Adding a few other folks for comment.

Steve

comment:2 by dmorissette, 17 years ago

I like this enhancement idea, but would have a few questions/comments:

1- Instead of "ANGLETRUENORTH TRUE|FALSE", we could try to use something more
generic and that could support other flags that apply to the angle in the
future. For instance ANGLEMODE with a value of TRUENORTH.

2- The use of clockwise angles for this mode bugs me. I find that it's just
going to lead to confusion if the default is counter-clockwise angles (as it is
today) and TRUENORTH uses clockwise angles. Can you provide examples of "this
type of applications" that use clockwise angles and justify this choice? For
instance Geographic coordinate systems typically use (latitude, longitude), but
we still use x,y (i.e. lon, lat) to refer to geographic coordinates to avoid
causing confusion with axis order changing depending on the coordinate system.
The WMS 1.3.0 spec has made that decision to break with the past and impose the
use the "correct" axis order for every coordinate system and the mess that
resulted (and still hasn't been resolved) is a good example of what happens when
you trade simplicity for correctness.

3- If there is really a need to support clockwise angles then it's probably not
limited to applications using TRUENORTH, and then perhaps we could use different
values of ANGLEMODE to specify whether angles should be interpreted clockwise or
counter-clockwise. 
  Possible ANGLEMODE values: CCW (default), CW, TRUENORTHCCW, TRUENORTHCW

comment:3 by dmorissette, 17 years ago

BTW, this enhancement probably needs a RFC before it can be integrated in MapServer.

comment:4 by fwarmerdam, 17 years ago

I agree with Daniel with regard to the RFC, and I too am wondering if there
are ways of generalizing this a bit. 

comment:5 by sroberts@…, 17 years ago

In answer to Daniel's #4 comments I agree that changing from counter-clockwise
to clockwise will cause confusion but I have no choice. In the world of marine
navigation (which is the world I work in) heading, bearing, direction, course
over ground(COG), speed over ground(SOG), and many others are all defined as
"clockwise". The bible for marine navigation is called "Bowditch - The American
Practical Navigator" and you will always find a copy on any large vessel. There
is an online copy at:
 
  http://www.irbs.com/bowditch/

Open chapter 1 and read page 5 and 6 for the definition of direction, heading
and bearing. For Bearing it has:

 Bearing (B, Brg.) is the direction of one terrestrial
 point from another, expressed as angular distance from
 000° (North) clockwise through 360°.

All the navigation data that is generated and archived by the ship's nav systems
that I work on uses "clockwise" for angles. 

I assume the above definitions applies to all forms of navigation. Anybody who
has ever flown an airplane knows that their compass heading is always measured
"CLOCKWISE" starting from the Magnetic NORTH. For another source see:

 http://en.wikipedia.org/wiki/Bearing_%28navigation%29

It is essential that this enhancement support clockwise drawing of angles
otherwise it is not going to do me(or other potential users) much good. I like
your option 3. This should provide the most flexibility.

I've thought about making this subroutine a little more general. I initially
tried something like:

int msProjectAngle(projectionObj *in, projectionObj *out, pointObj *point,
double *angle)

But I quickly discovered in mapdraw.c I did not have easy access to the original
unprojected point. So I was forced to use the projected point which eliminated
the need for the "in" projection. I also needed access to the latlong projection
for the algorithm to work which forced me to pass the map object. So the
subroutine has deviated from the "standard" used in mapproject.c. Not sure if
this matters or not.

Right now this subroutine uses the north pole as the reference point so I would
probably rename it to something like "msProjectAngleTrueNorth". To make it more
general one could include a reference point in the input parameter list. For the
truenorth case one would just pass the reference point of 90N,0E. This would
also mean adding a reference point directive to the mapfile. This might start to
get complicated fast?

What is involved in an RFC?

-Steve

comment:6 by sroberts@…, 17 years ago

I decided to play around with ESRI's ArcMap and see how they do this. When you
rotate a symbol you are given a choice of two rotation styles:

1) Geographic

    0|
     |
     |   90
-----------
270  |
     |
     |180


2) Arithmetic

   90|
     |
     |    0
-----------
180  |
     |
     |270


The default is Geographic. The "Geographic" style is clockwise relative to
"north" which is what I need. But I played around with different projections and
as far as I can tell the ESRI software does not have the smarts to draw the
geographic angles correctly on these projections. But the software I have is
somewhat old so maybe this works in later versions.

-Steve

comment:7 by bartvde, 13 years ago

Did anything ever happen in Mapserver to implement such a thing as described in this enhancement report?

comment:8 by bartvde, 13 years ago

It seems this was discussed but never implemented?

http://mapserver.org/development/rfc/ms-rfc-45.html

in reply to:  8 comment:9 by sroberts, 13 years ago

As far as I can tell nothing has been done on this. What will it take to get this moving again?

comment:10 by dmorissette, 13 years ago

Description: modified (diff)

Just like for any enhancement, it would need a dev to champion it, prepare a RFC and discuss it on the -dev list, and eventually commit, update docs and support any bug/side-effect that may arise once it is released.

In a previous comment you asked "What is involved in a RFC?"... the best way to find out is to look at a few recent RFCs (there are several good examples in the RFC 60-69 range) and the corresponding discussions in the mapserver-dev archives. If you want, you can prepare the RFC yourself and propose it on the -dev list for discussion/approval. Then if it is approved you could eventually contribute a patch for code and docs via this ticket... then the last missing bit will be to find a committer to review and commit your patches. Another option is to convince (or hire) one of the devs to do this for you of course.

comment:11 by dmorissette, 13 years ago

Cc: dmorissette added
Note: See TracTickets for help on using tickets.