Sign up to receive free email alerts when patent applications with chosen keywords are publishedSIGN UP

Abstract:

A system and method for label placement is disclosed that achieves the
twin goals of practical efficiency and high labeling quality by employing
cartographic heuristics. A caller defines map and label properties. Then
labels are pulled within a map boundary. Labels are next ordered by
priority in descending importance. The order of testing labels is
determined. Attempts are made to move overlapping labels. This is an
iterative process; therefore there must be criteria that halt the
procedure. Upon reaching an acceptable solution, the label properties are
adjusted to reflect the new label placements.

Claims:

1. A method for determining when to invoke a computer routine to halt
label movement of a group of labels on a map utilizing a computer system
comprising the computer implemented steps of: determining for the group
of labels a collision score; determining for the group of labels an
iteration count; determining for the group of labels a slow change count;
and determining for the group of labels an oscillation count; wherein the
routine to halt label movement is invoked when the collision score
indicates there are no label collisions, or the iteration count is
greater than a first given value, or the slow change count is greater
than a second given value, or the oscillation count is greater than a
third given value.

2. The method of claim 1 wherein determining the collision score
comprises calculating for each overlapping pair of labels i and j, where
i and j are not equal to each other, the following formula: collision
score = ij ( ( adjusted priority for
i ) 2 + ( adjusted priority for j ) 2 )
. ##EQU00002##

3. The method of claim 1 wherein determining the iteration count
comprises incrementing the iteration count upon each iteration in the
collision score.

4. The method of claim 1 wherein determining the slow change count
comprises incrementing the slow change count upon each iteration in the
collision score according to the following calculation: slow change
count=slow change count+1 when (collision score<=previous collision
score) and (collision score>X*previous collision score) where X is
close to but less than one; wherein else slow change count=zero.

6. A computer system for determining the iteration to invoke a computer
routine to halt label movement of a group of labels on a map, said
computer system comprising: input means for inputting map data and label
data; memory means for storing the iteration; processor means responsive
to a control program for generating digital signals corresponding to the
iteration, the processor means being adapted to: determining for the
group of labels a collision score; determining for the group of labels an
iteration count; determining for the group of labels a slow change count;
and determining for the group of labels an oscillation count; wherein the
iteration to invoke the computer routine to halt label movement is
determined when the collision score indicates there are no label
collisions, or the iteration count is greater than a first given value,
or the slow change count is greater than a second given value, or the
oscillation count is above a third given value.

7. The system of claim 6 wherein determining for the group of labels the
collision score comprises calculating for each overlapping pair of labels
i and j, where i and j are not equal to each other, the following
formula: collision score = ij ( ( adjusted
priority for i ) 2 + ( adjusted priority
for j ) 2 ) . ##EQU00003##

8. The system of claim 6 wherein determining for the group of labels the
iteration count comprises incrementing the iteration count upon each
iteration in the collision score.

9. The system of claim 6 wherein determining for the group of labels the
slow change count comprises incrementing the slow change count upon each
iteration in the collision score according to the following calculation:
slow change count=slow change count+1 when (collision score<=previous
collision score) and (collision score>X*previous collision score)
where X is close to but less than one; wherein else slow change
count=zero.

10. The system of claim 6 wherein determining for the group of labels the
oscillation count comprises incrementing the oscillation count upon each
iteration in the collision score according to the following calculation:
oscillation count=oscillation count+1 when ((collision score>previous
collision score and previous collision score<previous previous
collision score) or (collision score<previous collision score and
previous collision score>previous previous collision score)); wherein
else oscillation count=zero.

12. The medium of claim 11 wherein determining for the group of labels
the collision score comprises calculating for each overlapping pair of
labels i and j, where i and j are not equal to each other, the following
formula: collision score = ij ( ( adjusted
priority for i ) 2 + ( adjusted priority
for j ) 2 ) . ##EQU00004##

13. The medium of claim 11 wherein determining for the group of labels
the iteration count comprises incrementing the iteration count upon each
iteration in the collision score.

14. The medium of claim 11 wherein determining for the group of labels
the slow change count comprises incrementing the slow change count upon
each iteration in the collision score according to the following
calculation: slow change count=slow change count+1 when (collision
score<=previous collision score) and (collision score>X*previous
collision score) where X is close to but less than one; wherein else slow
change count=zero.

15. The medium of claim 11 wherein determining for the group of labels
the oscillation count comprises incrementing the oscillation count upon
each iteration in the collision score according to the following
calculation: oscillation count=oscillation count+1 when ((collision
score>previous collision score and previous collision
score<previous previous collision score) or (collision
score<previous collision score and previous collision
score>previous previous collision score)); wherein else oscillation
count=zero.

Description:

CROSS REFERENCE TO RELATED APPLICATION

[0001] This application is a continuation of U.S. patent application Ser.
No. 11/891,606, filed Aug. 13, 2007, which in turn is a continuation of
U.S. patent application Ser. No. 10/462,044, filed Jun. 16, 2003, now
U.S. Pat. No. 7,425,968, the entire file wrapper contents of which are
hereby incorporated by reference as though fully set out at length.

COPYRIGHT NOTICE AND PERMISSION

[0002] This document contains some material which is subject to copyright
protection. The copyright owner has no objection to the reproduction with
proper attribution of authorship and ownership and without alteration by
anyone of this material as it appears in the files or records of the
United States Patent and Trademark Office, but otherwise reserves all
rights whatsoever.

FIELD OF THE INVENTION

[0003] The present invention relates to a computer-implemented method and
apparatus for automatically labeling maps or graph layouts in accordance
with predefined label criteria.

BACKGROUND OF THE INVENTION

[0004] Maps include geographic drawings showing countries, cities, rivers,
bodies of water, mountains, and other features of interest. Labeling
cartographic features is a fundamental part of map-making. Placing each
label optimally with respect to its corresponding feature invariably
produces labels overlapping each other or too close to each other. As
this results in confusion and unacceptable maps, methods to reposition
labels or not draw them at all must be used to create a map that conveys
as much information as possible.

[0005] Tagging graphical objects with text labels is a fundamental task in
the design of many types of informational graphics. This problem is seen
in its most essential form in cartography, but it also arises frequently
in the production of other informational graphics such as scatter plots.
The quality of a labeling is determined essentially by the degree to
which labels obscure other labels or features of the underlying graphic.
The goal is to choose positions for the labels that do not give rise to
label overlaps and that minimize obscuration of features. Construction of
a good labeling is thus a combinatorial optimization problem, which has
been shown to be NP-hard (Marks and Shieber, 1991). As a hypothetical
baseline algorithm, randomly choosing positions for each label generates
a poor labeling, both aesthetically, and as quantified using a metric
that counts the number of conflicted labels, i.e., those that obscure
point features or other labels.

[0006] In addition to geographical and technical maps, there are many
labeling applications relating to graph layouts and drawings. These
applications include, but are not limited to, areas such as database
design (e.g. entity relationship diagrams), software engineering
including CASE, software debugging, complex web pages, CAD drafting,
complex electrical diagrams, and telecommunications and communications
networking. In fact, the labeling of the graphical features of any
drawing is generally necessary because it conveys information essential
to understanding the drawing. For complex and information rich drawings,
computer aided labeling is increasingly employed.

