[Mapserver-dev] Labels that follow streets with bends

Steve Lime steve.lime at dnr.state.mn.us
Mon Feb 10 17:50:36 EST 2003

Lemme think. On the MapServer side there are a couple of issues. How to integrate the support into the map file and into the source itself. 

For the mapfile it's probably as simple as adding a FLOW option to the POSITION parameter. Might need a couple of new options in the LABEL object if more control is desired but at first glance I would think that old parameters like MINFEATURESIZE can cover what we need. Could need a FLOW TRUE/FALSE option depending on how much POSITION is necessary.

In terms of the source the issues are larger. The current code generates a label point and you'd actually need the path (i.e. shapeObj) to operate on. I don't worry about non-cached labels since they could simply access a wrapper to the gd function anyway. We'd need to extend the labelCacheMemberObj to hold that path. Assuming we can store the path then the label cache operation is the part. The cache operates based on the outlines (bounding boxes) of labels and their associated markers (ANNOTATION layers). The current GD code coughs up the metrics and when combined with the position information gives us enough to do collision avoidance. In your case we need more. You can't use a single bounding rect for flowing text. It will over estimate the amount of  space necessary. Instead you'd want a bounding rect for each character. The collision avoidance code is already setup for labels with multiple bounding polygons. It's hard, because with strings the size of the label with or without rotation is the same. So MapServer actually takes metrics from unrotated labels and then rotates them internally so that bounding polygons are tight to the label. With this application rotation is everything and the size of the label is not consistent with or without flowing. Your function is going to have to produce more detailed information it gives back. Even bounding rects for each rotated character would be workable (i.e. turn int *brect into int **brect).  You first have to produce a placement without drawing and then evaluate that placement against the cache. That will be more expensive in this case.

Does this help/make sense?


>>> <woodbri at swoodbridge.com> 02/09/03 10:56AM >>>
Hi all,

There has been some some discussion of have street labels follow 
bends in the streets in the past. I have decided to take a pass at 
implementing a routine to do this.

Here are my initial thoughts on this. I am looking for comments and 

My plan is to implement a function like this:

bchar *TextPath(
    gdImagePtr im,
    int *brect,
    int fg,
    char *fontname,
    double ptsize,
    int npts,
    int *X,
    int *Y,
    char *string,
    int flags);

most of these args are identical to the gdImageStingFT() call and 
this function would work similarly to it if you pass it NULL for im. 
The polyline would be passed in using the npts, X, Y args; and flags 
I envision would be used to control the behavior of the function with 
respect to
NO_PARTIAL  - fail is polyline is too short to render the whole 
TRUNCATE  - trucate the string if it is too long
EXTEND - virtually extend the last segment to write the whole string
REVERSE - the direction of the polyline
AUTO - figure out the best placement of the text so it is most 
ABOVE|BELOW|CENTER the text on the polyline

My first pass at this will be straight forward if not brute force. I 
will take each char in the string and see if I have enough room to 
place it on the segment, if not place it on the next segment until I 
run out of chars or segments. I will also probably ignore most of the 
flags and implement it as flags = EXTEND|AUTO; I plan to write the 
function to just call gdImageStringFTEx() to do the work, a later 
optimization might be to clone the gdImageStringFTEx() source so I 
can make some optimization.

This implementation has the advantage for me that I can dev and test 
in a simplified GD only environment. On the down side real 
performance will not be as easily tested until it is integrated into 

If I implement as described above will it be easy to integrate into 
mapserver? Issues? concerns?

-Steve W.

Mapserver-dev mailing list
Mapserver-dev at lists.gis.umn.edu 

More information about the mapserver-dev mailing list