[0007] As used in the present specification, the term "map" is used to
include both geographical and technical maps as well as graph layouts and
drawings. The term "label" is used to refer to text or other indicia to
be placed on a map.

[0008] A system and method for labeling objects on maps while avoiding
collisions with other labels has been sought after. Some apparently
powerful algorithms for automatic label placement on maps use heuristics
that capture considerable cartographic expertise but are hampered by
provably inefficient methods of search and optimization.

[0009] This patent discloses a system and method for label placement that
achieves the twin goals of practical efficiency and high labeling quality
by employing cartographic heuristics.

SUMMARY OF THE INVENTION

[0010] The present invention provides a computer-implemented system and
method of automatically labeling a map in accordance with predefined
label location, placement, and priority criteria.

[0011] Here, each label is represented as a convex polygon with any
orientation on the map. Labels have various parameters associated with
them such as location, size, shape, number and location of vertices,
target feature, priority, movement constraints, and clearance. After
finding the best position of a label for every feature without regard to
other labels or features, higher priority label positions are compared to
lower priority label positions two at a time. If the labels interfere,
the lower priority label is moved within its movement constraint. Several
candidate locations for the lower priority label position are found by
moving it the shortest distance to avoid the higher priority label
position. A new location is acceptable if the location does not collide
with a label of higher priority. It can collide with a label of lower
priority. If no candidate positions are acceptable, the label is not
moved. This process continues until all labels are inspected, after which
a deviation from the desired result function is calculated. This function
is zero if the label interference for all labels is zero and greater than
zero otherwise. The whole process is repeated until the evaluation
function equals zero or the change in the evaluation function is less
than a given percent (e.g., two percent) for a small number (e.g., four)
of iterations or if it oscillates for a number (e.g., six) of iterations
or if the number of iterations is greater than a set number (e.g.,
twenty). If any interference remains, then interfering labels with lower
priorities are not drawn.

[0012] The details of the present invention, both as to its structure and
operation, can best be understood in reference to the accompanying
drawings, in which like reference to the accompanying drawings, in which
like reference numerals refer to like parts, and in which:

BRIEF DESCRIPTION OF THE DRAWINGS

[0013] FIG. 1 is a diagram of a computer hardware architecture compatible
with the present system and method.

[0014] FIG. 2 is a schematic diagram showing an exemplary computer program
product.

[0015] FIG. 3 is a flow chart showing the overall logic of the present
system and method.

[0016] FIGS. 4a, 4b, and 4c is a flow chart showing the initialization of
the anti-collision system and method.

[0027] Referring initially to FIG. 1, a system is shown which includes a
digital processing apparatus. This system is a general-purpose computer
1000. The computer may include a graphics display, print hardware, and
print software, or may be as simple as a generic personal computer. The
example computer in FIG. 1 includes central processor 1010, system memory
1015, disk storage 1020 (e.g., hard drive, floppy drive, CD-ROM drive,
and DVD drive), controller 1005, network adapter 1050, video adapter
1030, and monitor 1055. Data input may be through one or more of the
following agencies: keyboard 1035, pointing device 1040, disk storage
1020, local area network 1060, point to point communications 1065, and
wide area network 1070 (e.g., internet).

[0028] One or more features of the computer as shown may be omitted while
still permitting the practice of the invention. For example, printer 1045
is not necessary for maps intended to be displayed only on monitor 1055.
Likewise, network adapter 1050, local area network 1060, point to point
communications 1065, and wide area network 1070 are not necessary when
the primary method of data input is via removable disk storage.

[0029] The flow charts herein illustrate the structure of the logic of the
present invention as embodied in computer program software. Those skilled
in the art will appreciate that the flow charts illustrate the structures
of logic elements, such as computer program code elements or electronic
logic circuits, that function according to this invention. Manifestly,
the invention is practiced in its essential embodiment by a machine
component that renders the logic elements in a form that instructs a
digital processing apparatus (that is, a computer) to perform a sequence
of function steps corresponding to those shown.

[0030] FIG. 2 shows a computer program product which includes a disk 1080
having a computer usable medium 1085 thereon for storing program modules
a, b, c, and d. While 4 modules are shown in FIG. 2, it is to be
understood that the number of modules into which the program is divided
is arbitrary and may be in any particular embodiment a different number.

[0031] Modules a, b, c, d may be a computer program that is executed by
processor 1010 within the computer 1000 as a series of
computer-executable instructions. In addition to the above-mentioned disk
storage 1020, these instructions may reside, for example in RAM or ROM of
the computer 1000 or the instructions may be stored on a DASD array,
magnetic tape, electronic read-only memory, or other appropriate data
storage device. In an illustrative embodiment of the invention, the
computer-executable instructions may be lines of compiled C++ code.

[0032] FIG. 3 is an overview and summary of the label anti-collision
procedure for maps. The caller of the procedure performs the first stage,
routine 5, and the second stage, routine 8. Routine 5 involves locating
each label on a map in the optimal position with respect to its target
feature without regard to other labels or features. Routine 8 assigns
properties to the map and the labels.

[0033] To begin, the user must specify how to initially place labels on a
map. That is, commencing at routine 5, it is assumed that the user will
assign positions that give the best label location with respect to its
associated feature. For this procedure to work, the user places the
labels in the best spots according to their criteria regardless of other
labels and map features. For example, in the initial positions, labels
may overlap each other and/or extend over the map boundary. Labels are
assumed to be convex polygons while the map boundary is assumed to be a
rectangle.

[0034] Next, at routine 8, the user must assign properties to the map and
the labels. Map properties include its height and width. A label's
properties include the associated map feature(s), initial location, size,
shape, angular orientation, priority, movement constraints, and
clearance. In addition, each label has an associated property that
indicates the fraction of the label area that can extend outside the map
boundary before it is not drawn. The procedure takes all of these
properties into account to move labels to acceptable positions or to not
draw the label.

[0035] The following discussion concerns only those geometric objects in
the plane of the map, of which the labels are a part. All labels are
restricted to convex planar polygons in this plane. A planar polygon is
convex if it contains all the line segments connecting any pair of its
points. If two convex planar polygons overlap, this means that:

[0036]
1) at least one vertex of one polygon is inside the other polygon, or

[0037] 2) at least one edge of one polygon crosses or touches (i.e.,
intersects) an edge of the other polygon.

[0038] To begin the anti-collision procedure, three initialization steps
occur. First, labels lying partially inside the map boundary must either
be moved completely inside the portrait or be excluded from being
compared to other labels and excluded from being drawn. Each label has
movement types and constraints that determine whether or not the label
qualifies for movement completely onto the map. These movement types and
constraints are explained below. Labels qualifying for movement to the
inside of the map are moved regardless of the collision status with any
other label.

[0039] Second, the labels must be ordered in a list with respect to
priority from highest priority to lowest priority. In general, many
labels will have the same priority. Within any group of labels with the
same priority, any particular label is randomly placed within that block.

[0040] Third and last, variables that monitor the state of the procedure
must be initialized.

[0041] The purpose of routine 10 is to move labels within the map
boundary. If too much of a label is outside the boundary, it will not be
included in the map. Each label is tested to determine what fraction of
its area is within the map boundary.

[0042] At routine 20, labels are sorted in order of descending priority.
Halting criteria parameters are initialized at routine 30.

[0043] Every combination of two labels is tested for overlap in routine
40. When comparing labels to determine if they overlap, it is important
to choose the order of comparison properly to avoid excessive calculation
and moving labels more times than necessary. The highest priority labels
should be tested for overlap before labels of lower priority.

[0044] The overlap test at routine 45 has three parts. First, it must be
determined if any vertex of a first label is inside the second label.
Second, it must be determined if any vertex of a second label is inside
the first label. Third, it must determine if any edge of the first label
intersects any edge of the second label. If at any point either label is
determined to overlap the other label, then any remaining parts are
bypassed.

[0045] Labels are moved about the map at routine 50 to clear existing
label collisions. After it is determined that two labels overlap, the
routine finds several new locations for the lower priority of the two
labels that eradicate the existing overlap. These locations are ranked by
how far the label must be moved, shortest to longest. Then if
appropriate, the lower priority is moved to a new location, and its
location parameters are adjusted.

[0046] The evaluation function, routine 60, quantifies the extent of label
collisions. Routines 40, 45, 50, and 60 iterate until halt routine
criteria 70 are satisfied. Labels may move several times before the
iterations stop.

[0047] After the iterations stop, all labels are examined for any overlap
and label properties are adjusted at routine 80. Finally, control is
returned at routine 90 to the user to draw or view the map.

[0048] FIGS. 4a, 4b, and 4c display the logic of routine 10 in detail. The
purpose of routine 10 is to make sure all of a label is within the map
boundary. If too much of a label is outside the boundary, it will not be
included in the map. Each label is tested to determine what fraction of
its area is within the map boundary. A particular label is divided into a
grid; 32 by 32 cells is a typical division that works well in practice.
If the centroid of a cell is within the map boundary, the entire cell
contributes to the fraction of the label within the boundary. The areas
of each cell within the map are added to together. If this sum of cell
areas, divided by the total label area, is greater than a predetermined
value, then the label is moved entirely onto the map according to the
movement procedure and the movement constraints described below. The only
change to the procedure is that there is no test for overlap with other
labels. The qualifying labels are moved onto the map at this time and
tested later.

[0049] Step 100 obtains a list of labels from data storage. Each label is
tested for whether the entire label is inside the map boundary. First,
step 108 initializes flags that will be used in routine 10. Step 112
tests whether vertices of each label are outside the map boundary. If the
vertices of a label are all inside the map boundary, then the next label
is tested. If any vertices of a label are outside the map boundary, then,
at step 116, a circumscribing rectangle is placed around the label. Then
the circumscribing rectangle is divided into a plurality of cells at step
120. For example, the rectangle may be divided into 64 cells by 64 cells
forming a total of 4096 cells.

[0050] Each cell is tested, step 124. The test includes finding the center
point of each cell to find the number of cells inside the label, step
128. Then, at step 132, the center point of each cell used to find the
number of cells both inside the label and inside the map.

[0051] The fraction of the label inside the map boundary is determined at
step 136. The high and the low values of the x and y coordinates for the
vertices of the label are found in step 140. Then the label is tested,
step 144, to determine if the fraction of the label inside the map
boundary is high enough to qualify for attempted movement inside the map.
There is one of two possible ways the label might move depending on its
movement constraints, which is determined in step 148. One movement, in
both the x-axis and y-axis direction, is performed in steps 152, 156,
160, 164, and 168. In step 152, the x-axis and y-axis movement of the
label in the plane of the map (2D type movement) is initialized to (0,0).
In step 156, the minimum 2D type movement to move the entire label within
the map is determined (see the following pseudo-code for Routine 10 which
shows how to determine the minimum 2D type movement).

[0052] In step 160, the maximum allowed 2D movement parameter for the
label from its original position is compared to the minimum 2D type
movement. In step 164, it is determined if the label fits within the map
boundary after the label has been moved by the minimum 2D movement. This
is really a test to see if the label is too big to fit in the map. In
step 168, if the label can fit in the map, a label flag and a label
parameter are set.

[0053] The other movement, restricted to a vector, is performed in steps
172, 176, 180, 184, and 188. In step 172, the vector type label movement
candidates(s) to move the label within the map is determined (see the
following pseudo-code for Routine 10 which shows how to determine the
minimum vector movement). In step 176, a loop cycles through candidate(s)
for the label which are determined in step 172. In step 180, if the
maximum allowed vector movement parameter for the label from its original
position is less than the magnitude of the current candidate for the
label, go to step 176. Otherwise, go to step 184. In step 184, if the
label does not fit within the map boundary after the label has been moved
by the current candidate, go to step 176. This is really a test to see if
the label is too big to fit in the map. Otherwise, go to step 188. In
step 188, if the label can fit in the map, a label flag and a label
parameter are set. If the label is partially or totally outside the map,
and cannot be properly moved within the map, which is checked in step
192, then a parameter for that label is set in step 196.

[0054] Once all labels have been tested, step 104 exits routine 10 and
proceeds to routine 20.

[0055] Referring to FIG. 5, labels are sorted by priority at step 200 from
the highest priority label to the lowest priority label and placed into a
data structure map. Step 210 exits routine 20 and proceeds to routine 30,
an initialization of halting criteria variables.

[0056] In FIG. 6, step 300 initializes halting criteria variables. Step
310 exits routine 30 and proceeds to routine 40, a test of every
combination of two labels for overlap.

[0057] The above-described logic is further shown in the following
pseudo-code with comments:

TABLE-US-00001
PULL IN THE LABELS FROM THE EDGES OF THE MAP ROUTINE
//Pseudo-code for the Initialization of the Anti-collision Procedure
for Maps
//List of pseudo-code variables
previous_collision_score - the collision score from the previous
iteration
previous_previous_collision_score - the collision score from two
iterations ago
iteration_count - number of times the anti-collision procedure has
looped
slow_change_count - number of iterations of continuous slow change of
collision score
oscillation_count - number of iterations of continuous oscillation of
collision score
priority_of_most_important_label - numerical priority value of the most
important label
priority_range - the difference between the priority of the least and
the most important labels. This number is non-negative.
frac_inside - fraction of label inside the map boundaries
map_x_size - the number of x units in the map - map boundary is a
rectangle
map_y_size - the number of y units in the map - map boundary is a
rectangle
(xMove2D, yMove2D) - the label movement if the label qualifies for
movement completely inside the map boundary and the label parameters
specify 2D type movement
(xMoveVec[ ], yMoveVec[ ]) - an array of label movements if the label
qualifies for movement completely inside the map boundary and the label
parameters specify vector type movement
(xc, yc) - center point of a cell formed from a grid within the
circumscribing rectangle around the label
(x_IP, y_IP) - a point satisfying various conditions used to properly
move a label completely inside the map boundary
LABEL_TOO_MUCH_OUTSIDE_PORTRAIT - indicates if the
procedure has determined that the label has much area outside the
map boundary or can not be properly moved to a new position completely
inside the map boundary. This is a flag of every label set by the
procedure.
LABEL_OUTSIDE_PORTRAIT - Not used. This is a flag of every label
set by the procedure.
LABEL_MOVED_INTO_PORTRAIT - indicates if the procedure has
moved a label that was originally partially outside the map boundary to a
new position completely inside the map boundary. This is a flag of every
label set by the procedure.
LABEL_MIN_FRACTION_INSIDE - minimum fraction of the label
that must be inside the map boundary to attempt relocation completely
inside the map boundary. This is a parameter of every label set by caller.
LABEL_NEW_LOCATION - A vector (x, y) which is added to all
vertices of a label if the procedure moves the label. This vector has an
initial value of (0, 0). This is a parameter of every label determined by
the
procedure.
// pseudo-code also has:
// a list of possible label movement candidates to pull the label
inside the map boundary
// a data structure map of labels and their properties sorted by
priority from the most
// important label to the least important label
------------------------------------------------------------
// THIS IS THE START OF ROUTINE 10
// The labels are not in any particular order at this point.
// They are only in the order in which they are received from the
caller.
for i = first unordered label to last unordered label
set label i flag LABEL_OUTSIDE_PORTRAIT = FALSE
set label i flag LABEL_TOO_MUCH_OUTSIDE_PORTRAIT =
FALSE
set label i flag LABEL_MOVED_INTO_PORTRAIT = FALSE
set label i parameter LABEL_NEW_LOCATION = (0, 0)
// Determine if the label is inside or outside the map boundary.
// If all vertices are inside, then the entire label is inside.
// Here, a vertex on the map boundary is inside the boundary.
label_inside_map = TRUE
for j = first vertex of label i to last vertex of label i
if ( vertex j outside map boundary ) {
label_inside_map = FALSE
}
next j
if ( label_inside_map = FALSE ) {
// Below, find the approximate fraction of the label inside the map
boundary.
// The circumscribing rectangle has edges parallel to the map edges.
// Note that both the rectangle and the label are convex polygons.
Put a circumscribing rectangle around label i
Divide the circumscribing rectangle into 64 units by 64 units forming
4096 cells
in_label = 0
in_label_and_map = 0
for k = first cell to last cell
Find center point of cell k called (xc, yc)
// Here, a point on a label edge or map boundary is inside the label
or map.
// Use the "point inside convex polygon" procedure described in the
// labels overlap section.
if( (xc, yc) inside label ) {
in_label = in_label + 1
if( (xc, yc) inside map boundary ) {
in_label_and_map = in_label_and_map + 1
}
}
next k
frac_inside = ( in_label_and_map )/( in_label )
// Move the label inside the map boundary if enough of the label is
inside.
// Some of the vertices below may be the same vertex.
(x_low, yL) = coordinates of vertex with lowest x coordinate
(x_high, yH) = coordinates of vertex with highest x coordinate
(xL, y_low) = coordinates of vertex with lowest y coordinate
(xH, y_high) = coordinates of vertex with highest y coordinate
// find the new location for the label
if ( frac_inside > LABEL_MIN_FRACTION_INSIDE parameter
of label i ) {
if ( 2D type movement for label i ) {
(xMove2D, yMove2D) = (0, 0)
// If both conditions are true, the label will not fit into the
map.
if ( x_low < 0 ) {
xMove2D = 0 - x_low
}
else if ( x_high > map_x_size - 1 ) {
xMove2D = map_x_size - 1 - x_high
}
// If both conditions are true, the label will not fit into the
map.
if ( y_low < 0 ) {
yMove2D = 0 - y_low
}
else if ( y_high > map_y_size - 1 ) {
yMove2D = map_y_size - 1 - y_high
}
// Determine if the label is still within its movement parameters.
// This means has the label moved too far from its original
position.
// The original location parameter is never changed. It does not
Change
// because it is always used for comparison to the new position.
if ( (xMove2D, yMove2D) within label i 2D type movement
parameters
) {
// Determine if the label is still inside the map boundary after
movement.
// This is really a test to see if the label is too big to fit in
the map.
// Here, a vertex on the map boundary is not outside the map.
// This test works because both label and map are convex polygons.
for j = first vertex of label i to last vertex of label i
label_moved_outside_map = FALSE
if ( ( vertex j + (xMove2D, yMove2D) ) of label i is outside map
boundary ) {
label_moved_outside_map = TRUE
}
next j
if ( label_moved_outside_map = FALSE ) {
set label i flag LABEL_MOVED_INTO_PORTRAIT = TRUE
set label i parameter LABEL_NEW_LOCATION =
(xMove2D, yMove2D)
}
}
}
else { // vector type movement
count = 0
// If both conditions are true, the label will not fit into the
map.
if ( x_low < 0 ) {
find a point (x_IP, y_IP) which meets the following requirements
contained by a line parallel to the vector type movement
contained by a the line x = 0
contained by a line also containing (x_low, yL)
if ( (x_IP, y_IP) exists ) {
xMoveVec[count] = x_IP - x_low
yMoveVec[count] = y_IP - yL
place in list of possible label movement candidates
count = count + 1
}
}
else if ( x_high > map_x_size - 1 ) {
find a point (x_IP, y_IP) which meets the following requirements
contained by a line parallel to the vector type movement
contained by a the line x = map_x_size - 1
contained by a line also containing (x_high, yH)
if ( (x_IP, y_IP) exists ) {
xMoveVec[count] = x_IP - x_high
yMoveVec[count] = y_IP - yH
place in list of possible label movement candidates
count = count + 1
}
}
// If both conditions are true, the label will not fit into the map.
if ( y_low < 0 ) {
find a point (x_IP, y_IP) which meets the following requirements
contained by a line parallel to the vector type movement
contained by a the line y = 0
contained by a line also containing (xL, y_low)
if ( (x_IP, y_IP) exists ) {
xMoveVec[count] = x_IP - xL
yMoveVec[count] = y_IP - y_low
place in list of possible label movement candidates
count = count + 1
}
}
else if ( y_high > map_y_size - 1 ) {
find a point (x_IP, y_IP) which meets the following requirements
contained by a line parallel to the vector type movement
contained by a the line y = map_y_size - 1
contained by a line also containing (xH, y_high)
if ( (x_IP, y_IP) exists ) {
xMoveVec[count] = x_IP - xH
yMoveVec[count] = y_IP - y_high
place in list of possible label movement candidates
count = count + 1
}
}
// Can have zero, one, or two possible label movement candidates
for k = 0 to (count - 1)
// Determine if the label is still within its movement parameters.
// This means has the label moved too far from its original
position.
// The original location parameter is never changed. It does not
Change
// because it is always used for comparison to the new position.
move_distance = magnitude of (xMoveVec[k], yMoveVec[k])
if ( move_distance within label i vector type movement
parameters
) {
// Determine if the label is still inside the map boundary after
movement.
// This is really a test to see if the label is too big to fit in
the map.
// Here, a vertex on the map boundary is not outside the map.
// This test works because both label and map are convex
polygons.
for j = first vertex of label i to last vertex of label i
label_moved_outside_map = FALSE
if(( vertex j + (xMoveVec[k], yMoveVec[k])) of label i is
outside map boundary) {
label_moved_outside_map = TRUE
}
next j
if ( label_moved_outside_map = FALSE ) {
set label i flag LABEL_MOVED_INTO_PORTRAIT = TRUE
set label i parameter LABEL_NEW_LOCATION =
(xMoveVec[k], yMoveVec[k])
break out of loop // go past next k
}
}
next k

} // end of vector type movement
}
if ( label i flag LABEL_MOVED_INTO_PORTRAIT = FALSE ) {
set label i flag LABEL_TOO_MUCH_OUTSIDE_PORTRAIT =
TRUE
}
} // end if label_inside_map = FALSE
next i
// THIS IS THE START OF ROUTINE 20
// Sort the labels by priority.
// The labels with the highest priorities have the lowest numbers.
// Priorities may be negative numbers.
// Labels may have the same priority.
// After this loop, assume all labels are ordered properly.
Sort labels by priority from the most important label to the least
important label
and place into a data structure map
// THIS IS THE START OF ROUTINE 30
// Initialize halting criteria variables
priority_range = priority_of_least_important_label -
priority_of_most_important_label
// initialize these two variables to large numbers
previous_collision_score = Very Large Number
previous_previous_collision_score = Very Large Number
iteration_count = 0
slow_change_count = 0
oscillation_count = 0

[0058] Referring to FIGS. 7a and 7b, labels are compared to determine if
they overlap (routine 40). The number of labels and the maximum numerical
difference between the highest and lowest priority labels is determined
in step 400. All labels are grouped according to priority.

[0059] In step 403, a loop cycles through all the priorities from the
highest priority (i.e. priority 0) to the lowest priority of the labels
(i.e. priority last_Pri), for every integer from 0 to last_Pri. In step
406, it is determined if there are any labels corresponding to the
current priority in the loop. If there are no labels with the current
priority of the loop, then in step 409, set the value of array
first_label[current priority of loop] to -1 and set the value of the
array last label [current priority of loop] to -1. If there are labels
with the current priority of the loop, then in step 412, set the value of
array first_label [current priority of loop] to the index of the most
important label with priority p and set the value of the array last_label
[current priority of loop] to the index of the least important label with
priority p.

[0060] It is important to choose the order of comparison properly to avoid
excessive calculation and moving labels more times than necessary. Steps
415, 421, 424, 427, 430, 436, and 442 perform cycling through label
pairs. This part compares two labels using loops. In step 415, the loop
for the first label starts at priority 0 and goes to priority last_Pri.
In step 421, if the value of the variable:

[0061] first label [current priority of first loop]

is equal to -1, then go back to the beginning of loop for the first
label. Otherwise, go to step 424.

[0062] In step 424, the loop for the second label starts at the current
priority of the first loop and goes to priority `last_Pri.` In step 427,
if the value of the variable:

[0063] first label [current priority of second loop]

is equal to -1, then go back to the beginning of loop for the second
label. Otherwise, go to step 430.

[0064] In step 430, a third loop starts at the index in the list of labels
of the first label with a priority equal to the current priority of the
first loop and goes to the index in the list of labels of the last label
with a priority equal to the current priority of the first loop. In step
433, if the label with the current index in the list of labels from the
loop in step 430 is completely outside of the map or too much of the
label is outside of the map, then go back to step 430. Otherwise, go to
step 436.

[0065] In step 436, a fourth loop starts at the index in the list of
labels of the first label with a priority equal to the current priority
of the second loop and goes to the index in the list of labels of the
last label with a priority equal to the current priority of the second
loop. When step 436 has finished examining the relevant labels, then step
436 returns to step 430. As discussed above, when step 430 has finished
examining the relevant labels, then step 430 returns to step 424. If step
426 has not finished examining the relevant labels, then proceed to step
439. In step 439, if the label with the current index in the list of
labels from the loop in step 436 is completely outside of the map or too
much of the label is outside of the map, then go back to step 436.
Otherwise, go to step 442. In step 442, if the current label index of the
loop in step 430 is less than or equal to the current label index of the
loop in step 436, then go to step 436. Otherwise, go to step 445.

[0066] Step 445, which corresponds to routine 45, tests for overlap
between the members of the pair. Step 448, which corresponds to routine
50, performs the movement procedure on one of the labels if they overlap.
Step 418 exits routine 40 and proceeds to routine 60, an evaluation
function procedure.

[0067] The above-described logic is further shown in the following
pseudo-code with comments:

TABLE-US-00002
Order of Comparison for the Label Overlap Test Routine
// The n labels have already been sorted in priority order,
// from the most important, label 0, consecutively,
// to the least important, label (n - 1).
LABEL_TOO_MUCH_OUTSIDE_PORTRAIT - indicates if the procedure has
determined that the label has much area outside the map boundary or can
not be properly moved to a new position completely inside the map
boundary. This is a flag of every label set by the procedure.
LABEL_OUTSIDE_PORTRAIT - Not used. This is a flag of every label set by
the procedure.
LABEL_MOVED_INTO_PORTRAIT - indicates if the procedure has moved a
label that was originally partially outside the map boundary to a new
position completely inside the map boundary. This is a flag of every
label set by the procedure.
last_Label_Index = number_of_labels - 1; // zero based
// Zero based.
// The highest priority is zero and the lowest priority is a number
greater than zero.
// Note that there may be priorities which have no labels.
Last_Pri = lowest priority - highest priority; // which equal the
lowest priority
// Below, if there are no labels with priority p,
// first_Pri[p] = -1 and last_Pri[p] = -1
// first_label[p] = first label index with priority p
// last_label[p] = last label index with priority p
for p = 0 to last_Pri; // highest priority to lowest priority
if labels with priority p exist
first_label[p] = most important label with priority p;
last_label[p] = least important label with priority p;
Else
first_label[p] = -1;
last_label[p] = -1;
next p;
for i_pri = 0 to last_Pri; // highest priority to lowest priority
if first_label[i_pri] = -1, continue to next i_pri;
for j_pri = i_pri to last_Pri; // highest priority to lowest priority
if first_label[j_pri] = -1, continue to next j_pri;
for i_idx = first_label[i_pri] to last_label[i_pri];
if i_idx flag LABEL_TOO_MUCH_OUTSIDE_PORTRAIT = TRUE OR
LABEL_OUTSIDE_PORTRAIT = TRUE, continue to next i_idx
for j_idx = first_label[j_pri] to last_label[j_pri];
// Do not compare a label to itself or
// compare labels which have been previously compared,
// for this particular iteration of the entire algorithm.
if i_idx <= j_idx, continue to next j_idx;
if j_idx flag LABEL_TOO_MUCH_OUTSIDE_PORTRAIT = TRUE OR
LABEL_OUTSIDE_PORTRAIT = TRUE, continue to next j_idx
if label i_idx overlaps label j_idx,
then perform the label movement procedure on label j_idx;
next j_idx;
next i_idx;
next j_pri;
next i_pri;

[0068] All labels are restricted to convex planar polygons in the plane of
the map. A planar polygon is convex if it contains all the line segments
connecting any pair of its points. If two convex planar polygons overlap,
this means that:

[0069] 1) at least one vertex of one polygon is inside
the other polygon, or

[0070] 2) at least one edge of one polygon
intersects an edge of the other polygon.

[0071] Routine 45, shown in FIG. 8, is a label overlap test procedure. The
overlap test has three parts. First, it determines if any vertex of the
first polygon is inside the second polygon, step 462. Second, it
determines if any vertex of the second polygon is inside the first
polygon, step 466. Third, it determines if any edge of the first polygon
intersects any edge of the second polygon, step 470. Once any vertex is
found to be inside the other polygon, there is no need to test remaining
vertices and edges. Once any edge is found to intersect any edge of the
other polygon, there is no need to test remaining edges and vertices.

[0072] Prior to the overlap test, routine 45 begins by receiving two
labels from caller in step 450. In step 454, the maximum and minimum x
and y values for each label are determined. These x and y values form
circumscribing rectangles, whose edges are parallel to the map's x axis
and y axis, for each label. In step 458, the circumscribing rectangles
for each label are compared. If these circumscribing rectangles do not
overlap, then routine 45 returns "no overlap" to the caller in step 478.

[0073] FIG. 8 shows the test for whether a vertex of a polygon is inside
another polygon. The method is shown in "Determining if a Point Lies on
the Interior of a Polygon," Paul Bourke (available on the world wide
web). Consider the standard right-handed two-dimensional Cartesian
coordinate system with the positive y direction up and the positive x
direction to the right. A first polygon's edges are chosen such that the
perimeter is traversed in the counterclockwise (CCW) direction (the
perimeter may be traversed in a clockwise direction so long as it is done
consistently). At step 462, if any vertex of a second polygon is to the
left of all edges of the first polygon, then that vertex is inside the
first polygon. Likewise, at step 466, if any vertex of the first polygon
is to the left of all edges of the second polygon then that vertex is
inside the second polygon. If any vertex of a polygon is inside another
polygon, then the polygons overlap. This is the test for a point being
inside a convex planar polygon.

[0074] Lines containing the edges that make up a polygon may be written,

(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)=0

where (x,y) is any point on the line, and (X1,Y1) and (X2,Y2) are the
endpoints of an edge of the polygon under test. Points lying on the
polygon edges satisfy the line equations, while points not on the polygon
edges do not satisfy those equations. If (x, y) is any point in the
plane, the equation for a line containing an edge is:

(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)=K

where K is a real number constant.

[0075] Then, for all points to the left of any edge, K>0, and for all
points to the right of any edge, K<0. Note that point 2 in the above
equation is at the head of the vector representing the edge and point 1
is at the tail of the vector representing edge. This is true because, for
all edges pointing to the right, (X2-X1)>0. For any point above the
line containing the edge, (x_above, y_above), there exists a point,
(x,y), on the line, such that:

x_above=x and y_above>y

Therefore:

(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)=(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)

(y_above-Y1)(X2-X1)-(x-X1)(Y2-Y1)>(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)

(y_above-Y1)(X2-X1)-(x_above-X1)(Y2-Y1)>(y-Y1)(X2-X1)-(x-X1)(Y2-Y1)

[0076] A point that is above a line pointing to the right is a point that
lies to the left of the line. Similar arguments show that any point on
the left of lines pointing up, pointing down, or pointing left yields a
positive value with substituted into the line equation.

[0077] Step 470 tests whether the edges of one polygon intersect another
polygon. Consider the equations of the lines that contain the edges of
the first polygon and the equations of the lines that contain the edges
of the second polygon. Determine the intersection point for every
two-line combination, where one line is a line that contains an edge of
the first polygon and the other line is a line that contains an edge of
the second polygon. If the intersection point lies on or between the
endpoints of the polygon edges, then the edge of one polygon intersects
the edge of the other polygon and the polygons overlap. In cases where
the lines are parallel, and not coincident, no intersection point exists
for that pair of lines. If the lines are coincident, then the edges may
or may not touch, but if the edges touch then the polygons overlap.

[0078] If the three above overlap tests, at step 462, step 466, step 470,
find an overlap between the two labels, then routine 45 returns "labels
overlap" to the caller in step 482, step 486, and step 490, respectively.
If after performing the three tests, there is no overlap between the two
labels, then routine 45 returns "no overlap" to the caller in step 474.

[0079] The above-described logic is further shown in the following
pseudo-code with comments:

TABLE-US-00003
Pseudo-code for the Overlap Test of Convex Planar Polygons
List of pseudo-code variables
(x_2_i, y_2_i) - vertex i of polygon 2
(X1_j, Y1_j) - vertex 1 of edge j of polygon 1
(X2_j, Y2_j) - vertex 2 of edge j of polygon 1
(x_IP, y_IP) - intersection point of lines containing edges
x_max_i - max x of edge i
y_min_j - min y on edge j
find max x, max y, min x, min y on polygon 1 - each will be on a
Vertex
find max x, max y, min x, min y on polygon 2 - each will be on a
vertex
// if any expression is true, the polygons do not overlap, so return
False
if (min x of polygon 1 >= max x of polygon 2) RETURN NO_OVERLAP
if (min x of polygon 2 >= max x of polygon 1) RETURN NO_OVERLAP
if (min y of polygon 1 >= max y of polygon 2) RETURN NO_OVERLAP
if (min y of polygon 2 >= max y of polygon 1) RETURN NO_OVERLAP
// if any vertex of polygon 2 is inside polygon 1, the result is
greater than zero.
// proceed around polygon 1 in the CCW direction for each vertex of
polygon 2
for i = first vertex of polygon 2 to last vertex of polygon 2
inside = TRUE
for j = first edge of polygon 1 to last edge of polygon 1 in CCW
Direction
if((y_2_i - Y1_j)(X2_j - X1_j) - (x_2_i - X1_j)(Y2_j -
Y1_j) <= 0)
inside = FALSE
next j
if (inside = TRUE), RETURN OVERLAP
next i
Repeat the above, except test polygon 1 vertices with polygon 2 edges
Return OVERLAP if appropriate
// perform the edge intersection test
for i = first edge of polygon 1 to last edge of polygon 1
of the two endpoints of edge i, get x_max_i, y_max_i,
x_min_i, y_min_i
for j = first edge of polygon 2 to last edge of polygon 2
of the two endpoints of edge j, get x_max_j, y_max_j, x_min_j,
y_min_j
solve for intersection point, (x_IP, y_IP), of lines containing edge
i and edge j
if intersection point exists
// An intersection at an endpoint is an overlap.
// These tests also take care vertical and horizontal edges.
if (x_IP <= x_max_i and x_IP >= x_min_i) and
(y_IP <= y_max_i and y_IP >= y_min_i) and
(x_IP <= x_max_j and x_IP >= x_min_j) and
(y_IP <= y_max_j and y_IP >= y_min_j), RETURN
OVERLAP
next j
next i
RETURN NO_OVERLAP

[0080] Labels must be moved about the map to clear existing label
collisions. After it is determined that two labels overlap, routine 50
(FIGS. 9a, 9b, and 9c) finds several new locations for the lower priority
of the two labels that eradicate the existing overlap. The higher
priority label is a first label while a lower priority label is a second
label. These locations are ranked by how far the second label must be
moved, shortest to longest. The actual location finally selected must
meet the following criteria:

[0081] 1) the second label moves a shorter
distance than other qualifying locations;

[0082] 2) the second label
movement does not result in overlap with another label (or labels) of
equal or higher priority than the first label;

[0083] 3) the second label
movement does not exceed the maximum movement parameters

[0084] 4) for
that particular label; and

[0085] 5) no part of the second label is moved
outside the map boundary.

[0086] If no candidate locations meet these criteria, the second label is
not moved. During the process of fixing existing collisions, other
collisions may be created. New collisions are only allowed if it reduces
collisions among labels with priorities equal to or higher than the first
label. As the procedure iterates, new collisions are handled like the
original collisions. The procedure will minimize collisions.

[0087] Each label may be moved in one of two ways. A caller selects the
type of movement of a label to the exclusion of the other type of
movement. First, a label may move in any direction on the map, up to a
maximum distance from the original location. This is referred to as 2D
type movement. Second, a label may move parallel to a vector up to a
maximum distance from the original location in the positive vector
direction or the negative vector direction. This is referred to as vector
type movement that may be used for linear features such as highways and
rivers. Both the vector and the maximum distances are in the label's
parameter list. Labels on a map may consist of any mixture of 2D movement
and vector movement types. However, higher priority labels must be
examined before lower priority labels regardless of movement type.

[0088] Prior to the attempted label movement, routine 50 begins by
receiving two labels from caller in step 500. Routine 50 cycles through
the edges of first label in step 503 and cycles through the vertices of
second label in step 509. A counter is set in step 506.

[0089] The first label's edges are traversed in a CCW direction.
Remembering that these operations take place on a two dimensional map,
step 512 tests whether each vertex of the second label is left of a line
containing an edge of the first label when the first label is traversed
in a CCW direction. A vertex of the second label is said to be on a label
side of the line containing the edge of the first label if the vertex of
the second label and area of the first label are on the same side of the
line containing the edge of the first label. Note that these labels are
restricted to convex polygons so all of one label will be on one side of
the line containing the label's edge and no part of the label will be on
the other side of the line. Likewise, a vertex of a second convex polygon
is said to be on a convex polygon side of a line containing an edge of a
first convex polygon if the vertex of the second convex polygon and area
of the first convex polygon are on the same side of the line containing
the edge of the first convex polygon. If step 515 specifies a 2D type
movement, then step 518 finds an intersection of two lines. A first line
is the line that contains one edge of the first label. A second line is
perpendicular the first line and contains the vertex. If, instead, step
515 specifies a vector type movement, then step 521 finds an intersection
of a line containing an edge and a line parallel to the vector type
movement also containing the vertex.

[0090] If in either the 2D type movement case or the vector type movement
case, an intersection exists, step 524, and the vertex is on the label
side as defined above, step 527 calculates a first vector from the vertex
to the intersection. If the first vector is too small, step 530, then the
routine 50 calculates, in steps 533, 536, and 539, a second vector with
desirable properties listed in steps 536 and 539. In the case that the
first vector is too small, the first vector is replaced by the second
vector. Whichever vector remains, it is hereafter referred to as the
vector.

[0091] Step 542 tests whether the vector is within movement bounds from
the original label location. If at step 545, it is within bounds, the
vector is placed on an end of a list of qualified vectors and a length of
the vector is placed on an end of a length list. Once all vertices of the
second label are tested, if there any qualified vectors (step 548), then,
at step 551:

[0092] 1) Find the maximum length in the length list and a
corresponding qualified vector from the vector list;

[0093] 2) Insert the
length and the qualified vector into a data structure map that is sorted
by distance; and

[0094] 3) Empty the length list and vector list.

[0095] After all the edges of the first label are checked, at step 554 the
steps starting at step 512 are repeated using the edges of the second
label and the vertices of the first label. For any qualifying vectors, a
negative of the vector is taken and that vector and its length are
inserted into the data structure map.

[0096] Next, tests are performed to determine if proposed locations for
the second label are acceptable. At step 560, starting with a shortest
vector in the data structure map, the second label is moved in both a
direction and a length of the shortest vector to obtain a new location
for the second label. Then, at step 563, a test is performed to determine
if part of the new location for the second label is outside the map
boundary. If, the new location for the second label places part of the
second label outside the map boundary, repeat steps 557, 560, and 563,
using a next vector from the data structure map. Step 566 retrieves
labels with priorities greater than or equal to the first label. In step
569, if any retrieved label is the first label or the second label, then
retrieve the next label in step 566. At step 572, the overlap test is
performed on the current candidate location for the second label against
labels that fail tests at step 563 and step 569. If there is an overlap,
steps 557 through 572 are repeated. Otherwise, the second label is moved
to the candidate location in step 575. After a new location is found for
the second label among the proposed locations, or after all proposed
locations are determined to be unacceptable, then data structure map is
cleared in step 578, and a next pair of labels is supplied in step 581.

[0097] The above-described logic is further shown in the following
pseudo-code with comments:

TABLE-US-00004
Movement Procedure of Convex Planar Polygons
// List of pseudo-code variables
(x_2_j, y_2_j) - vertex j of polygon 2
(X1_i, Y1_i) - vertex 1 of edge i of polygon 1
(X2_i, Y2_i) - vertex 2 of edge i of polygon 1
(x_IP, y_IP) - intersection point of lines containing edge and vertex
(X,Y) - vector from vertex to edge
pseudo-code also has:
a list of distances
a list of vectors
a data structure map of distances and vectors sorted by distance,
short to long
// Polygon 1 is the more important polygon and polygon 2 will move if
possible
// Here, the vertices in a polygon are on the left side of the edge
// of the other polygon when traversing it in the CCW direction,
// but the vertices are not necessarily inside the other polygon.
// That is why all possibilities are caught in the algorithm below -
// even where no vertex from either polygon is inside the other.
// Do not have to check specifically for the above case.
// If a vertex of polygon 2 is on left side a polygon 1 edge, the
result is greater than zero.
// proceed around polygon 1 in the CCW direction for each vertex of
polygon 2
// Note the the vertex in question does not have to be inside polygon 1
for i = first edge of polygon 1 to last edge of polygon 1 in CCW
Direction
count_of_possible_vertices = 0
for j = first vertex of polygon 2 to last vertex of polygon 2
if((y_2_j - Y1_i)(X2_i - X1_i) - (x_2_j - X1_i)(Y2_i -
Y1_i) > 0)
if (2D type movement for polygon 2)
// a solution will always exist for this case
solve for intersection point, (x_IP, y_IP), of a line containing
edge i
and a line perpendicular to edge i containing (x_2_j, y_2_j)
if (vector type movement for polygon 2)
// a solution might not exist for this case
solve for intersection point, (x_IP, y_IP), of a line containing
edge i
and a line parallel to the vector type movement containing (x_2_j,
y_2_j)
if ( solution exits for (x_IP, y_IP) )
// get vector from vertex to intersection point
(X,Y) = (x_IP - x_2_j, y_IP - y_2_j)
if ( (X,Y) length minute )
if ( 2D type movement for polygon 2 )
find a point (X,Y) which meets the following requirements
on right side of edge i (CCW)
contained by a line perpendicular to edge i
contained by a line also containing (x_IP, y_IP)
a minute distance from (x_IP, y_IP)
else // vector type movement for polygon 2
find a point (X,Y) which meets the following requirements
on right side of edge i (CCW)
contained by a line parallel to the vector type movement
contained by a line also containing (x_IP, y_IP)
a minute distance from (x_IP, y_IP)
// because polygon may move several times, keep the original
location of the label
if ( movement of (X,Y) leaves polygon with movement limit )
// Make vector just a bit larger that the distance to the edge
// so when polygon 2 is moved, it moves just outside the polygon 1
length_of_XY = length of (X, Y) * (1.0 + 1.0e-09)
X = X * (1.0 + 10e-09)
Y = Y * (1.0 + 10e-09)
append length_of_XY to end of distance list
append (X,Y) to end of vector list
count_of_possible_vertices = count_of_possible_vertices + 1
next j
if (count_of_possible_vertices > 0)
find the maximum distance in the distance list
get the corresponding vector to this distance from the vector list
insert the distance and the vector into the data structure map sorted
by distance,
from the shortest distance to the longest distance
empty distance list and vector list
next i
Repeat the above, except use polygon 1 vertices and with polygon 2
Edges
The vector for possible movement, (X,Y), is reversed
Insert the results into the same distance/vector data structure map
// the outer loop is just going thought the sorted data structure map
for i = first location candidate to last location candidate
get new location for polygon by adding vector (X,Y) to each vertex
if ( any part of label outside map boundary ) next i
for j = first label to last label whose priority >= polygon 1
if ( polygon 1 is label j or polygon 2 is label j) next j
if ( polygon 2 in location candidate i overlaps label j ) next i
update polygon 2 location in its parameter list
break out of both for loops
next j
next i
clear the data structure map
get the next pair of labels to be tested for overlap

The Evaluation Function, the Halting Criteria, and the Adjustment of Label
Properties

[0098] The following pseudo-code contains a reminder to initialize
collision scores and priority ranges at the top of the procedure. This is
shown in FIG. 10, assignment 590.

[0099] It is probable that the process of label movement will iterate
indefinitely, therefore halting criteria are needed. An evaluation
function provides input to a halting procedure to stop the process at an
acceptable point. The calculation of the evaluation function is
represented by routine 60 as shown in FIG. 11. All labels that overlap
are known at this point. The procedure used to reduce label collisions is
an iterative process. A collision score is a variable that measures the
severity of collisions of labels in the map. It is initialized to zero in
step 600. Step 605 performs cycling through label pairs. In step 610,
each label of the current pair of labels is tested to see if it has too
much of its area outside the map or if it is completely outside the map.
This avoids unnecessary calculation for labels that will not be used. The
overlap test (routine 45) is performed in step 615. If no overlap occurs
between the two labels being tested, then another unique pair of labels
is fetched in step 605. If overlap occurs, then the collision score is
added to the previous collision score in step 620. The final value of the
collision score is attained after all the unique label pairs have been
tested. In this anti-collision procedure for maps, the evaluation
function at step 620 is:

where the score is the summation over every pair of overlapping labels.
The result of this function is defined as zero if no collisions remain
and greater than zero if any collisions remain. The function penalizes
disproportionately for collisions involving high priority labels. For
instance, a collision involving a high priority label and a low priority
label gets a higher score (worse) than a collision involving two medium
priority labels.

[0100] Routine 70 as shown in FIG. 12 evaluates halting criteria to
determine if the labels are in optimal locations. The iterative process
must halt at some point. A slow change halting criteria is evaluated in
step 700. If the slow change per iteration in the collision score occurs,
the slow change count is incremented by one in step 705. If the slow
change per iteration does not occur, the slow change variable is reset to
zero in step 710. A short-term oscillation halting criteria is evaluated
in step 715. If the short-term oscillation in the collision score occurs,
the short-term oscillation count is incremented by one in step 720. If
the short-term oscillation does not occur, the short-term oscillation
count is reset to zero in step 725. The previous values of the collision
score are stored in step 730. Step 730 also increments the iteration
count by one. Here, an iteration is one cycle of the anti-collision
algorithm that includes routines 40, 45, 50, and 60. Example rules tested
at step 735 to halt the procedure follow:

[0101] 1) the evaluation
function is below a minimum value;

[0102] 2) the number of iterations is
greater than a maximum value;

[0103] 3) the evaluation function changes
less than a minimum percentage of the previous iteration for more than a
set number of iterations; and

[0104] 4) the evaluation function
oscillates for more than a set number of consecutive iterations.

[0105] If none of these conditions is met, the anti-collision algorithm is
repeated in step 740, noting that labels may move several times before
the iterations stop. A label's new position is stored in its parameter
list at the time a label is moved. The original position is always
available in the label's parameter list.

[0106] Routine 80, as shown in FIG. 13, adjusts label properties. At this
point, labels will not be moved because the halting criteria have been
satisfied. However, some labels may still overlap. Routine 80 begins in
step 800 by setting the DRAW flag to TRUE for every label. Step 805
performs cycling through label pairs. In step 810, each label of the
current pair is tested to see if it has too much of its area outside the
map or if it is completely outside the map. This avoids unnecessary
calculation for labels that are not used. Labels that have some or all of
their area outside the map have their DRAW flag set to FALSE in step 815.
The overlap test (routine 45) is performed in step 820 on those label
pairs for which neither have any area outside the map. If no overlap
occurs between the two labels being tested, then another unique pair of
labels is fetched in step 805.

[0107] Otherwise, go to step 825. In step 825, if both labels have MUST
DRAW=TRUE, then go to step 840. Otherwise, go to step 830. In step 830,
if the first label has MUST DRAW=TRUE, then go to step 840. Otherwise, go
to step 835. In step 835, if the second label has MUST DRAW=TRUE, then go
to step 845. Otherwise, go to step 840. In step 840, the second label has
its draw flag set to DRAW=FALSE. In step 845, the first label has its
draw flag set to DRAW=FALSE. Here, the first label is higher on the list
of labels than the second label.

[0108] These flags are in the label's parameter list. The MUST DRAW flag
is set by the caller. If the DRAW flag is true, this procedure will draw
the label. If the DRAW is false, this procedure will not draw the label.
For any pair of overlapping labels, the following somewhat arbitrary
rules determine the final state of a label's DRAW flag:

[0109] 1) If
one label has MUST DRAW=TRUE, that label sets DRAW=TRUE, and the second
label sets DRAW=FALSE.

[0110] 2) If both labels have MUST DRAW=TRUE, the
label higher on the list of label priority sets DRAW=TRUE, and the other
label sets DRAW=FALSE. Note that this will hold for labels of equal
priority.

[0111] 3) If neither label has MUST DRAW=TRUE, the label higher
on the list of label priority sets DRAW=TRUE, and the other label sets
DRAW=FALSE. Note that this will hold for labels of equal priority.

[0112] The label priority list and the overlap test are described in
preceding sections of the description of the entire anti-collision
procedure.

[0113] After label properties are adjusted, control is returned to the
caller, in step 900 of FIG. 14.

[0114] The above-described logic is further shown in the following
pseudo-code with comments.

Pseudo-code for the Evaluation Function, the Halting Criteria, and the
Adjustment of Label Properties

[0116] While the particular SYSTEM AND METHOD FOR LABELING MAPS as herein
shown and described in detail is fully capable of attaining the
above-described objects of the invention, it is to be understood that it
is the presently preferred embodiment of the present invention and is
thus representative of the subject matter which is broadly contemplated
by the present invention, that the scope of the present invention fully
encompasses other embodiments which may become obvious to those skilled
in the art, and that the scope of the present invention is accordingly to
be limited by nothing other than the appended claims, in which reference
to an element in the singular means "at least one". All structural and
functional equivalents to the elements of the above-described preferred
embodiment that are known or later come to be known to those of ordinary
skill in the art are expressly incorporated herein by reference and are
intended to be encompassed by the present claims. Moreover, it is not
necessary for a device or method to address each and every problem sought
to be solved by the present invention, for it to be encompassed by the
present claims. Furthermore, no element, component, or method step in the
present disclosure is intended to be dedicated to the public regardless
of whether the element, component, or method step is explicitly recited
in the claims.