[cairo-commit] roadster/src animator.h, 1.2, 1.3 db.c, 1.34, 1.35 db.h, 1.15, 1.16 downloadmanager.c, 1.2, 1.3 glyph.h, 1.7, 1.8 import_tiger.c, 1.24, 1.25 locationeditwindow.c, 1.3, 1.4 locationeditwindow.h, 1.2, 1.3 main.c, 1.33, 1.34 mainwindow.c, 1.52, 1.53 mainwindow.h, 1.13, 1.14 map.c, 1.55, 1.56 map.h, 1.27, 1.28 map_draw_cairo.c, 1.29, 1.30 map_draw_gdk.c, 1.28, 1.29 map_hittest.c, 1.2, 1.3 map_hittest.h, 1.1, 1.2 map_math.c, 1.3, 1.4 map_math.h, 1.2, 1.3 map_tilemanager.c, 1.2, 1.3 map_tilemanager.h, 1.1, 1.2 mapinfowindow.c, 1.1, 1.2 search_city.h, 1.1, 1.2 search_location.h, 1.3, 1.4 search_road.h, 1.2, 1.3 test_poly.c, 1.2, 1.3 util.c, 1.17, 1.18 util.h, 1.17, 1.18

Ian McIntosh commit at pdx.freedesktop.org
Mon Oct 17 20:05:28 PDT 2005


Committed by: ian

Update of /cvs/cairo/roadster/src
In directory gabe:/tmp/cvs-serv7805/src

Modified Files:
	animator.h db.c db.h downloadmanager.c glyph.h import_tiger.c 
	locationeditwindow.c locationeditwindow.h main.c mainwindow.c 
	mainwindow.h map.c map.h map_draw_cairo.c map_draw_gdk.c 
	map_hittest.c map_hittest.h map_math.c map_math.h 
	map_tilemanager.c map_tilemanager.h mapinfowindow.c 
	search_city.h search_location.h search_road.h test_poly.c 
	util.c util.h 
Log Message:
	* configure.ac: Added -Wall compiler option (show all warnings).
	* src/map_draw_cairo.c: The return of Cairo!  Now drawing from tile data and using bounding box overlap tests.
	* src/map_hittest.c: The return of hittesting!
	* src/db.c: Remove dead code.
	* src/downloadmanager.c: Properly return a value from a GnomeVFS callback.
	* src/import_tiger.c: Switch from GPtrArrays to GArrays for points.
	* src/main.c: Properly include libintl.h
	* src/map.c: Cleanups.  Dead code removal.
	* src/map_draw_gdk.c: Add random road segment color option for debugging.
	* src/map_math.c: Added polygon clipping and line stitching.
	* src/map_tilemanager.c: Do basic line stitching at load time.
	* src/mainwindow.c: Cleanups.  Move some code to util.c
	* src/util.c: Receive some code from mainwindow.c


Index: animator.h
===================================================================
RCS file: /cvs/cairo/roadster/src/animator.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- animator.h	25 Sep 2005 19:02:37 -0000	1.2
+++ animator.h	18 Oct 2005 03:05:25 -0000	1.3
@@ -36,6 +36,7 @@
 
 animator_t* animator_new(EAnimationType eAnimationType, gdouble fAnimationTimeInSeconds);
 gdouble animator_get_progress(animator_t* pAnimator);
+gboolean animator_is_done(animator_t* pAnimator);
 void animator_destroy(animator_t* pAnimator);
 
 #endif

Index: db.c
===================================================================
RCS file: /cvs/cairo/roadster/src/db.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- db.c	10 Oct 2005 07:07:36 -0000	1.34
+++ db.c	18 Oct 2005 03:05:25 -0000	1.35
@@ -232,30 +232,6 @@
 	g_free(pszString);
 }
 
-static guint db_count_table_rows(const gchar* pszTable)
-{
-	if(!db_is_connected()) return 0;
-
-	MYSQL_RES* pResultSet;
-	MYSQL_ROW aRow;
-	gchar azQuery[MAX_SQLBUFFER_LEN];
-	guint uRows = 0;
-
-	// count rows
-	g_snprintf(azQuery, MAX_SQLBUFFER_LEN, "SELECT COUNT(*) FROM %s;", pszTable);
-	if(mysql_query(g_pDB->pMySQLConnection, azQuery) != MYSQL_RESULT_SUCCESS) {
-		g_message("db_count_table_rows query failed: %s\n", mysql_error(g_pDB->pMySQLConnection));
-		return 0;
-	}
-	if((pResultSet = MYSQL_GET_RESULT(g_pDB->pMySQLConnection)) != NULL) {
-		if((aRow = mysql_fetch_row(pResultSet)) != NULL) {
-			uRows = atoi(aRow[0]);
-		}
-		mysql_free_result(pResultSet);
-	}
-	return uRows;
-}
-
 /******************************************************
 ** data inserting
 ******************************************************/
@@ -280,7 +256,7 @@
 	return FALSE;
 }
 
-gboolean db_insert_road(gint nLOD, gint nRoadNameID, gint nLayerType, gint nAddressLeftStart, gint nAddressLeftEnd, gint nAddressRightStart, gint nAddressRightEnd, gint nCityLeftID, gint nCityRightID, const gchar* pszZIPCodeLeft, const gchar* pszZIPCodeRight, GPtrArray* pPointsArray, gint* pReturnID)
+gboolean db_insert_road(gint nLOD, gint nRoadNameID, gint nLayerType, gint nAddressLeftStart, gint nAddressLeftEnd, gint nAddressRightStart, gint nAddressRightEnd, gint nCityLeftID, gint nCityRightID, const gchar* pszZIPCodeLeft, const gchar* pszZIPCodeRight, GArray* pPointsArray, gint* pReturnID)
 {
 //	g_assert(pReturnID != NULL);
 	if(!db_is_connected()) return FALSE;
@@ -290,7 +266,7 @@
 	gint nCount = 0;
 	gint i;
 	for(i=0 ; i < pPointsArray->len ;i++) {
-		mappoint_t* pPoint = g_ptr_array_index(pPointsArray, i);
+		mappoint_t* pPoint = &g_array_index(pPointsArray, mappoint_t, i);
 
 		gchar azNewest[40];
 
@@ -699,3 +675,29 @@
 //         " INDEX (LocalFileName))",
 //         NULL);
 }
+
+#ifdef ROADSTER_DEAD_CODE
+// static guint db_count_table_rows(const gchar* pszTable)
+// {
+//     if(!db_is_connected()) return 0;
+//
+//     MYSQL_RES* pResultSet;
+//     MYSQL_ROW aRow;
+//     gchar azQuery[MAX_SQLBUFFER_LEN];
+//     guint uRows = 0;
+//
+//     // count rows
+//     g_snprintf(azQuery, MAX_SQLBUFFER_LEN, "SELECT COUNT(*) FROM %s;", pszTable);
+//     if(mysql_query(g_pDB->pMySQLConnection, azQuery) != MYSQL_RESULT_SUCCESS) {
+//         g_message("db_count_table_rows query failed: %s\n", mysql_error(g_pDB->pMySQLConnection));
+//         return 0;
+//     }
+//     if((pResultSet = MYSQL_GET_RESULT(g_pDB->pMySQLConnection)) != NULL) {
+//         if((aRow = mysql_fetch_row(pResultSet)) != NULL) {
+//             uRows = atoi(aRow[0]);
+//         }
+//         mysql_free_result(pResultSet);
+//     }
+//     return uRows;
+// }
+#endif

Index: db.h
===================================================================
RCS file: /cvs/cairo/roadster/src/db.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- db.h	5 Oct 2005 06:09:36 -0000	1.15
+++ db.h	18 Oct 2005 03:05:25 -0000	1.16
@@ -84,7 +84,7 @@
 void db_disable_keys(void);
 
 gboolean db_insert_city(const gchar* pszName, gint nStateID, gint* pnReturnCityID);
-gboolean db_insert_road(gint nLOD, gint nRoadNameID, gint nLayerType, gint nAddressLeftStart, gint nAddressLeftEnd, gint nAddressRightStart, gint nAddressRightEnd, gint nCityLeftID, gint nCityRightID, const gchar* pszZIPCodeLeft, const gchar* pszZIPCodeRight, GPtrArray* pPointsArray, gint* pReturnID);
+gboolean db_insert_road(gint nLOD, gint nRoadNameID, gint nLayerType, gint nAddressLeftStart, gint nAddressLeftEnd, gint nAddressRightStart, gint nAddressRightEnd, gint nCityLeftID, gint nCityRightID, const gchar* pszZIPCodeLeft, const gchar* pszZIPCodeRight, GArray* pPointsArray, gint* pReturnID);
 
 gboolean db_city_get_id(const gchar* pszName, gint nStateID, gint* pnReturnID);
 gboolean db_state_get_id(const gchar* pszName, gint* pnReturnID);

Index: downloadmanager.c
===================================================================
RCS file: /cvs/cairo/roadster/src/downloadmanager.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- downloadmanager.c	1 Oct 2005 19:09:05 -0000	1.2
+++ downloadmanager.c	18 Oct 2005 03:05:25 -0000	1.3
@@ -144,6 +144,8 @@
 		_downloadmanager_move_pending_to_active(pDownloadManager);
 	}
 	// XXX: what other statuses messages do we care about?  (failed?)
+
+	return 1;	// XXX: added a return value without testing-- is this the right value?
 }
 
 static gboolean _downloadmanager_begin_download(download_t* pDownload)

Index: glyph.h
===================================================================
RCS file: /cvs/cairo/roadster/src/glyph.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- glyph.h	1 Oct 2005 05:24:16 -0000	1.7
+++ glyph.h	18 Oct 2005 03:05:25 -0000	1.8
@@ -41,6 +41,9 @@
 void glyph_init();
 glyph_t* glyph_load_at_size(const gchar* pszName, gint nMaxWidth, gint nMaxHeight);
 glyph_t* glyph_load(const gchar* pszName);
+
+void glyph_reload_all(void);
+
 GdkPixbuf* glyph_get_pixbuf(const glyph_t* pGlyph);
 GdkPixmap* glyph_get_pixmap(glyph_t* pGlyph, GtkWidget* pTargetWidget);
 //void glyph_draw_centered(cairo_t* pCairo, gint nGlyphHandle, gdouble fX, gdouble fY);

Index: import_tiger.c
===================================================================
RCS file: /cvs/cairo/roadster/src/import_tiger.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- import_tiger.c	12 Oct 2005 03:04:05 -0000	1.24
+++ import_tiger.c	18 Oct 2005 03:05:25 -0000	1.25
@@ -100,13 +100,13 @@
 {
 	gint nTLID;		// index- TLID links a complete chain together
 
-	GPtrArray* pPointsArray;
+	GArray* pPointsArray;
 } tiger_record_rt2_t;
 
 void callback_free_rt2(gpointer p)
 {
 	tiger_record_rt2_t* pRT2 = (tiger_record_rt2_t*)p;
-	g_ptr_array_foreach(pRT2->pPointsArray, util_g_free_with_param, NULL);
+	g_array_free(pRT2->pPointsArray, TRUE);
 	g_free(pRT2);
 }
 
@@ -142,7 +142,7 @@
 void callback_free_rti(gpointer p)
 {
 	tiger_record_rti_t* pRTi = (tiger_record_rti_t*)p;
-	g_ptr_array_foreach(pRTi->pRT1LinksArray, util_g_free_with_param, NULL);
+	g_ptr_array_free(pRTi->pRT1LinksArray, TRUE);	// XXX: double check that RTi doesn't own these?
 	g_free(pRTi);
 }
 
@@ -185,80 +185,88 @@
 
 gdouble g_afPolygonMinSizeAtLODs[MAP_NUM_LEVELS_OF_DETAIL] = {0, 0.001, 0.01};	// in world degrees
 
-gint g_aaObjectTypeDetailAtLODs[MAP_NUM_OBJECT_TYPES][MAP_NUM_LEVELS_OF_DETAIL] = {
-	{0,0,0,0},
-	{1,0,0,0},	// minor rd
-	{1,6,0,0},	// major rd
-	{1,6,12,0},	// hw
-	{1,3,0,0},	// hw ramp
-	{0,0,0,0},	// (unused)
-	{0,0,0,0},	// (unused)
-	{1,8,0,0},	// rail
-	{1,1,1,1},	// park
-	{2,0,0,0},	// river
-	{1,1,1,1},	// lake
-	{1,1,1,1},	// misc area
-	{1,1,1,1},	// urban area
+// tolerance for polygons at LOD1 = .004
+
+// 0.0 means no tolerance, object keeps all distinguishing points (all but multiple points in a straight line)
+// -1 means object type is always absent from this LOD
+gdouble g_afObjectTypeToleranceAtLODs[MAP_NUM_OBJECT_TYPES][MAP_NUM_LEVELS_OF_DETAIL] = {
+	{0,		0,		0,		0},	// XXX: get rid of this stupid 0 index!!
+
+	{0,		-1,		-1,		-1},	// minor rd
+	{0,		0.002,	-1,		-1},	// major rd
+	{0,		0.002,	0.008,	0.032},	// hw
+	{0,		0.002,	-1,		-1},	// hw ramp
+	{-1,	-1,		-1,		-1},	// (unused)
+	{-1,	-1,		-1,		-1},	// (unused)
+	{0.0,	0.001,	-1,		-1},	// rail
+	{0.0,	0.00115,0.02,	0.08},	// park
+	{0.0,	-1,		-1,		-1},	// river
+	{0.0,	0.00115,0.02,	0.08},	// lake
+	{0.0,	0.00115,0.02,	0.08},	// misc area
+	{0.0,	0.00115,0.02,	0.08},	// urban area
 };
+// 0.00115 seems perfect for 1:243000
+
+// Remember: LOW tolerance means MORE points
 
 gboolean object_type_exists_at_lod(gint nRecordType, gint nLOD)
 {
 	if(nRecordType < 0) {
-		g_warning("nRecordType = %d\n", nRecordType); 
+		g_warning("nRecordType = %d\n", nRecordType);
 	}
 	g_assert(nRecordType >= 0);
 	g_assert(nRecordType < MAP_NUM_OBJECT_TYPES);
 	g_assert(nLOD >= 0);
 	g_assert(nLOD <= 3);
-	return (g_aaObjectTypeDetailAtLODs[nRecordType][nLOD] > 0);
+	return (g_afObjectTypeToleranceAtLODs[nRecordType][nLOD] != -1.0);
 }
 
-gint object_type_detail_at_lod(gint nRecordType, gint nLOD)
+gdouble object_type_tolerance_at_lod(gint nRecordType, gint nLOD)
 {
 	g_assert(nRecordType >= 0);
 	g_assert(nRecordType < MAP_NUM_OBJECT_TYPES);
 	g_assert(nLOD >= 0);
 	g_assert(nLOD <= 3);
-	return (g_aaObjectTypeDetailAtLODs[nRecordType][nLOD]);
-}
-
-void reduce_object_detail_for_lod(gint nRecordType, gint nLOD, GPtrArray* pSourceArray, GPtrArray* pDestArray)
-{
-	g_assert(pSourceArray);
-	g_assert(pDestArray);
-
-	if(!object_type_exists_at_lod(nRecordType, nLOD)) return;
-
-	gint nDetail = object_type_detail_at_lod(nRecordType, nLOD);
-	g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, 0));
-
-	// our super-hacky algorithm just steps N points at a time
-	gint i;
-	for(i = nDetail ; i < (pSourceArray->len-1) ; i+=nDetail) {
-		g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, i));
-	}
-	g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, pSourceArray->len-1));
+	return (g_afObjectTypeToleranceAtLODs[nRecordType][nLOD]);
 }
 
-void util_bounding_box_of_points_array(GPtrArray* pPointsArray, maprect_t* pReturnRect)
-{
-	pReturnRect->A.fLatitude = MAX_LATITUDE;	// init to worst possible values
-	pReturnRect->A.fLongitude = MAX_LONGITUDE;
-	
-	pReturnRect->B.fLatitude = MIN_LATITUDE;
-	pReturnRect->B.fLongitude = MIN_LONGITUDE;
-
-	gint i;
-	for(i=0 ; i<pPointsArray->len ; i++) {
-		mappoint_t* pPoint = g_ptr_array_index(pPointsArray, i);
-
-		pReturnRect->A.fLatitude = min(pReturnRect->A.fLatitude, pPoint->fLatitude);
-		pReturnRect->A.fLongitude = min(pReturnRect->A.fLongitude, pPoint->fLongitude);
+// void reduce_object_detail_for_lod(gint nRecordType, gint nLOD, GPtrArray* pSourceArray, GPtrArray* pDestArray)
+// {
+//     g_assert(pSourceArray);
+//     g_assert(pDestArray);
+//
+//     if(!object_type_exists_at_lod(nRecordType, nLOD)) return;
+//
+//     gint nDetail = object_type_detail_at_lod(nRecordType, nLOD);
+//     g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, 0));
+//
+//     // our super-hacky algorithm just steps N points at a time
+//     gint i;
+//     for(i = nDetail ; i < (pSourceArray->len-1) ; i+=nDetail) {
+//         g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, i));
+//     }
+//     g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, pSourceArray->len-1));
+// }
 
-		pReturnRect->B.fLatitude = max(pReturnRect->B.fLatitude, pPoint->fLatitude);
-		pReturnRect->B.fLongitude = max(pReturnRect->B.fLongitude, pPoint->fLongitude);
-	}
-}
+// void util_bounding_box_of_points_array(GPtrArray* pPointsArray, maprect_t* pReturnRect)
+// {
+//     pReturnRect->A.fLatitude = MAX_LATITUDE;    // init to worst possible values
+//     pReturnRect->A.fLongitude = MAX_LONGITUDE;
+//
+//     pReturnRect->B.fLatitude = MIN_LATITUDE;
+//     pReturnRect->B.fLongitude = MIN_LONGITUDE;
+//
+//     gint i;
+//     for(i=0 ; i<pPointsArray->len ; i++) {
+//         mappoint_t* pPoint = g_ptr_array_index(pPointsArray, i);
+//
+//         pReturnRect->A.fLatitude = min(pReturnRect->A.fLatitude, pPoint->fLatitude);
+//         pReturnRect->A.fLongitude = min(pReturnRect->A.fLongitude, pPoint->fLongitude);
+//
+//         pReturnRect->B.fLatitude = max(pReturnRect->B.fLatitude, pPoint->fLatitude);
+//         pReturnRect->B.fLongitude = max(pReturnRect->B.fLongitude, pPoint->fLongitude);
+//     }
+// }
 
 static gboolean import_tiger_read_lat(gint8* pBuffer, gdouble* pValue)
 {
@@ -441,12 +449,6 @@
 			*pValue = MAP_OBJECT_TYPE_PARK;
 			return TRUE;
 		}
-		else {
-			*pValue = MAP_OBJECT_TYPE_MISC_AREA;
-			return TRUE;
-		}
-
-		// TODO: Add 'misc areas' to get all this stuff?
 		/*
 		D21 Apartment building
 		D24 Marina
@@ -455,18 +457,21 @@
 		D31 Hospital
 		D36 Jail
 		D37 Fed. Penitentiary / state prison
-		
+
 		D4* educational
 		D43 schools/university
 		D44 religious church/synagogue
-		
+
 		D5* transportation
 		D51 airport
 		D52 train station
 		D53 bus terminal
 		D54 marine terminal
-
 		*/
+		else {
+			*pValue = MAP_OBJECT_TYPE_MISC_AREA;
+			return TRUE;
+		}
 	}
 	else if(chFeatureClass == 'E') {		// topographic
 		/*
@@ -477,14 +482,7 @@
 //		g_print("found topographic (E%c%c)\n", chCode, chSubCode);
 	}
 	else if(chFeatureClass == 'H') { 	// water
-
 		if(chCode == '0') {
-			// generic unknown water ...
-			// this includes charles river (cambridge/boston ma)
-			// but they are badly formed for some reason?
-//			*pValue = MAP_OBJECT_TYPE_LAKE;
-//			return TRUE;
-//			return FALSE;
 			if(chSubCode == '1') {
 				// these need to be stitched by lat/lon
 				//*pValue = MAP_OBJECT_TYPE_LAKE;	// shoreline of perennial water feature
@@ -504,25 +502,23 @@
 			return TRUE;
 		}
 		else if(chCode == '5') { 	// ocean
-			if(chSubCode == '1') {
-				*pValue = MAP_OBJECT_TYPE_LAKE;	// bay, estuary, gulf or sound
-				return TRUE;				
-			}
-			else {
-//				*pValue = MAP_OBJECT_TYPE_LAKE;
-//				return TRUE;
-				//~ *pValue = MAP_OBJECT_TYPE_OCEAN;
-				//~ return TRUE;
-			}
+//             if(chSubCode == '1') {
+//                 *pValue = MAP_OBJECT_TYPE_LAKE; // bay, estuary, gulf or sound
+//                 return TRUE;
+//             }
+//             else {
+// //              *pValue = MAP_OBJECT_TYPE_LAKE;
+// //              return TRUE;
+//                 //~ *pValue = MAP_OBJECT_TYPE_OCEAN;
+//                 //~ return TRUE;
+//             }
 		}
 		else if(chCode == '6') { 	// water-filled gravel pit
-			g_print("found code H6: water filled gravel pit!\n");
-			//~ *pValue = MAP_OBJECT_TYPE_LAKE;
-			//~ return TRUE;
+			g_debug("found code H6: water filled gravel pit!");
+			//*pValue = MAP_OBJECT_TYPE_LAKE;
+			//return TRUE;
 		}
 	}
-	//~ *pValue = MAP_OBJECT_TYPE_TRAIL;
-	//~ return TRUE;
 	*pValue = MAP_OBJECT_TYPE_NONE;
 	return FALSE;
 }
@@ -652,7 +648,7 @@
 			// create new one and add it
 			pRecord = g_new0(tiger_record_rt2_t, 1);
 			pRecord->nTLID = nTLID;
-			pRecord->pPointsArray = g_ptr_array_new();
+			pRecord->pPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
 
 			// add to table
 			g_hash_table_insert(pTable, &pRecord->nTLID, pRecord);
@@ -669,11 +665,7 @@
 			if(point.fLatitude == 0.0 && point.fLongitude == 0.0) {
 				break;
 			}
-			mappoint_t* pNewPoint = g_new0(mappoint_t, 1);
-			pNewPoint->fLatitude = point.fLatitude;
-			pNewPoint->fLongitude = point.fLongitude;
-
-			g_ptr_array_add(pRecord->pPointsArray, pNewPoint);
+			g_array_append_val(pRecord->pPointsArray, point);
 		}
 	}
 	return TRUE;
@@ -857,43 +849,23 @@
 	static int nCallCount=0; nCallCount++;
 	if((nCallCount%CALLBACKS_PER_PULSE) == 0) importwindow_progress_pulse();
 	
-	GPtrArray* pTempPointsArray = g_ptr_array_new();
+	GArray* pTempPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
 	tiger_import_process_t* pImportProcess = (tiger_import_process_t*)user_data;
 	tiger_record_rt1_t* pRecordRT1 = (tiger_record_rt1_t*)value;
 	// lookup table2 record by TLID
 	tiger_record_rt2_t* pRecordRT2 = g_hash_table_lookup(pImportProcess->pTableRT2, &pRecordRT1->nTLID);
 
 	// add RT1's point A, (optionally) add all points from RT2, then add RT1's point B
-	g_ptr_array_add(pTempPointsArray, &pRecordRT1->PointA);
+	g_array_append_val(pTempPointsArray, pRecordRT1->PointA);
 	if(pRecordRT2 != NULL) {
 		// append all points from pRecordRT2->pPointsArray to pTempPointsArray
 		gint i;
 		for(i=0 ; i<pRecordRT2->pPointsArray->len ; i++) {
-			g_ptr_array_add(pTempPointsArray, g_ptr_array_index(pRecordRT2->pPointsArray, i));		
+			mappoint_t* p = &g_array_index(pRecordRT2->pPointsArray, mappoint_t, i);
+			g_array_append_val(pTempPointsArray, *p);
 		}
 	}
-	g_ptr_array_add(pTempPointsArray, &pRecordRT1->PointB);
-
-	//
-	// Change rivers into lakes if they are circular (why doesn't this work here?)
-	//
-//     if(pRecordRT1->nRecordType == MAP_OBJECT_TYPE_RIVER) {
-//         if(((gint)(pRecordRT1->PointA.fLongitude * 1000.0)) == ((gint)(pRecordRT1->PointB.fLongitude * 1000.0)) &&
-//            ((gint)(pRecordRT1->PointA.fLatitude * 1000.0)) == ((gint)(pRecordRT1->PointB.fLatitude * 1000.0)))
-//         {
-//             if(pRecordRT1->PointA.fLongitude != pRecordRT1->PointB.fLongitude) {
-//                 g_print("OOPS: %20.20f != %20.20f\n", pRecordRT1->PointA.fLongitude, pRecordRT1->PointB.fLongitude);
-//             }
-//             if(pRecordRT1->PointA.fLatitude != pRecordRT1->PointB.fLatitude) {
-//                 g_print("OOPS: %20.20f != %20.20f\n", pRecordRT1->PointA.fLatitude, pRecordRT1->PointB.fLatitude);
-//             }
-//             g_print("converting circular river to lake: %s\n", pRecordRT1->achName);
-//             pRecordRT1->nRecordType = MAP_OBJECT_TYPE_LAKE;
-//         }
-//         else {
-// //          g_print("NOT converting river: %s (%f != %f)(%f != %f)\n", pRecordRT1->achName, pRecordRT1->PointA.fLongitude, pRecordRT1->PointB.fLongitude, pRecordRT1->PointA.fLatitude, pRecordRT1->PointB.fLatitude);
-//         }
-//     }
+	g_array_append_val(pTempPointsArray, pRecordRT1->PointB);
 
 	// use RT1's FIPS code to lookup related RTc record, which contains a CityID
 	gint nCityLeftID=0;
@@ -936,28 +908,42 @@
 			db_insert_roadname(pRecordRT1->achName, pRecordRT1->nRoadNameSuffixID, &nRoadNameID);
 		}
 
-		gint nLOD = MAP_LEVEL_OF_DETAIL_BEST;
-		db_insert_road(nLOD, nRoadNameID, pRecordRT1->nRecordType,
+		gint nLOD;
+		for(nLOD = MAP_LEVEL_OF_DETAIL_BEST ; nLOD <= MAP_LEVEL_OF_DETAIL_WORST ; nLOD++) {
+			if(!object_type_exists_at_lod(pRecordRT1->nRecordType, nLOD)) continue;
+
+			GArray* pReducedPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
+
+			gdouble fTolerance = object_type_tolerance_at_lod(pRecordRT1->nRecordType, nLOD);
+			map_math_simplify_pointstring(pTempPointsArray, fTolerance, pReducedPointsArray);
+
+			// Need 2 points to form a line
+			if(pReducedPointsArray->len >= 2) {
+				if(nLOD == MAP_LEVEL_OF_DETAIL_BEST) {
+					db_insert_road(nLOD, nRoadNameID, pRecordRT1->nRecordType,
 					   pRecordRT1->nAddressLeftStart, pRecordRT1->nAddressLeftEnd,
 					   pRecordRT1->nAddressRightStart, pRecordRT1->nAddressRightEnd,
 					   nCityLeftID, nCityRightID,
 					   azZIPCodeLeft, azZIPCodeRight,
-					   pTempPointsArray, NULL);
-
-		for(nLOD = MAP_LEVEL_OF_DETAIL_BEST+1 ; nLOD <= MAP_LEVEL_OF_DETAIL_WORST ; nLOD++) {
-			GPtrArray* pReducedPointsArray = g_ptr_array_new();
-
-			reduce_object_detail_for_lod(pRecordRT1->nRecordType, nLOD, pTempPointsArray, pReducedPointsArray);
-			if(pReducedPointsArray->len > 0) {
-				g_assert(pReducedPointsArray->len >= 2);
+					   pReducedPointsArray, NULL);
+					
+				}
+				else {
+					db_insert_road(nLOD, nRoadNameID, pRecordRT1->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL,
+								   pReducedPointsArray, NULL);
+				}
 
-				db_insert_road(nLOD, nRoadNameID, pRecordRT1->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL, 
-							   pReducedPointsArray, NULL);
+				if(pReducedPointsArray->len < pTempPointsArray->len) {
+					g_debug("line %s reduced from %d to %d points at LOD %d", pRecordRT1->achName, pTempPointsArray->len, pReducedPointsArray->len, nLOD);
+				}
 			}
-			g_ptr_array_free(pReducedPointsArray, TRUE);
+			else {
+				g_warning("line %s reduced to %d points", pRecordRT1->achName, pReducedPointsArray->len);
+			}
+			g_array_free(pReducedPointsArray, TRUE);
 		}
 	}
-	g_ptr_array_free(pTempPointsArray, TRUE);
+	g_array_free(pTempPointsArray, TRUE);
 }
 
 typedef enum {
@@ -965,7 +951,7 @@
 	ORDER_BACKWARD
 } EOrder;
 
-static void tiger_util_add_RT1_points_to_array(tiger_import_process_t* pImportProcess, gint nTLID, GPtrArray* pPointsArray, EOrder eOrder)
+static void tiger_util_add_RT1_points_to_array(tiger_import_process_t* pImportProcess, gint nTLID, GArray* pPointsArray, EOrder eOrder)
 {
 	g_assert(pImportProcess != NULL);
 	g_assert(pImportProcess->pTableRT1 != NULL);
@@ -979,25 +965,27 @@
 	tiger_record_rt2_t* pRecordRT2 = g_hash_table_lookup(pImportProcess->pTableRT2, &pRecordRT1->nTLID);
 
 	if(eOrder == ORDER_FORWARD) {
-		g_ptr_array_add(pPointsArray, &pRecordRT1->PointA);
+		g_array_append_val(pPointsArray, pRecordRT1->PointA);
 		if(pRecordRT2 != NULL) {
 			// append all points from pRecordRT2->pPointsArray
 			gint i;
 			for(i=0 ; i<pRecordRT2->pPointsArray->len ; i++) {
-				g_ptr_array_add(pPointsArray, g_ptr_array_index(pRecordRT2->pPointsArray, i));
+				mappoint_t* p = &g_array_index(pRecordRT2->pPointsArray, mappoint_t, i);
+				g_array_append_val(pPointsArray, *p);
 			}
 		}
-		g_ptr_array_add(pPointsArray, &pRecordRT1->PointB);
+		g_array_append_val(pPointsArray, pRecordRT1->PointB);
 	} else {
-		g_ptr_array_add(pPointsArray, &pRecordRT1->PointB);
+		g_array_append_val(pPointsArray, pRecordRT1->PointB);
 		if(pRecordRT2 != NULL) {
 			// append all points from pRecordRT2->pPointsArray in REVERSE order
 			gint i;
 			for(i=pRecordRT2->pPointsArray->len-1 ; i>=0 ; i--) {
-				g_ptr_array_add(pPointsArray, g_ptr_array_index(pRecordRT2->pPointsArray, i));		
+				mappoint_t* p = &g_array_index(pRecordRT2->pPointsArray, mappoint_t, i);
+				g_array_append_val(pPointsArray, *p);
 			}
 		}
-		g_ptr_array_add(pPointsArray, &pRecordRT1->PointA);
+		g_array_append_val(pPointsArray, pRecordRT1->PointA);
 	}
 }
 
@@ -1041,10 +1029,10 @@
 	g_assert(pRecordRTi->pRT1LinksArray != NULL);
 	g_assert(pRecordRTi->pRT1LinksArray->len >= 1);
 
-	GPtrArray* pTempPointsArray = NULL;
+	GArray* pTempPointsArray = NULL;
 	// create a temp array to hold the points for this polygon (in order)
 	g_assert(pTempPointsArray == NULL);
-	pTempPointsArray = g_ptr_array_new();
+	pTempPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
 
 	// start with the RT1Link at index 0 (and remove it)
 	tiger_rt1_link_t* pCurrentRT1Link = g_ptr_array_index(pRecordRTi->pRT1LinksArray, 0);
@@ -1117,17 +1105,32 @@
 	g_assert(pCurrentRT1Link != NULL);
 	g_free(pCurrentRT1Link);
 
-	// save this polygon
-	if(pTempPointsArray->len > 3) {	// takes 3 to make a polygon
-		mappoint_t* p1 = g_ptr_array_index(pTempPointsArray, 0);
-		mappoint_t* p2 = g_ptr_array_index(pTempPointsArray, pTempPointsArray->len-1);
+	//
+	// IMPORTANT: Remove last point!
+	//  A) It's the same as first, so there's no reason to store it.
+	//  B) It lets us use 'map_math_simplify_pointstring' which doesn't work on closed polygons.
+	//
+	// NOTE: We copy the last point to the first when loading this polygon
+	//
+	mappoint_t* p1 = &g_array_index(pTempPointsArray, mappoint_t, 0);
+	mappoint_t* p2 = &g_array_index(pTempPointsArray, mappoint_t, pTempPointsArray->len-1);
 
-		if(p1->fLatitude != p2->fLatitude || p1->fLongitude != p2->fLongitude) {
-			g_print("Found a polygon that doesn't loop %s\n", pRecordRT7->achName);
-		}
+	if(p1->fLatitude != p2->fLatitude || p1->fLongitude != p2->fLongitude) {
+		g_warning("Found a polygon that doesn't loop %s\n", pRecordRT7->achName);
+	}
+
+	pTempPointsArray->len--;
+
+	// save this polygon
+	if(pTempPointsArray->len >= 3) {	// takes 3 to make a polygon
 
 		// insert record
 		if(pRecordRT7->nRecordType != MAP_OBJECT_TYPE_NONE) {
+			if(pRecordRT7->nRecordType == MAP_OBJECT_TYPE_RIVER) {
+				pRecordRT7->nRecordType = MAP_OBJECT_TYPE_LAKE;
+				g_debug("river => lake");
+			}
+
 			gint nRoadNameID = 0;
 			if(pRecordRT7->achName[0] != '\0') {
 				//g_printf("inserting area name %s\n", pRecordRT7->achName);
@@ -1135,37 +1138,36 @@
 			}
 
 			// Write LOD 0
-			gint nLOD = MAP_LEVEL_OF_DETAIL_BEST;
-			db_insert_road(nLOD, nRoadNameID, pRecordRT7->nRecordType, 0, 0, 0, 0, 0, 0, "", "", 
-						   pTempPointsArray, NULL);
-
-			// Write higher LODs
-			maprect_t rc;
-			util_bounding_box_of_points_array(pTempPointsArray, &rc);
-			gdouble fWidth = rc.B.fLongitude - rc.A.fLongitude;
-			gdouble fHeight = rc.B.fLatitude - rc.A.fLatitude;
+			gint nLOD;
+			for(nLOD = MAP_LEVEL_OF_DETAIL_BEST ; nLOD <= MAP_LEVEL_OF_DETAIL_WORST ; nLOD++) {
+				if(!object_type_exists_at_lod(pRecordRT7->nRecordType, nLOD)) continue;
 
-			for(nLOD = MAP_LEVEL_OF_DETAIL_BEST+1 ; nLOD <= MAP_LEVEL_OF_DETAIL_WORST ; nLOD++) {
-				if((fWidth < g_afPolygonMinSizeAtLODs[nLOD]) || (fHeight < g_afPolygonMinSizeAtLODs[nLOD])) {
-					g_print("object exluded at LOD %d\n", nLOD);
-					break;	// not visible (nor at higher LODs, so break instead of continue)
-				}
-				
-				GPtrArray* pReducedPointsArray = g_ptr_array_new();
+				GArray* pReducedPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
 
-				reduce_object_detail_for_lod(pRecordRT7->nRecordType, nLOD, pTempPointsArray, pReducedPointsArray);
-				if(pReducedPointsArray->len > 0) {
-					g_assert(pReducedPointsArray->len >= 2);
+				gdouble fTolerance = object_type_tolerance_at_lod(pRecordRT7->nRecordType, nLOD);
+				map_math_simplify_pointstring(pTempPointsArray, fTolerance, pReducedPointsArray);
 
-					db_insert_road(nLOD, nRoadNameID, pRecordRT7->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL, 
-								   pReducedPointsArray, NULL);
+				// Need three points to form a polygon
+				if(pReducedPointsArray->len >= 3) {
+					if(nLOD == MAP_LEVEL_OF_DETAIL_BEST) {
+						db_insert_road(nLOD, nRoadNameID, pRecordRT7->nRecordType, 0, 0, 0, 0, 0, 0, "", "", 
+									   pReducedPointsArray, NULL);
+					}
+					else {
+						db_insert_road(nLOD, nRoadNameID, pRecordRT7->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL,
+									   pReducedPointsArray, NULL);
+					}
+					g_debug("%s reduced from %d to %d points at LOD %d\n", pRecordRT7->achName, pTempPointsArray->len, pReducedPointsArray->len, nLOD);
 				}
-				g_ptr_array_free(pReducedPointsArray, TRUE);
+				else {
+					g_debug("%s had %d and was excluded at LOD %d\n", pRecordRT7->achName, pTempPointsArray->len, nLOD);
+					//g_debug("%s reduced from %d to %d points\n", pRecordRT7->achName, pTempPointsArray->len, pReducedPointsArray->len);
+				}
+				g_array_free(pReducedPointsArray, TRUE);
 			}
-
 		}
 	}
-	g_ptr_array_free(pTempPointsArray, TRUE);
+	g_array_free(pTempPointsArray, TRUE);
 
 	// we SHOULD have used all RT1 links up!
 	if(pRecordRTi->pRT1LinksArray->len > 0) {

Index: locationeditwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/locationeditwindow.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- locationeditwindow.c	25 Sep 2005 19:02:37 -0000	1.3
+++ locationeditwindow.c	18 Oct 2005 03:05:25 -0000	1.4
@@ -110,6 +110,8 @@
 	GLADE_LINK_WIDGET(pGladeXML, g_LocationEditWindow.pLocationSetComboBox, GTK_COMBO_BOX, "locationsetcombobox");
 	GLADE_LINK_WIDGET(pGladeXML, g_LocationEditWindow.pLocationAddressTextView, GTK_TEXT_VIEW, "locationaddresstextview");
 
+	g_object_set(G_OBJECT(g_LocationEditWindow.pLocationSetComboBox), "has-frame", FALSE, NULL); 
+
 	GLADE_LINK_WIDGET(pGladeXML, g_LocationEditWindow.pAttributeExpander, GTK_EXPANDER, "attributeexpander");
 	gtk_expander_set_use_markup(g_LocationEditWindow.pAttributeExpander, TRUE);
 

Index: locationeditwindow.h
===================================================================
RCS file: /cvs/cairo/roadster/src/locationeditwindow.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- locationeditwindow.h	24 Sep 2005 05:25:25 -0000	1.2
+++ locationeditwindow.h	18 Oct 2005 03:05:25 -0000	1.3
@@ -31,6 +31,7 @@
 
 void locationeditwindow_init(GladeXML* pGladeXML);
 void locationeditwindow_hide(void);
+void locationeditwindow_show_for_new(gint nDefaultLocationSetID);
 
 G_END_DECLS
 

Index: main.c
===================================================================
RCS file: /cvs/cairo/roadster/src/main.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- main.c	5 Oct 2005 06:09:36 -0000	1.33
+++ main.c	18 Oct 2005 03:05:25 -0000	1.34
@@ -25,11 +25,16 @@
 #  include <config.h>
 #endif
 
+#ifdef ENABLE_NLS
+#	include <libintl.h>
+#endif
+
 #include <gtk/gtk.h>
 #include "main.h"
 #include "gui.h"
 #include "db.h"
 #include "map.h"
+#include "map_style.h"
 #include "gpsclient.h"
 #include "locationset.h"
 #include "location.h"
@@ -151,7 +156,7 @@
 	db_init();
 
 	g_print("connecting to db\n");
-	gboolean bConnected = db_connect(NULL, NULL, NULL, "");
+	db_connect(NULL, NULL, NULL, "");	// Connect to internal DB
 
 	g_print("creating database tables\n");
 	db_create_tables();

Index: mainwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/mainwindow.c,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- mainwindow.c	12 Oct 2005 03:56:44 -0000	1.52
+++ mainwindow.c	18 Oct 2005 03:05:25 -0000	1.53
@@ -39,6 +39,7 @@
 #include "gotowindow.h"
 #include "db.h"
 #include "map.h"
+#include "map_math.h"
 #include "map_hittest.h"
 #include "map_style.h"
 #include "importwindow.h"
@@ -49,8 +50,8 @@
 #include "animator.h"
 #include "map_history.h"
 #include "mapinfowindow.h"
-
 #include "tooltipwindow.h"
+#include "locationeditwindow.h"
 
 #define PROGRAM_NAME			"Roadster"
 #define PROGRAM_COPYRIGHT		"Copyright (c) 2005 Ian McIntosh"
@@ -164,7 +165,10 @@
 
 struct {
 	gint nCursor;
-} g_aDirectionCursors[] = {GDK_LEFT_PTR, GDK_TOP_SIDE, GDK_TOP_RIGHT_CORNER, GDK_RIGHT_SIDE, GDK_BOTTOM_RIGHT_CORNER, GDK_BOTTOM_SIDE, GDK_BOTTOM_LEFT_CORNER, GDK_LEFT_SIDE, GDK_TOP_LEFT_CORNER};
+} g_aDirectionCursors[] = {{GDK_LEFT_PTR}, 
+{GDK_TOP_SIDE}, 
+{GDK_TOP_RIGHT_CORNER}, 
+{GDK_RIGHT_SIDE}, {GDK_BOTTOM_RIGHT_CORNER}, {GDK_BOTTOM_SIDE}, {GDK_BOTTOM_LEFT_CORNER}, {GDK_LEFT_SIDE}, {GDK_TOP_LEFT_CORNER}};
 
 struct {
 	GtkWindow* pWindow;
@@ -302,9 +306,9 @@
 	return pCursor;
 }
 
-void mainwindow_draw_xor_rect(screenrect_t* pRect)
+void mainwindow_draw_selection_rect(screenrect_t* pRect)
 {
-	map_draw_gdk_xor_rect(g_MainWindow.pMap, GTK_WIDGET(g_MainWindow.pDrawingArea)->window, pRect);
+	map_draw_xor_rect(g_MainWindow.pMap, GTK_WIDGET(g_MainWindow.pDrawingArea)->window, pRect);
 }
 
 void mainwindow_set_not_busy(void** ppCursor)
@@ -334,7 +338,7 @@
 
 		// XXX: how do we specify zoom level in YMaps URL?
 		{"Yahoo! Maps", "http://maps.yahoo.com/maps_result?lat={LAT}&lon={LON}"},
-		
+
 		{"MSN Maps", "http://maps.msn.com/map.aspx?C={LAT}%2C{LON}&S=800%2C740&alts1={ALTITUDE_MILES}"},
 
 		{"MSN Virtual Earth Roads", "http://virtualearth.msn.com/default.aspx?v=1&cp={LAT}|{LON}&lvl={ZOOM_1_TO_19}&style=r"},
@@ -375,9 +379,6 @@
 
 void mainwindow_init(GladeXML* pGladeXML)
 {
-	GtkCellRenderer* pCellRenderer;
-  	GtkTreeViewColumn* pColumn;
-
 	// Window / Container Widgets
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pWindow, GTK_WINDOW, "mainwindow");
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pToolbar, GTK_HBOX, "maintoolbar");
@@ -702,7 +703,7 @@
 
 void mainwindow_statusbar_update_zoomscale(void)
 {
-	gchar* pszNew = g_strdup_printf("1:%d", map_get_zoomlevel_scale(g_MainWindow.pMap));
+	gchar* pszNew = g_strdup_printf("1:%d", map_get_scale(g_MainWindow.pMap));
 	mainwindow_set_statusbar_zoomscale(pszNew);
 	g_free(pszNew);
 }
@@ -735,10 +736,10 @@
 	return GTK_WIDGET_VISIBLE(g_MainWindow.pSidebox);
 }
 
-GtkWidget* mainwindow_get_window(void)
-{
-	return GTK_WIDGET(g_MainWindow.pWindow);
-}
+// GtkWidget* mainwindow_get_window(void)
+// {
+//     return GTK_WIDGET(g_MainWindow.pWindow);
+// }
 
 void mainwindow_toggle_fullscreen(void)
 {
@@ -954,70 +955,6 @@
 	mainwindow_draw_map(DRAWFLAG_ALL);
 }
 
-
-EDirection match_border(gint nX, gint nY, gint nWidth, gint nHeight, gint nBorderSize)
-{
-	EDirection eDirection;
-
-	// Corner hit targets are L shaped and 1/3 of the two borders it touches
-	gint nXCorner = nWidth/3;
-	gint nYCorner = nHeight/3;
-
-	// LEFT EDGE?
-	if(nX <= nBorderSize) {
-		if(nY <= nYCorner) {
-			eDirection = DIRECTION_NW;
-		}
-		else if((nY+nYCorner) >= nHeight) {
-			eDirection = DIRECTION_SW;
-		}
-		else {
-			eDirection = DIRECTION_W;
-		}
-	}
-	// RIGHT EDGE?
-	else if((nX+nBorderSize) >= nWidth) {
-		if(nY <= nYCorner) {
-			eDirection = DIRECTION_NE;
-		}
-		else if((nY+nYCorner) >= nHeight) {
-			eDirection = DIRECTION_SE;
-		}
-		else {
-			eDirection = DIRECTION_E;
-		}
-	}
-	// TOP?
-	else if(nY <= nBorderSize) {
-		if(nX <= nXCorner) {
-			eDirection = DIRECTION_NW;
-		}
-		else if((nX+nXCorner) >= nWidth) {
-			eDirection = DIRECTION_NE;
-		}
-		else {
-			eDirection = DIRECTION_N;
-		}
-	}
-	// BOTTOM?
-	else if((nY+nBorderSize) >= nHeight) {
-		if(nX <= nXCorner) {
-			eDirection = DIRECTION_SW;
-		}
-		else if((nX+nXCorner) >= nWidth) {
-			eDirection = DIRECTION_SE;
-		}
-		else {
-			eDirection = DIRECTION_S;
-		}
-	}
-	// center.
-	else {
-		eDirection = DIRECTION_NONE;
-	}
-	return eDirection;
-}
-
 static gboolean mainwindow_on_mouse_button_click(GtkWidget* w, GdkEventButton *event)
 {
 	gint nX, nY;
@@ -1026,10 +963,6 @@
 	gint nWidth = GTK_WIDGET(g_MainWindow.pDrawingArea)->allocation.width;
 	gint nHeight = GTK_WIDGET(g_MainWindow.pDrawingArea)->allocation.height;
 
-	// nX and nY clipped to screen
-	gint nClippedX = (nX < 0) ? 0 : (nX > nWidth) ? nWidth : nX;
-	gint nClippedY = (nY < 0) ? 0 : (nY > nHeight) ? nHeight : nY;
-
 	EDirection eScrollDirection = DIRECTION_NONE;
 
 	// get mouse position on screen
@@ -1047,7 +980,7 @@
 			tooltip_hide(g_MainWindow.pTooltip);
 
 			// Is it at a border?
-			eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+			eScrollDirection = util_match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
 			if(eScrollDirection != DIRECTION_NONE) {
 				// begin a scroll
 				GdkCursor* pCursor = gdk_cursor_new(g_aDirectionCursors[eScrollDirection].nCursor);
@@ -1128,7 +1061,7 @@
 				}
 				else {
 					// Since we're not redrawing the map, we need to erase the selection rectangle
-					mainwindow_draw_xor_rect(&(g_MainWindow.rcZoomRect));
+					mainwindow_draw_selection_rect(&(g_MainWindow.rcZoomRect));
 				}
 				// all done
 				g_MainWindow.bDrawingZoomRect = FALSE;
@@ -1174,7 +1107,7 @@
 		}
 		else if(event->type == GDK_2BUTTON_PRESS) {
 			// can only double-click in the middle (not on a scroll border)
-			eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+			eScrollDirection = util_match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
 			if(eScrollDirection == DIRECTION_NONE) {
 				animator_destroy(g_MainWindow.pAnimator);
 
@@ -1193,7 +1126,7 @@
 	else if (event->button == MOUSE_BUTTON_RIGHT) {
 		// single right-click?
 		if(event->type == GDK_BUTTON_PRESS) {
-			GtkMenu* pMenu = g_MainWindow.pMapPopupMenu;	// default to generic map popup
+			//GtkMenu* pMenu = g_MainWindow.pMapPopupMenu;	// default to generic map popup
 
 			if(pHitStruct != NULL) {
 				if(pHitStruct->eHitType == MAP_HITTYPE_LOCATION) {
@@ -1294,7 +1227,7 @@
 		g_MainWindow.ptClickLocation.nY = nY;
 	}
 	else if(g_MainWindow.bScrolling) {
-		EDirection eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+		EDirection eScrollDirection = util_match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
 
 		// update cursor
 		nCursor = g_aDirectionCursors[eScrollDirection].nCursor;
@@ -1304,18 +1237,18 @@
 	}
 	else if(g_MainWindow.bDrawingZoomRect) {
 		//g_print("updating rect\n");
-		mainwindow_draw_xor_rect(&g_MainWindow.rcZoomRect);	// erase old rect (XOR operator rocks!)
+		mainwindow_draw_selection_rect(&g_MainWindow.rcZoomRect);	// erase old rect (XOR operator rocks!)
 
 		g_MainWindow.rcZoomRect.B.nX = nClippedX;
 		g_MainWindow.rcZoomRect.B.nY = nClippedY;
 
-		mainwindow_draw_xor_rect(&g_MainWindow.rcZoomRect);	// draw new rect
+		mainwindow_draw_selection_rect(&g_MainWindow.rcZoomRect);	// draw new rect
 	}
 	else {
 		// If not dragging or scrolling, user is just moving mouse around.
 		// Update tooltip and mouse cursor based on what we're pointing at.
 
-		EDirection eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+		EDirection eScrollDirection = util_match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
 
 		if(eScrollDirection == DIRECTION_NONE) {
 			// get mouse position on screen
@@ -1393,12 +1326,14 @@
 static gboolean mainwindow_on_enter_notify(GtkWidget* w, GdkEventCrossing *event)
 {
 	// mouse entered our window.  nothing to do (we'll respond to mouse motion)
+	return FALSE; 	// propagate further
 }
 
 static gboolean mainwindow_on_leave_notify(GtkWidget* w, GdkEventCrossing *event)
 {
 	// mouse left our window
 	tooltip_hide(g_MainWindow.pTooltip);
+	return FALSE; 	// propagate further
 }
 
 // Respond to mouse scroll wheel
@@ -1419,6 +1354,7 @@
 		mainwindow_draw_map(DRAWFLAG_GEOMETRY);
 		mainwindow_set_draw_pretty_timeout(DRAW_PRETTY_ZOOM_TIMEOUT_MS);
 	}
+	return FALSE; 	// propagate further
 }
 
 static gboolean mainwindow_on_key_press(GtkWidget *widget, GdkEventKey *pEvent, gpointer user_data)
@@ -1433,16 +1369,16 @@
 	else if(pEvent->keyval == GDK_Escape) {
 		if(g_MainWindow.bDrawingZoomRect == TRUE) {
 			// cancel zoom-rect
-			mainwindow_draw_xor_rect(&(g_MainWindow.rcZoomRect));
+			mainwindow_draw_selection_rect(&(g_MainWindow.rcZoomRect));
 			g_MainWindow.bDrawingZoomRect = FALSE;
 		}
 	}
-	return FALSE;
+	return FALSE; 	// propagate further
 }
 static gboolean mainwindow_on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
 	//g_print("key_release\n");
-	return FALSE;
+	return FALSE; 	// propagate further
 }
 
 static gboolean mainwindow_on_window_state_change(GtkWidget *_unused, GdkEventKey *pEvent, gpointer __unused)
@@ -1451,6 +1387,7 @@
 	g_signal_handlers_block_by_func(g_MainWindow.pViewFullscreenMenuItem, mainwindow_on_fullscreenmenuitem_activate, NULL);
 	gtk_check_menu_item_set_active(g_MainWindow.pViewFullscreenMenuItem, util_gtk_window_is_fullscreen(g_MainWindow.pWindow));
 	g_signal_handlers_unblock_by_func(g_MainWindow.pViewFullscreenMenuItem, mainwindow_on_fullscreenmenuitem_activate, NULL);
+	return FALSE; 	// propagate further
 }
 
 static void mainwindow_begin_import_geography_data(void)
@@ -1585,22 +1522,22 @@
 /*
 ** GPS Functions
 */
-gboolean mainwindow_on_gps_show_position_toggled(GtkWidget* _unused, gpointer* __unused)
+void mainwindow_on_gps_show_position_toggled(GtkWidget* _unused, gpointer* __unused)
 {
 
 }
 
-gboolean mainwindow_on_gps_keep_position_centered_toggled(GtkWidget* _unused, gpointer* __unused)
+void mainwindow_on_gps_keep_position_centered_toggled(GtkWidget* _unused, gpointer* __unused)
 {
 
 }
 
-gboolean mainwindow_on_gps_show_trail_toggled(GtkWidget* _unused, gpointer* __unused)
+void mainwindow_on_gps_show_trail_toggled(GtkWidget* _unused, gpointer* __unused)
 {
 
 }
 
-gboolean mainwindow_on_gps_stick_to_roads_toggled(GtkWidget* _unused, gpointer* __unused)
+void mainwindow_on_gps_stick_to_roads_toggled(GtkWidget* _unused, gpointer* __unused)
 {
 
 }
@@ -1734,10 +1671,8 @@
 	gint16 nPixelDeltaY = nY - (GTK_WIDGET(g_MainWindow.pDrawingArea)->allocation.height / 2);
 
 	// Convert pixels to world coordinates
-	gint nZoomLevel = map_get_zoomlevel(g_MainWindow.pMap);
-	double fWorldDeltaX = map_pixels_to_degrees(g_MainWindow.pMap, nPixelDeltaX, nZoomLevel);
-	// reverse the X, clicking above
-	double fWorldDeltaY = -map_pixels_to_degrees(g_MainWindow.pMap, nPixelDeltaY, nZoomLevel);
+	double fWorldDeltaX = map_math_pixels_to_degrees_at_scale(nPixelDeltaX, map_get_scale(g_MainWindow.pMap));
+	double fWorldDeltaY = -map_math_pixels_to_degrees_at_scale(nPixelDeltaY, map_get_scale(g_MainWindow.pMap));
 
 	mappoint_t pt;
 	map_get_centerpoint(g_MainWindow.pMap, &pt);
@@ -1766,7 +1701,7 @@
 
 	if(map_points_equal(pPoint, &centerPoint)) return;
 
-	if(map_get_distance_in_pixels(g_MainWindow.pMap, pPoint, &centerPoint) < MAX_DISTANCE_FOR_AUTO_SLIDE_IN_PIXELS) {
+//     if(map_get_distance_in_pixels(g_MainWindow.pMap, pPoint, &centerPoint) < MAX_DISTANCE_FOR_AUTO_SLIDE_IN_PIXELS) {
 		g_MainWindow.bSliding = TRUE;
 		g_MainWindow.pAnimator = animator_new(ANIMATIONTYPE_FAST_THEN_SLIDE, SLIDE_TIME_IN_SECONDS_AUTO);
 
@@ -1777,11 +1712,11 @@
 		// set endpoint
 		g_MainWindow.ptSlideEndLocation.fLatitude = pPoint->fLatitude;
 		g_MainWindow.ptSlideEndLocation.fLongitude = pPoint->fLongitude;
-	}
-	else {
-		mainwindow_map_center_on_mappoint(pPoint);	// Too far-- don't slide.  Jump instead.
-		mainwindow_add_history();					// The slide timeout would have done this when the slide was over
-	}
+//     }
+//     else {
+//         mainwindow_map_center_on_mappoint(pPoint);  // Too far-- don't slide.  Jump instead.
+//         mainwindow_add_history();                   // The slide timeout would have done this when the slide was over
+//     }
 }
 
 // used by searchwindow and this window
@@ -1927,7 +1862,7 @@
 	apszReplacements[1].pszReplace = util_format_gdouble(ptCenter.fLongitude);
 	apszReplacements[2].pszReplace = g_strdup_printf("%f", rcVisible.B.fLatitude - rcVisible.A.fLatitude);
 	apszReplacements[3].pszReplace = g_strdup_printf("%f", rcVisible.B.fLongitude - rcVisible.A.fLongitude);
-	apszReplacements[4].pszReplace = g_strdup_printf("%d", map_get_zoomlevel_scale(g_MainWindow.pMap));
+	apszReplacements[4].pszReplace = g_strdup_printf("%d", map_get_scale(g_MainWindow.pMap));
 	apszReplacements[5].pszReplace = g_strdup_printf("%d", util_get_int_at_percent_of_range(fZoomPercent, 1, 10));
 	apszReplacements[6].pszReplace = g_strdup_printf("%d", util_get_int_at_percent_of_range(fZoomPercent, 1, 19));
 //	apszReplacements[7].pszReplace = g_strdup_printf("%d", nAltitudeMiles);

Index: mainwindow.h
===================================================================
RCS file: /cvs/cairo/roadster/src/mainwindow.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- mainwindow.h	1 Oct 2005 19:09:05 -0000	1.13
+++ mainwindow.h	18 Oct 2005 03:05:25 -0000	1.14
@@ -26,12 +26,13 @@
 
 #include <glade/glade.h>
 #include "map.h"
+#include "util.h"
 
 G_BEGIN_DECLS
 
 void mainwindow_init(GladeXML* pGladeXML);
 void mainwindow_draw_map(gint nDrawFlags);
-GtkWidget* mainwindow_get_window(void);
+// GtkWidget* mainwindow_get_window(void);
 
 // Visibility
 void mainwindow_show(void);
@@ -76,10 +77,6 @@
 
 void mainwindow_add_history();
 
-typedef enum {
-	DIRECTION_NONE, DIRECTION_N, DIRECTION_NE, DIRECTION_E, DIRECTION_SE, DIRECTION_S, DIRECTION_SW, DIRECTION_W, DIRECTION_NW
-} EDirection;
-
 void mainwindow_scroll_direction(EDirection eScrollDirection, gint nPixels);
 
 #define SIDEBAR_TAB_LOCATIONSETS	0

Index: map.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map.c,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- map.c	12 Oct 2005 03:04:05 -0000	1.55
+++ map.c	18 Oct 2005 03:05:25 -0000	1.56
@@ -24,12 +24,16 @@
 #include <gdk/gdkx.h>
 #include <gtk/gtk.h>
 #include <math.h>
+#include <string.h>
 
 #include "main.h"
 #include "map_style.h"
 #include "map_tilemanager.h"
+#include "map_math.h"
 #include "gui.h"
 #include "map.h"
+#include "map_draw_gdk.h"
+#include "map_draw_cairo.h"
 #include "mainwindow.h"
 #include "util.h"
 #include "db.h"
@@ -68,11 +72,7 @@
 
 /* Prototypes */
 static void map_init_location_hash(map_t* pMap);
-
-static void map_store_location(map_t* pMap, location_t* pLocation, gint nLocationSetID);
-
-static void map_data_clear(map_t* pMap);
-void map_get_render_metrics(const map_t* pMap, rendermetrics_t* pMetrics);
+//static void map_store_location(map_t* pMap, location_t* pLocation, gint nLocationSetID);
 
 gdouble map_get_straight_line_distance_in_degrees(mappoint_t* p1, mappoint_t* p2);
 
@@ -88,20 +88,20 @@
 	{ 28000000, UNIT_MILES,500,UNIT_KILOMETERS,500, 	1, 3},	// 7
 	{ 21000000, UNIT_MILES,500,UNIT_KILOMETERS,500, 	1, 3},	// 8
 
-	{ 14000000, UNIT_MILES,10,	UNIT_KILOMETERS,12, 	2, 2},	// *9
-	{ 11600000, UNIT_MILES,10,	UNIT_KILOMETERS,12, 	2, 2},	// 10
-	{  9200000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	2, 2},	// 11
-	{  6800000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	2, 2},	// 12
+	{ 14000000, UNIT_MILES,10,	UNIT_KILOMETERS,12, 	2, 3},	// *9
+	{ 11600000, UNIT_MILES,10,	UNIT_KILOMETERS,12, 	2, 3},	// 10
+	{  9200000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	2, 3},	// 11
+	{  6800000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	2, 3},	// 12
 
 	{  4400000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	3, 2},	// *13
 	{  3850000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	3, 2},	// 14
 	{  3300000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	3, 2},	// 15
 	{  2750000, UNIT_MILES, 5,	UNIT_KILOMETERS, 7, 	3, 2},	// 16
 
-	{  2200000, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 1},	// *17
-	{  1832250, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 1},	// 18
-	{  1464500, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 1},	// 19
-	{  1100000, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 1},	// 20
+	{  2200000, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 2},	// *17
+	{  1832250, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 2},	// 18
+	{  1464500, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 2},	// 19
+	{  1100000, UNIT_MILES,20,	UNIT_KILOMETERS,15, 	4, 2},	// 20
 
 	{   729000, UNIT_MILES,10,	UNIT_KILOMETERS, 8, 	5, 1},	// *21
 	{   607500, UNIT_MILES,10,	UNIT_KILOMETERS, 8, 	5, 1},	// 22
@@ -213,14 +213,21 @@
 
 	// Load geometry
 	TIMER_BEGIN(loadtimer, "--- BEGIN ALL DB LOAD");
-//	map_data_clear(pMap);
-	GPtrArray* pTileArray = map_tilemanager_load_tiles_for_worldrect(pMap->pTileManager, &(pRenderMetrics->rWorldBoundingBox), pRenderMetrics->nLevelOfDetail);
+
+	if(pMap->pLastActiveTilesArray != NULL) {
+		map_tilemanager_free_tile_list(pMap->pTileManager, pMap->pLastActiveTilesArray);
+	}
+	GPtrArray* pTilesArray = map_tilemanager_load_tiles_for_worldrect(pMap->pTileManager, &(pRenderMetrics->rWorldBoundingBox), pRenderMetrics->nLevelOfDetail);
+
+	// save this list for hit testing
+	pMap->pLastActiveTilesArray = pTilesArray;
+
 	TIMER_END(loadtimer, "--- END ALL DB LOAD");
 
 	scenemanager_clear(pMap->pSceneManager);
 	scenemanager_set_screen_dimensions(pMap->pSceneManager, pRenderMetrics->nWindowWidth, pRenderMetrics->nWindowHeight);
 
-	gint nRenderMode = RENDERMODE_FAST; //RENDERMODE_FAST; // RENDERMODE_PRETTY
+	gint nRenderMode = RENDERMODE_FAST; //RENDERMODE_PRETTY; // 
 
 #ifdef ENABLE_LABELS_WHILE_DRAGGING
 	nDrawFlags |= DRAWFLAG_LABELS;	// always turn on labels
@@ -234,15 +241,15 @@
 	if(nRenderMode == RENDERMODE_FAST) {
 		// 
 		if(nDrawFlags & DRAWFLAG_GEOMETRY) {
-			map_draw_gdk(pMap, pTileArray, pRenderMetrics, pTargetPixmap, DRAWFLAG_GEOMETRY);
+			map_draw_gdk(pMap, pTilesArray, pRenderMetrics, pTargetPixmap, DRAWFLAG_GEOMETRY);
 			nDrawFlags &= ~DRAWFLAG_GEOMETRY;
 		}
 
 		// Call cairo for finishing the scene
-		map_draw_cairo(pMap, pTileArray, pRenderMetrics, pTargetPixmap, nDrawFlags);
+		map_draw_cairo(pMap, pTilesArray, pRenderMetrics, pTargetPixmap, nDrawFlags);
 	}
 	else {	// nRenderMode == RENDERMODE_PRETTY
-		map_draw_cairo(pMap, pTileArray, pRenderMetrics, pTargetPixmap, nDrawFlags);
+		map_draw_cairo(pMap, pTilesArray, pRenderMetrics, pTargetPixmap, nDrawFlags);
 	}
 
 #ifdef ENABLE_SCENEMANAGER_DEBUG_TEST
@@ -251,8 +258,11 @@
 #endif
 
 	gtk_widget_queue_draw(pMap->pTargetWidget);
+}
 
-	g_ptr_array_free(pTileArray, TRUE);
+void map_draw_xor_rect(map_t* pMap, GdkDrawable* pTargetDrawable, screenrect_t* pRect)
+{
+	map_draw_gdk_xor_rect(pMap, pTargetDrawable, pRect);
 }
 
 // ========================================================
@@ -289,7 +299,7 @@
 	return pMap->uZoomLevel;	// between MIN_ZOOM_LEVEL and MAX_ZOOM_LEVEL
 }
 
-guint32 map_get_zoomlevel_scale(const map_t* pMap)
+guint32 map_get_scale(const map_t* pMap)
 {
 	return g_sZoomLevels[pMap->uZoomLevel-1].uScale;	// returns "5000" for 1:5000 scale
 }
@@ -335,9 +345,9 @@
 	gint16 nPixelDeltaY = uY - (pMap->MapDimensions.uHeight / 2);
 
 	// Convert pixels to world coordinates
-	gdouble fWorldDeltaX = map_pixels_to_degrees(pMap, nPixelDeltaX, pMap->uZoomLevel);
+	gdouble fWorldDeltaX = map_math_pixels_to_degrees_at_scale(nPixelDeltaX, map_get_scale(pMap));
 	// reverse the X, clicking above
-	gdouble fWorldDeltaY = -map_pixels_to_degrees(pMap, nPixelDeltaY, pMap->uZoomLevel);
+	gdouble fWorldDeltaY = -map_math_pixels_to_degrees_at_scale(nPixelDeltaY, map_get_scale(pMap));
 
 //	g_message("panning %d,%d pixels (%.10f,%.10f world coords)\n", nPixelDeltaX, nPixelDeltaY, fWorldDeltaX, fWorldDeltaY);
 
@@ -354,16 +364,15 @@
 	map_get_screenrect_centerpoint(pRect, &ptCenter);
 	map_center_on_windowpoint(pMap, ptCenter.nX, ptCenter.nY);
 	//g_print("box centerpoint = %d,%d\n", ptCenter.nX, ptCenter.nY);
-	
+
 	// calculate size of rectangle in degrees
-	gdouble fBoxLongitude = map_pixels_to_degrees(pMap, map_screenrect_width(pRect), pMap->uZoomLevel); 
-	gdouble fBoxLatitude = map_pixels_to_degrees(pMap, map_screenrect_height(pRect), pMap->uZoomLevel); 
+	gdouble fBoxLongitude = map_math_pixels_to_degrees_at_scale(map_screenrect_width(pRect), map_get_scale(pMap));
+	gdouble fBoxLatitude = map_math_pixels_to_degrees_at_scale(map_screenrect_height(pRect), map_get_scale(pMap));
 	//g_print("box size pixels = %d,%d\n", map_screenrect_width(pRect), map_screenrect_height(pRect));
 	//g_print("box size = %f,%f\n", fBoxLongitude, fBoxLatitude);
 
 	// go from zoomed all the way to all the way out, looking for a rectangle
 	// that is wide & tall enough to show all of pRect
-	gboolean bFound = FALSE;
 	gint nZoomLevel;
 	for(nZoomLevel = MAX_ZOOM_LEVEL ; nZoomLevel >= MIN_ZOOM_LEVEL ; nZoomLevel--) {
 		pMap->uZoomLevel = nZoomLevel;
@@ -433,8 +442,8 @@
 	//
 	// Calculate how many world degrees we'll be drawing
 	//
-	pMetrics->fScreenLatitude = map_pixels_to_degrees(pMap, pMap->MapDimensions.uHeight, pMetrics->nZoomLevel);
-	pMetrics->fScreenLongitude = map_pixels_to_degrees(pMap, pMap->MapDimensions.uWidth, pMetrics->nZoomLevel);
+	pMetrics->fScreenLatitude = map_math_pixels_to_degrees_at_scale(pMap->MapDimensions.uHeight, map_get_scale(pMap));
+	pMetrics->fScreenLongitude = map_math_pixels_to_degrees_at_scale(pMap->MapDimensions.uWidth, map_get_scale(pMap));
 
 	// The world bounding box (expressed in lat/lon) of the data we will be drawing
 	pMetrics->rWorldBoundingBox.A.fLongitude = pMap->MapCenter.fLongitude - pMetrics->fScreenLongitude/2;
@@ -522,31 +531,6 @@
 								map_callback_free_locations_array);	/* value destroy function */
 }
 
-static void map_store_location(map_t* pMap, location_t* pLocation, gint nLocationSetID)
-{
-	GPtrArray* pLocationsArray;
-	pLocationsArray = g_hash_table_lookup(pMap->pLocationArrayHashTable, &nLocationSetID);
-	if(pLocationsArray != NULL) {
-		// found existing array
-		//g_print("existing for set %d\n", nLocationSetID);
-	}
-	else {
-		//g_print("new for set %d\n", nLocationSetID);
-
-		// need a new array
-		pLocationsArray = g_ptr_array_new();
-		g_assert(pLocationsArray != NULL);
-
-		gint* pKey = g_malloc(sizeof(gint));
-		*pKey = nLocationSetID;
-		g_hash_table_insert(pMap->pLocationArrayHashTable, pKey, pLocationsArray);
-	}
-
-	// add location to the array of locations!
-	g_ptr_array_add(pLocationsArray, pLocation);
-	//g_print("pLocationsArray->len = %d\n", pLocationsArray->len);
-}
-
 // ========================================================
 //  Functions to deal with "selected" locations (POI), which are always kept in RAM
 // ========================================================
@@ -679,5 +663,30 @@
 	g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, pSourceArray->len-1));
 //g_print("pDestArray->len = %d\n", pDestArray->len);
 }
+
+static void map_store_location(map_t* pMap, location_t* pLocation, gint nLocationSetID)
+{
+	GPtrArray* pLocationsArray;
+	pLocationsArray = g_hash_table_lookup(pMap->pLocationArrayHashTable, &nLocationSetID);
+	if(pLocationsArray != NULL) {
+		// found existing array
+		//g_print("existing for set %d\n", nLocationSetID);
+	}
+	else {
+		//g_print("new for set %d\n", nLocationSetID);
+
+		// need a new array
+		pLocationsArray = g_ptr_array_new();
+		g_assert(pLocationsArray != NULL);
+
+		gint* pKey = g_malloc(sizeof(gint));
+		*pKey = nLocationSetID;
+		g_hash_table_insert(pMap->pLocationArrayHashTable, pKey, pLocationsArray);
+	}
+
+	// add location to the array of locations!
+	g_ptr_array_add(pLocationsArray, pLocation);
+	//g_print("pLocationsArray->len = %d\n", pLocationsArray->len);
+}
 */
 #endif

Index: map.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map.h,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- map.h	10 Oct 2005 07:07:36 -0000	1.27
+++ map.h	18 Oct 2005 03:05:25 -0000	1.28
@@ -212,6 +212,7 @@
 //	maplayer_data_t	*apLayerData[ MAP_NUM_OBJECT_TYPES + 1 ];
 
 	maptilemanager_t* pTileManager;
+	GPtrArray* pLastActiveTilesArray;	// holds currently visible tiles at correct LOD (they're owned by tile manager)
 
 	// Locationsets
 	GHashTable		*pLocationArrayHashTable;
@@ -276,7 +277,7 @@
 
 // Gets and Sets
 guint16 map_get_zoomlevel(const map_t* pMap);
-guint32 map_get_zoomlevel_scale(const map_t* pMap);
+guint32 map_get_scale(const map_t* pMap);
 
 gboolean map_can_zoom_in(const map_t* pMap);
 gboolean map_can_zoom_out(const map_t* pMap);
@@ -309,8 +310,12 @@
 void map_release_pixmap(map_t* pMap);
 
 void map_draw(map_t* pMap, GdkPixmap* pTargetPixmap, gint nDrawFlags);
+void map_draw_xor_rect(map_t* pMap, GdkDrawable* pTargetDrawable, screenrect_t* pRect);
+
 void map_add_track(map_t* pMap, gint hTrack);
 
+void map_get_render_metrics(const map_t* pMap, rendermetrics_t* pMetrics);
+
 gboolean map_location_selection_add(map_t* pMap, gint nLocationID);
 gboolean map_location_selection_remove(map_t* pMap, gint nLocationID);
 

Index: map_draw_cairo.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_cairo.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- map_draw_cairo.c	6 Oct 2005 00:00:53 -0000	1.29
+++ map_draw_cairo.c	18 Oct 2005 03:05:25 -0000	1.30
@@ -45,9 +45,11 @@
 #include <cairo.h>
 #include <cairo-xlib.h>
 #include <math.h>
+#include <string.h>
 
 #include "main.h"
 #include "map.h"
+#include "map_math.h"
 #include "mainwindow.h"
 #include "util.h"
 #include "road.h"
@@ -59,7 +61,7 @@
 
 // Draw whole layers
 static void map_draw_cairo_layer_polygons(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle);
-static void map_draw_cairo_layer_roads(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle);
+static void map_draw_cairo_layer_lines(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle);
 static void map_draw_cairo_layer_road_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle);
 static void map_draw_cairo_layer_polygon_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle);
 
@@ -71,7 +73,7 @@
 
 // Draw labels for a single line/polygon
 static void map_draw_cairo_road_label(map_t* pMap, cairo_t *pCairo, maplayerstyle_t* pLayerStyle, rendermetrics_t* pRenderMetrics, GArray* pMapPointsArray, const gchar* pszLabel);
-static void map_draw_cairo_polygon_label(map_t* pMap, cairo_t *pCairo, maplayerstyle_t* pLayerStyle, rendermetrics_t* pRenderMetrics, GArray* pMapPointsArray, const gchar* pszLabel);
+static void map_draw_cairo_polygon_label(map_t* pMap, cairo_t *pCairo, maplayerstyle_t* pLayerStyle, rendermetrics_t* pRenderMetrics, GArray* pMapPointsArray, maprect_t* pBoundingRect, const gchar* pszLabel);
 
 // Draw map extras
 static void map_draw_cairo_map_scale(map_t* pMap, cairo_t *pCairo, rendermetrics_t* pRenderMetrics);
@@ -147,6 +149,14 @@
 
 			if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LINES) {
 				if(nDrawFlags & DRAWFLAG_GEOMETRY) {
+					gint iTile;
+					for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+						maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
+						map_draw_cairo_layer_lines(pMap, pCairo, pRenderMetrics,
+												 pTile->apMapObjectArrays[pLayer->nDataSource],               // data
+												 pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);       // style
+					}
+
 //                     map_draw_cairo_layer_roads(pMap, pCairo, pRenderMetrics,
 //                                                pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
 //                                                pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
@@ -154,6 +164,13 @@
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGONS) {
 				if(nDrawFlags & DRAWFLAG_GEOMETRY) {
+					gint iTile;
+					for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+						maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
+						map_draw_cairo_layer_polygons(pMap, pCairo, pRenderMetrics,
+												 pTile->apMapObjectArrays[pLayer->nDataSource],               // data
+												 pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);       // style
+					}
 //                     map_draw_cairo_layer_polygons(pMap, pCairo, pRenderMetrics,
 //                                                   pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
 //                                                   pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
@@ -256,14 +273,16 @@
 
 	for(i=0 ; i<pRoadsArray->len ; i++) {
 		road_t* pRoad = g_ptr_array_index(pRoadsArray, i);
-		
-		if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) {
+
+		if(pRoad->pszName[0] == '\0') {
 			continue;
 		}
 
-		if(pRoad->pszName[0] != '\0') {
-			map_draw_cairo_road_label(pMap, pCairo, pLayerStyle, pRenderMetrics, pRoad->pMapPointsArray, pRoad->pszName);
+		if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) {
+			continue;
 		}
+
+		map_draw_cairo_road_label(pMap, pCairo, pLayerStyle, pRenderMetrics, pRoad->pMapPointsArray, pRoad->pszName);
 	}
 	cairo_restore(pCairo);
 }
@@ -287,9 +306,15 @@
 	gint i;
 	for(i=0 ; i<pRoadsArray->len ; i++) {
 		road_t* pRoad = g_ptr_array_index(pRoadsArray, i);
-		if(pRoad->pszName[0] != '\0') {
-			map_draw_cairo_polygon_label(pMap, pCairo, pLayerStyle, pRenderMetrics, pRoad->pMapPointsArray, pRoad->pszName);
+		if(pRoad->pszName[0] == '\0') {
+			continue;
 		}
+
+		if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) {
+			continue;
+		}
+
+		map_draw_cairo_polygon_label(pMap, pCairo, pLayerStyle, pRenderMetrics, pRoad->pMapPointsArray, &(pRoad->rWorldBoundingBox), pRoad->pszName);
 	}
 	cairo_restore(pCairo);
 }
@@ -297,7 +322,7 @@
 //
 // Draw a whole layer of lines
 //
-void map_draw_cairo_layer_roads(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle)
+void map_draw_cairo_layer_lines(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle)
 {
 	mappoint_t* pPoint;
 	road_t* pRoad;
@@ -346,25 +371,32 @@
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
-		if(pRoad->pMapPointsArray->len >= 2) {
-			pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, 0);
+		EOverlapType eOverlapType = map_rect_a_overlap_type_with_rect_b(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox));
+		if(eOverlapType == OVERLAP_NONE) {
+			continue;
+		}
 
-			// go to index 0
-			cairo_move_to(pCairo, 
+		if(pRoad->pMapPointsArray->len < 2) {
+			continue;
+		}
+
+		pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, 0);
+
+		// go to index 0
+		cairo_move_to(pCairo, 
+					  pLayerStyle->nPixelOffsetX + SCALE_X(pRenderMetrics, pPoint->fLongitude), 
+					  pLayerStyle->nPixelOffsetY + SCALE_Y(pRenderMetrics, pPoint->fLatitude));
+
+		// start at index 1 (0 was used above)
+		for(iPoint=1 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
+			pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);//~ g_print("  point (%.05f,%.05f)\n", ScaleX(pPoint->fLongitude), ScaleY(pPoint->fLatitude));
+			cairo_line_to(pCairo, 
 						  pLayerStyle->nPixelOffsetX + SCALE_X(pRenderMetrics, pPoint->fLongitude), 
 						  pLayerStyle->nPixelOffsetY + SCALE_Y(pRenderMetrics, pPoint->fLatitude));
-
-			// start at index 1 (0 was used above)
-			for(iPoint=1 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
-				pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);//~ g_print("  point (%.05f,%.05f)\n", ScaleX(pPoint->fLongitude), ScaleY(pPoint->fLatitude));
-				cairo_line_to(pCairo, 
-							  pLayerStyle->nPixelOffsetX + SCALE_X(pRenderMetrics, pPoint->fLongitude), 
-							  pLayerStyle->nPixelOffsetY + SCALE_Y(pRenderMetrics, pPoint->fLatitude));
-			}
+		}
 #ifdef ENABLE_HACK_AROUND_CAIRO_LINE_CAP_BUG
-			cairo_stroke(pCairo);	// this is wrong place for it (see below)
+		cairo_stroke(pCairo);	// this is wrong place for it (see below)
 #endif
-   		}
 	}
 
 #ifndef ENABLE_HACK_AROUND_CAIRO_LINE_CAP_BUG
@@ -376,48 +408,57 @@
 	cairo_restore(pCairo);
 }
 
+void map_draw_cairo_polygon(cairo_t* pCairo, const rendermetrics_t* pRenderMetrics, const GArray* pMapPointsArray)
+{
+	// move to index 0
+	mappoint_t* pPoint = &g_array_index(pMapPointsArray, mappoint_t, 0);
+	cairo_move_to(pCairo, SCALE_X(pRenderMetrics, pPoint->fLongitude), SCALE_Y(pRenderMetrics, pPoint->fLatitude));
+
+	// start at index 1 (0 was used above)
+	gint iPoint;
+	for(iPoint=1 ; iPoint<pMapPointsArray->len ; iPoint++) {
+		pPoint = &g_array_index(pMapPointsArray, mappoint_t, iPoint);				
+		cairo_line_to(pCairo, SCALE_X(pRenderMetrics, pPoint->fLongitude), SCALE_Y(pRenderMetrics, pPoint->fLatitude));
+	}
+}
+
 void map_draw_cairo_layer_polygons(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle)
 {
-#if 0	// GGGGGGGGGGGGGGGG
 	road_t* pRoad;
-	mappoint_t* pPoint;
 
-	gdouble fLineWidth = pSubLayerStyle->afLineWidths[pRenderMetrics->nZoomLevel-1];
-	if(fLineWidth == 0.0) return;	// Don't both drawing with line width 0
-	if(pSubLayerStyle->clrColor.fAlpha == 0.0) return;	// invisible?
+	if(pLayerStyle->clrPrimary.fAlpha == 0.0) return;
 
 	// Set layer attributes	
-	map_draw_cairo_set_rgba(pCairo, &(pSubLayerStyle->clrColor));
-	cairo_set_line_width(pCairo, fLineWidth);
+	map_draw_cairo_set_rgba(pCairo, &(pLayerStyle->clrPrimary));
 	cairo_set_fill_rule(pCairo, CAIRO_FILL_RULE_EVEN_ODD);
-
-	cairo_set_line_join(pCairo, pSubLayerStyle->nJoinStyle);
-	cairo_set_line_cap(pCairo, pSubLayerStyle->nCapStyle);	/* CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_CAP */
-//	cairo_set_dash(pCairo, g_aDashStyles[pSubLayerStyle->nDashStyle].pfList, g_aDashStyles[pSubLayerStyle->nDashStyle].nCount, 0.0);
+	cairo_set_line_join(pCairo, pLayerStyle->nJoinStyle);
 
 	gint iString;
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
-		if(pRoad->pMapPointsArray->len >= 3) {
-			pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, 0);
+		EOverlapType eOverlapType = map_rect_a_overlap_type_with_rect_b(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox));
+		if(eOverlapType == OVERLAP_NONE) {
+//			g_print("OOPS!  A linestring with <3 points (%d)\n", pPointString->pPointsArray->len);
+			continue;
+		}
 
-			// move to index 0
-			cairo_move_to(pCairo, SCALE_X(pRenderMetrics, pPoint->fLongitude), SCALE_Y(pRenderMetrics, pPoint->fLatitude));
+		if(pRoad->pMapPointsArray->len < 3) {
+			continue;
+		}
 
-			// start at index 1 (0 was used above)
-			gint iPoint;
-			for(iPoint=1 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
-				pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);				
-				cairo_line_to(pCairo, SCALE_X(pRenderMetrics, pPoint->fLongitude), SCALE_Y(pRenderMetrics, pPoint->fLatitude));
-			}
+		if(eOverlapType == OVERLAP_PARTIAL) {
+			// draw clipped
+			GArray* pClipped = g_array_sized_new(FALSE, FALSE, sizeof(mappoint_t), pRoad->pMapPointsArray->len + 20);	// it's rarely more than a few extra points
+			map_math_clip_pointstring_to_worldrect(pRoad->pMapPointsArray, &(pRenderMetrics->rWorldBoundingBox), pClipped);
+			map_draw_cairo_polygon(pCairo, pRenderMetrics, pClipped);
+			g_array_free(pClipped, TRUE);
 		}
 		else {
-//			g_print("OOPS!  A linestring with <3 points (%d)\n", pPointString->pPointsArray->len);
+			map_draw_cairo_polygon(pCairo, pRenderMetrics, pRoad->pMapPointsArray);
 		}
 	}
 	cairo_fill(pCairo);
-#endif
 }
 
 void map_draw_cairo_layer_points(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray)
@@ -464,7 +505,7 @@
 */
 }
 
-#define ROAD_MAX_SEGMENTS 100
+#define ROAD_MAX_SEGMENTS 		(200)
 #define DRAW_LABEL_BUFFER_LEN	(200)
 
 typedef struct labelposition {
@@ -504,7 +545,7 @@
 	gdouble fRun = fX2 - fX1;
 	gdouble fLineLengthSquared = (fRun*fRun) + (fRise*fRise);
 
-	gchar* pszFontFamily = ROAD_FONT;
+	//gchar* pszFontFamily = ROAD_FONT;
 
 	cairo_save(pCairo);
 
@@ -653,7 +694,7 @@
 		return;
 	}
 
-	gchar* pszFontFamily = ROAD_FONT;		// XXX: remove hardcoded font
+	//gchar* pszFontFamily = ROAD_FONT;		// XXX: remove hardcoded font
 
 	cairo_save(pCairo);
 
@@ -728,7 +769,7 @@
 
 	//GPtrArray *pPositionsPtrArray = g_ptr_array_new();
 	gdouble fMaxScore = 0;
-	gint iBestPosition;
+	gint iBestPosition = -1;
 
 	for(iPosition = 1 ; iPosition < nPositions ; iPosition++) {
 		// finish calculating mean slope
@@ -779,6 +820,11 @@
 //                 pPos->fScore);
 //     }
 
+	if(iBestPosition == -1) {
+		cairo_restore(pCairo);
+		return;
+	}
+
 	cairo_font_extents_t font_extents;
 	cairo_font_extents(pCairo, &font_extents);
 
@@ -1135,143 +1181,119 @@
 //
 // Draw a single polygon label
 //
-void map_draw_cairo_polygon_label(map_t* pMap, cairo_t *pCairo, maplayerstyle_t* pLayerStyle, rendermetrics_t* pRenderMetrics, GArray* pMapPointsArray, const gchar* pszLabel)
+void map_draw_cairo_polygon_label(map_t* pMap, cairo_t *pCairo, maplayerstyle_t* pLayerStyle, rendermetrics_t* pRenderMetrics, GArray* pMapPointsArray, maprect_t* pBoundingRect, const gchar* pszLabel)
 {
-	if(pMapPointsArray->len < 3) return;
-
-	if(FALSE == scenemanager_can_draw_label_at(pMap->pSceneManager, pszLabel, NULL, SCENEMANAGER_FLAG_PARTLY_ON_SCREEN)) {
-		return;
-	}
-
-	gdouble fMaxLat = MIN_LATITUDE;	// init to the worst possible value so first point will override
-	gdouble fMinLat = MAX_LATITUDE;
-	gdouble fMaxLon = MIN_LONGITUDE;
-	gdouble fMinLon = MAX_LONGITUDE;
-	
-	gint i;
-	for(i=0 ; i<pMapPointsArray->len ; i++) {
-		mappoint_t* pMapPoint = &g_array_index(pMapPointsArray, mappoint_t, i);
-
-		// find polygon bounding box for visibility test below
-		fMaxLat = max(pMapPoint->fLatitude,fMaxLat);
-		fMinLat = min(pMapPoint->fLatitude,fMinLat);
-		fMaxLon = max(pMapPoint->fLongitude,fMaxLon);
-		fMinLon = min(pMapPoint->fLongitude,fMinLon);
-	}
-
-	// rectangle overlap test
-	if((fMaxLat < pRenderMetrics->rWorldBoundingBox.A.fLatitude)
-	   || (fMaxLon < pRenderMetrics->rWorldBoundingBox.A.fLongitude)
-	   || (fMinLat > pRenderMetrics->rWorldBoundingBox.B.fLatitude)
-	   || (fMinLon > pRenderMetrics->rWorldBoundingBox.B.fLongitude))
-	{
-	    return;	// not visible
-	}
-
-	gdouble fAreaOriginX = SCALE_X(pRenderMetrics, fMinLon);
-	gdouble fAreaOriginY = SCALE_Y(pRenderMetrics, fMaxLat);
-//g_print("Area origin (%f,%f)\n", fAreaOriginX, fAreaOriginY);
-
-	gdouble fAreaWidth = SCALE_X(pRenderMetrics, fMaxLon) - SCALE_X(pRenderMetrics, fMinLon);
-	gdouble fAreaHeight = SCALE_Y(pRenderMetrics, fMinLat) - SCALE_Y(pRenderMetrics, fMaxLat);
-//g_print("Area size (%f,%f)\n", fAreaWidth, fAreaHeight);
-
-	gchar** aLines = util_split_words_onto_two_lines(pszLabel, MIN_AREA_LABEL_LINE_LENGTH, MAX_AREA_LABEL_LINE_LENGTH);
-	gint nLineCount = g_strv_length(aLines);	// could be one or two, unless we change above function
-	gint* anWidths = g_new0(gint, nLineCount);
-
-	gdouble fLabelBoxWidth = 0.0;
-	gdouble fLabelBoxHeight = 0.0;
-
-	cairo_text_extents_t extents;
-	for(i=0 ; i<nLineCount ; i++) {
-		cairo_text_extents(pCairo, aLines[i], &extents);
-		anWidths[i] = extents.width;
-		fLabelBoxWidth = max(fLabelBoxWidth, (gdouble)extents.width);	// as wide as the widest line
-		fLabelBoxHeight += (gdouble)extents.height;						// total height of all lines
-	}
-
-	gdouble fOneLineHeight = fLabelBoxHeight / nLineCount;
-
-	gdouble fHorizontalPadding = (fAreaWidth - fLabelBoxWidth);
-	gdouble fVerticalPadding = (fAreaHeight - fLabelBoxHeight);
-//g_print("padding (%f,%f)\n", fHorizontalPadding, fVerticalPadding);
-
-	// various places to try...
-	struct { gdouble fX,fY; } afPercentagesOfPadding[] = {
-		{0.50, 0.50},
-		
-		// first the close-to-center positions (.25 and .75)
-		{0.50, 0.25}, {0.50, 0.75},	// dodge up/down
-		{0.25, 0.50}, {0.75, 0.50}, // dodge left/right middle
-		{0.25, 0.25}, {0.75, 0.25}, // upper left/right
-		{0.25, 0.75}, {0.75, 0.75}, // lower left/right
-
-		// now the far-from-center positions (0.0 and 1.0)
-//		{0.50, 0.00}, {0.50, 1.00},	// dodge up/down
-//		{0.00, 0.50}, {1.00, 0.50}, // dodge left/right middle
-//		{0.00, 0.00}, {1.00, 0.00}, // upper left/right
-//		{0.00, 1.00}, {1.00, 1.00}, // lower left/right		
-	};
-
-	gboolean bSuccess = FALSE;
-	gint iSlot;
-	for(iSlot=0 ; iSlot<G_N_ELEMENTS(afPercentagesOfPadding) ; iSlot++) {
-		gdouble fDrawBoxCornerX = fAreaOriginX + (fHorizontalPadding * afPercentagesOfPadding[iSlot].fX);
-		gdouble fDrawBoxCornerY = fAreaOriginY + (fVerticalPadding * afPercentagesOfPadding[iSlot].fY);
-
-		GdkRectangle rcLabelOutline;
-		rcLabelOutline.x = (gint)(fDrawBoxCornerX);
-		rcLabelOutline.width = (gint)(fLabelBoxWidth);
-		rcLabelOutline.y = (gint)(fDrawBoxCornerY);
-		rcLabelOutline.height = (gint)(fLabelBoxHeight);
-		if(FALSE == scenemanager_can_draw_rectangle(pMap->pSceneManager, &rcLabelOutline, SCENEMANAGER_FLAG_FULLY_ON_SCREEN)) {
-			continue;
-		}
-
-		// passed test!  claim this label and rectangle area
-		scenemanager_claim_label(pMap->pSceneManager, pszLabel);
-		scenemanager_claim_rectangle(pMap->pSceneManager, &rcLabelOutline);
-
-		//
-		// Draw Halo for all lines, if style dictates.
-		//
-		if(pLayerStyle->fHaloSize >= 0) {
-			cairo_save(pCairo);
-
-			map_draw_cairo_set_rgba(pCairo, &(pLayerStyle->clrHalo));
-
-			for(i=0 ; i<nLineCount ; i++) {
-				gint iHaloOffsets;
-				for(iHaloOffsets = 0 ; iHaloOffsets < G_N_ELEMENTS(g_aHaloOffsets); iHaloOffsets++) {
-					cairo_move_to(pCairo,
-								  g_aHaloOffsets[iHaloOffsets].nX + fDrawBoxCornerX + ((fLabelBoxWidth - anWidths[i])/2),
-								  g_aHaloOffsets[iHaloOffsets].nY + fDrawBoxCornerY + ((i+1) * fOneLineHeight));
-					cairo_show_text(pCairo, aLines[i]);
-				}
-			}
-			cairo_restore(pCairo);
-		}
-
-		//
-		// Draw text for all lines.
-		//
-		for(i=0 ; i<nLineCount ; i++) {
-			// Get total width of string
-			cairo_move_to(pCairo, 
-						  fDrawBoxCornerX + ((fLabelBoxWidth - anWidths[i])/2), 
-						  fDrawBoxCornerY + ((i+1) * fOneLineHeight));
-			cairo_show_text(pCairo, aLines[i]);
-		}
-		break;
-	}
-
-		// draw it
-//		cairo_save(pCairo);
-
-//		cairo_restore(pCairo);
-	g_strfreev(aLines);
-	g_free(anWidths);
+	// XXX: update to use bounding box instead of (removed) fMaxLon etc.
+//     if(pMapPointsArray->len < 3) return;
+//
+//     if(FALSE == scenemanager_can_draw_label_at(pMap->pSceneManager, pszLabel, NULL, SCENEMANAGER_FLAG_PARTLY_ON_SCREEN)) {
+//         return;
+//     }
+//
+//     gdouble fAreaOriginX = SCALE_X(pRenderMetrics, fMinLon);
+//     gdouble fAreaOriginY = SCALE_Y(pRenderMetrics, fMaxLat);
+//     //g_print("Area origin (%f,%f)\n", fAreaOriginX, fAreaOriginY);
+//
+//     gdouble fAreaWidth = SCALE_X(pRenderMetrics, fMaxLon) - SCALE_X(pRenderMetrics, fMinLon);
+//     gdouble fAreaHeight = SCALE_Y(pRenderMetrics, fMinLat) - SCALE_Y(pRenderMetrics, fMaxLat);
+//     //g_print("Area size (%f,%f)\n", fAreaWidth, fAreaHeight);
+//
+//     gchar** aLines = util_split_words_onto_two_lines(pszLabel, MIN_AREA_LABEL_LINE_LENGTH, MAX_AREA_LABEL_LINE_LENGTH);
+//     gint nLineCount = g_strv_length(aLines);    // could be one or two, unless we change above function
+//     gint* anWidths = g_new0(gint, nLineCount);
+//
+//     gdouble fLabelBoxWidth = 0.0;
+//     gdouble fLabelBoxHeight = 0.0;
+//
+//     cairo_text_extents_t extents;
+//     for(i=0 ; i<nLineCount ; i++) {
+//         cairo_text_extents(pCairo, aLines[i], &extents);
+//         anWidths[i] = extents.width;
+//         fLabelBoxWidth = max(fLabelBoxWidth, (gdouble)extents.width);   // as wide as the widest line
+//         fLabelBoxHeight += (gdouble)extents.height;                     // total height of all lines
+//     }
+//
+//     gdouble fOneLineHeight = fLabelBoxHeight / nLineCount;
+//
+//     gdouble fHorizontalPadding = (fAreaWidth - fLabelBoxWidth);
+//     gdouble fVerticalPadding = (fAreaHeight - fLabelBoxHeight);
+//     //g_print("padding (%f,%f)\n", fHorizontalPadding, fVerticalPadding);
+//
+//     // various places to try...
+//     struct { gdouble fX,fY; } afPercentagesOfPadding[] = {
+//         {0.50, 0.50},
+//
+//         // first the close-to-center positions (.25 and .75)
+//         {0.50, 0.25}, {0.50, 0.75}, // dodge up/down
+//         {0.25, 0.50}, {0.75, 0.50}, // dodge left/right middle
+//         {0.25, 0.25}, {0.75, 0.25}, // upper left/right
+//         {0.25, 0.75}, {0.75, 0.75}, // lower left/right
+//
+//         // now the far-from-center positions (0.0 and 1.0)
+// //      {0.50, 0.00}, {0.50, 1.00}, // dodge up/down
+// //      {0.00, 0.50}, {1.00, 0.50}, // dodge left/right middle
+// //      {0.00, 0.00}, {1.00, 0.00}, // upper left/right
+// //      {0.00, 1.00}, {1.00, 1.00}, // lower left/right
+//     };
+//
+//     //gboolean bSuccess = FALSE;
+//     gint iSlot;
+//     for(iSlot=0 ; iSlot<G_N_ELEMENTS(afPercentagesOfPadding) ; iSlot++) {
+//         gdouble fDrawBoxCornerX = fAreaOriginX + (fHorizontalPadding * afPercentagesOfPadding[iSlot].fX);
+//         gdouble fDrawBoxCornerY = fAreaOriginY + (fVerticalPadding * afPercentagesOfPadding[iSlot].fY);
+//
+//         GdkRectangle rcLabelOutline;
+//         rcLabelOutline.x = (gint)(fDrawBoxCornerX);
+//         rcLabelOutline.width = (gint)(fLabelBoxWidth);
+//         rcLabelOutline.y = (gint)(fDrawBoxCornerY);
+//         rcLabelOutline.height = (gint)(fLabelBoxHeight);
+//         if(FALSE == scenemanager_can_draw_rectangle(pMap->pSceneManager, &rcLabelOutline, SCENEMANAGER_FLAG_FULLY_ON_SCREEN)) {
+//             continue;
+//         }
+//
+//         // passed test!  claim this label and rectangle area
+//         scenemanager_claim_label(pMap->pSceneManager, pszLabel);
+//         scenemanager_claim_rectangle(pMap->pSceneManager, &rcLabelOutline);
+//
+//         //
+//         // Draw Halo for all lines, if style dictates.
+//         //
+//         if(pLayerStyle->fHaloSize >= 0) {
+//             cairo_save(pCairo);
+//
+//             map_draw_cairo_set_rgba(pCairo, &(pLayerStyle->clrHalo));
+//
+//             for(i=0 ; i<nLineCount ; i++) {
+//                 gint iHaloOffsets;
+//                 for(iHaloOffsets = 0 ; iHaloOffsets < G_N_ELEMENTS(g_aHaloOffsets); iHaloOffsets++) {
+//                     cairo_move_to(pCairo,
+//                                   g_aHaloOffsets[iHaloOffsets].nX + fDrawBoxCornerX + ((fLabelBoxWidth - anWidths[i])/2),
+//                                   g_aHaloOffsets[iHaloOffsets].nY + fDrawBoxCornerY + ((i+1) * fOneLineHeight));
+//                     cairo_show_text(pCairo, aLines[i]);
+//                 }
+//             }
+//             cairo_restore(pCairo);
+//         }
+//
+//         //
+//         // Draw text for all lines.
+//         //
+//         for(i=0 ; i<nLineCount ; i++) {
+//             // Get total width of string
+//             cairo_move_to(pCairo,
+//                           fDrawBoxCornerX + ((fLabelBoxWidth - anWidths[i])/2),
+//                           fDrawBoxCornerY + ((i+1) * fOneLineHeight));
+//             cairo_show_text(pCairo, aLines[i]);
+//         }
+//         break;
+//     }
+//
+//         // draw it
+// //      cairo_save(pCairo);
+//
+// //      cairo_restore(pCairo);
+//     g_strfreev(aLines);
+//     g_free(anWidths);
 }
 
 static void map_draw_cairo_map_scale(map_t* pMap, cairo_t *pCairo, rendermetrics_t* pRenderMetrics)

Index: map_draw_gdk.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_gdk.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- map_draw_gdk.c	11 Oct 2005 23:28:45 -0000	1.28
+++ map_draw_gdk.c	18 Oct 2005 03:05:25 -0000	1.29
@@ -24,6 +24,8 @@
 #define MAX_GDK_LINE_SEGMENTS (2000)
 
 //#define ENABLE_MAP_GRAYSCALE_HACK 	// just a little test.  black and white might be good for something
+//#define ENABLE_CLIPPER_SHRINK_RECT_TEST	// NOTE: even with this on, objects won't be clipped unless they cross the real screen border
+//#define ENABLE_RANDOM_ROAD_COLORS
 
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
@@ -106,9 +108,6 @@
 	if(nDrawFlags & DRAWFLAG_GEOMETRY) {
 		gint i;
 
-		// 2.1. Draw Background
-//		map_draw_gdk_background(pMap, pPixmap);
-
 		gint nStyleZoomLevel = g_sZoomLevels[pRenderMetrics->nZoomLevel-1].nStyleZoomLevel;
 
 		// 2.2. Draw layer list in reverse order (painter's algorithm: http://en.wikipedia.org/wiki/Painter's_algorithm )
@@ -204,10 +203,7 @@
 
 static void map_draw_gdk_layer_polygons(map_t* pMap, GdkPixmap* pPixmap, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, maplayerstyle_t* pLayerStyle)
 {
-	mappoint_t* pPoint;
 	road_t* pRoad;
-	gint iString;
-	gint iPoint;
 
 	if(pLayerStyle->clrPrimary.fAlpha == 0.0) return;	// invisible?  (not that we respect it in gdk drawing anyway)
 	if(pRoadsArray->len == 0) return;
@@ -235,6 +231,7 @@
 	context.pLayerStyle = pLayerStyle;
 	context.pRenderMetrics = pRenderMetrics;
 
+	gint iString;
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
@@ -256,8 +253,10 @@
 
 		if(eOverlapType == OVERLAP_PARTIAL) {
 			// draw clipped
-			// XXX: Currently no clipping, just draw normally
-			map_draw_gdk_polygons(pRoad->pMapPointsArray, &context);
+       		GArray* pClipped = g_array_sized_new(FALSE, FALSE, sizeof(mappoint_t), pRoad->pMapPointsArray->len + 20);	// it's rarely more than a few extra points
+			map_math_clip_pointstring_to_worldrect(pRoad->pMapPointsArray, &(pRenderMetrics->rWorldBoundingBox), pClipped);
+			map_draw_gdk_polygons(pClipped, &context);
+			g_array_free(pClipped, TRUE);
 		}
 		else {
 			// draw normally
@@ -337,6 +336,8 @@
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
+
+
 		EOverlapType eOverlapType = map_rect_a_overlap_type_with_rect_b(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox));
 		if(eOverlapType == OVERLAP_NONE) {
 			continue;
@@ -352,8 +353,13 @@
 			continue;
 		}
 
+#ifdef ENABLE_RANDOM_ROAD_COLORS
+		color_t clr;
+		util_random_color(&clr);
+		map_draw_gdk_set_color(pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], &clr);
+#endif
 		if(eOverlapType == OVERLAP_PARTIAL) {
-			// draw clipped
+			// TODO: draw clipped
 			map_draw_gdk_lines(pRoad->pMapPointsArray, &context);
 		}
 		else {

Index: map_hittest.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_hittest.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- map_hittest.c	11 Oct 2005 23:28:45 -0000	1.2
+++ map_hittest.c	18 Oct 2005 03:05:25 -0000	1.3
@@ -26,59 +26,100 @@
 #include "map.h"
 #include "map_hittest.h"
 #include "map_math.h"
+#include "map_style.h"
 #include "road.h"
 #include "location.h"
 #include "locationset.h"
 
-
 static gboolean map_hittest_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine);
 static ESide map_hittest_side_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pClosestPointOnLine, mappoint_t* pHitPoint);
 static gboolean map_hittest_locations(map_t* pMap, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
 static gboolean map_hittest_locationsets(map_t* pMap, rendermetrics_t* pRenderMetrics, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
 
+static gboolean map_hittest_layer_lines(GPtrArray* pRoadsArray, gdouble fMaxDistance, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
+static gboolean map_hittest_layer_polygons(GPtrArray* pMapObjectArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
+
+#define EXTRA_CLICKABLE_ROAD_IN_PIXELS	(3)
+
 // ========================================================
 //  Hit Testing
 // ========================================================
 
 gboolean map_hittest(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct)
 {
-#if 0	// GGGGGGGGGGGGGGGG
 	rendermetrics_t rendermetrics;
 	map_get_render_metrics(pMap, &rendermetrics);
 
-	if(map_hittest_locationselections(pMap, &rendermetrics, pMap->pLocationSelectionArray, pMapPoint, ppReturnStruct)) {
-		return TRUE;
-	}
+	GPtrArray* pTiles = pMap->pLastActiveTilesArray;
+	g_return_val_if_fail(pTiles != NULL, FALSE);
 
-	if(map_hittest_locationsets(pMap, &rendermetrics, pMapPoint, ppReturnStruct)) {
-		return TRUE;
-	}
+//     if(map_hittest_locationselections(pMap, &rendermetrics, pMap->pLocationSelectionArray, pMapPoint, ppReturnStruct)) {
+//         return TRUE;
+//     }
+//
+//     if(map_hittest_locationsets(pMap, &rendermetrics, pMapPoint, ppReturnStruct)) {
+//         return TRUE;
+//     }
+
+	gint nStyleZoomLevel = g_sZoomLevels[ map_get_zoomlevel(pMap) -1 ].nStyleZoomLevel;
 
 	// Test things in the REVERSE order they are drawn (otherwise we'll match things that have been painted-over)
 	gint i;
-	for(i=G_N_ELEMENTS(layerdraworder)-1 ; i>=0 ; i--) {
-		if(layerdraworder[i].eSubLayerRenderType != SUBLAYER_RENDERTYPE_LINES) continue;
-
-		gint nLayer = layerdraworder[i].nLayer;
-
-		// use width from whichever layer it's wider in
-		gdouble fLineWidth = max(g_aLayers[nLayer]->Style.aSubLayers[0].afLineWidths[pMap->uZoomLevel-1],
-					 g_aLayers[nLayer]->Style.aSubLayers[1].afLineWidths[pMap->uZoomLevel-1]);
+	for(i=0 ; i<pMap->pLayersArray->len ; i++) {
+		maplayer_t* pLayer = g_ptr_array_index(pMap->pLayersArray, i);
+		maplayerstyle_t* pLayerStyle = pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1];
 
-#define EXTRA_CLICKABLE_ROAD_IN_PIXELS	(3)
+		if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LINES) {
+			gdouble fLineWidth = pLayerStyle->fLineWidth;
+	
+			// XXX: hack, map_pixels should really take a floating point instead.
+			gdouble fMaxDistance = map_math_pixels_to_degrees_at_scale(1, map_get_scale(pMap)) * ((fLineWidth/2) + EXTRA_CLICKABLE_ROAD_IN_PIXELS);  // half width on each side
 
-		// make thin roads a little easier to hit
-		// fLineWidth = max(fLineWidth, MIN_ROAD_HIT_TARGET_WIDTH);
+			gint iTile;
+			for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+				maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
 
-		// XXX: hack, map_pixels should really take a floating point instead.
-		gdouble fMaxDistance = map_pixels_to_degrees(pMap, 1, pMap->uZoomLevel) * ((fLineWidth/2) + EXTRA_CLICKABLE_ROAD_IN_PIXELS);  // half width on each side
+				if(map_hittest_layer_lines(pTile->apMapObjectArrays[pLayer->nDataSource],
+										   fMaxDistance,
+										   pMapPoint,
+										   ppReturnStruct))
+				{
+					return TRUE;
+				}
+			}
+		}
+		else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGONS) {
+			gint iTile;
+			for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+				maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
 
-		if(map_hittest_layer_roads(pMap->apLayerData[nLayer]->pRoadsArray, fMaxDistance, pMapPoint, ppReturnStruct)) {
-			return TRUE;
+				if(map_hittest_layer_polygons(pTile->apMapObjectArrays[pLayer->nDataSource],
+											  pMapPoint,
+											  ppReturnStruct))
+				{
+					return TRUE;
+				}
+			}
 		}
-		// otherwise try next layer...
 	}
-#endif
+//     gint i;
+//     for(i=G_N_ELEMENTS(layerdraworder)-1 ; i>=0 ; i--) {
+//         if(layerdraworder[i].eSubLayerRenderType != SUBLAYER_RENDERTYPE_LINES) continue;
+//
+//         gint nLayer = layerdraworder[i].nLayer;
+//
+//         // use width from whichever layer it's wider in
+//         gdouble fLineWidth = max(g_aLayers[nLayer]->Style.aSubLayers[0].afLineWidths[pMap->uZoomLevel-1],
+//                      g_aLayers[nLayer]->Style.aSubLayers[1].afLineWidths[pMap->uZoomLevel-1]);
+//
+//         // XXX: hack, map_pixels should really take a floating point instead.
+//         gdouble fMaxDistance = map_pixels_to_degrees(pMap, 1, pMap->uZoomLevel) * ((fLineWidth/2) + EXTRA_CLICKABLE_ROAD_IN_PIXELS);  // half width on each side
+//
+//         if(map_hittest_layer_lines(pMap->apLayerData[nLayer]->pRoadsArray, fMaxDistance, pMapPoint, ppReturnStruct)) {
+//             return TRUE;
+//         }
+//         // otherwise try next layer...
+//     }
 	return FALSE;
 }
 
@@ -96,7 +137,7 @@
 	g_free(pHitStruct);
 }
 
-static gboolean map_hittest_layer_roads(GPtrArray* pRoadsArray, gdouble fMaxDistance, mappoint_t* pHitPoint, maphit_t** ppReturnStruct)
+static gboolean map_hittest_layer_lines(GPtrArray* pMapObjectArray, gdouble fMaxDistance, mappoint_t* pHitPoint, maphit_t** ppReturnStruct)
 {
 	g_assert(ppReturnStruct != NULL);
 	g_assert(*ppReturnStruct == NULL);	// pointer to null pointer
@@ -110,9 +151,11 @@
 
 	// Loop through line strings, order doesn't matter here since they're all on the same level.
 	gint iString;
-	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
-		road_t* pRoad = g_ptr_array_index(pRoadsArray, iString);
+	for(iString=0 ; iString<pMapObjectArray->len ; iString++) {
+		road_t* pRoad = g_ptr_array_index(pMapObjectArray, iString);
 		if(pRoad->pMapPointsArray->len < 2) continue;
+		// Can't do bounding box test on lines (unless we expand the box by fMaxDistance pixels)
+		//if(!map_math_mappoint_in_maprect(pHitPoint, &(pRoad->rWorldBoundingBox))) continue;
 
 		// start on 1 so we can do -1 trick below
 		gint iPoint;
@@ -166,6 +209,37 @@
 	return FALSE;
 }
 
+static gboolean map_hittest_layer_polygons(GPtrArray* pMapObjectArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct)
+{
+	g_assert(ppReturnStruct != NULL);
+	g_assert(*ppReturnStruct == NULL);	// pointer to null pointer
+
+	/* this is helpful for testing with the g_print()s in map_hit_test_line() */
+/*         mappoint_t p1 = {2,2};                */
+/*         mappoint_t p2 = {-10,10};             */
+/*         mappoint_t p3 = {0,10};               */
+/*         map_hit_test_line(&p1, &p2, &p3, 20); */
+/*         return FALSE;                         */
+
+	// Loop through line strings, order doesn't matter here since they're all on the same level.
+	gint iString;
+	for(iString=0 ; iString<pMapObjectArray->len ; iString++) {
+		road_t* pRoad = g_ptr_array_index(pMapObjectArray, iString);
+		if(pRoad->pMapPointsArray->len < 2) continue;
+		if(!map_math_mappoint_in_maprect(pHitPoint, &(pRoad->rWorldBoundingBox))) continue;
+
+		if(map_math_mappoint_in_polygon(pHitPoint, pRoad->pMapPointsArray)) {
+			maphit_t* pHitStruct = g_new0(maphit_t, 1);
+			pHitStruct->pszText = g_strdup("polygon hit");
+			pHitStruct->eHitType = MAP_HITTYPE_POLYGON;
+			
+			*ppReturnStruct = pHitStruct;
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
 static ESide map_hittest_side_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pClosestPointOnLine, mappoint_t* pHitPoint)
 {
 	// make a translated-to-origin *perpendicular* vector of the line (points to the "left" of the line when walking from point 1 to 2)
@@ -204,7 +278,7 @@
 // hit test all locations
 static gboolean map_hittest_locationsets(map_t* pMap, rendermetrics_t* pRenderMetrics, mappoint_t* pHitPoint, maphit_t** ppReturnStruct)
 {
-	gdouble fMaxDistance = map_pixels_to_degrees(pMap, 1, pMap->uZoomLevel) * 3;	// XXX: don't hardcode distance :)
+	gdouble fMaxDistance = map_math_pixels_to_degrees_at_scale(1, map_get_scale(pMap)) * 3;	// XXX: don't hardcode distance :)
 
 	const GPtrArray* pLocationSetsArray = locationset_get_array();
 	gint i;
@@ -336,8 +410,8 @@
 
 static gboolean map_hittest_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine)
 {
-	if(pHitPoint->fLatitude < (pPoint1->fLatitude - fMaxDistance) && pHitPoint->fLatitude < (pPoint2->fLatitude - fMaxDistance)) return FALSE;
-	if(pHitPoint->fLongitude < (pPoint1->fLongitude - fMaxDistance) && pHitPoint->fLongitude < (pPoint2->fLongitude - fMaxDistance)) return FALSE;
+//	if(pHitPoint->fLatitude < (pPoint1->fLatitude - fMaxDistance) && pHitPoint->fLatitude < (pPoint2->fLatitude - fMaxDistance)) return FALSE;
+//	if(pHitPoint->fLongitude < (pPoint1->fLongitude - fMaxDistance) && pHitPoint->fLongitude < (pPoint2->fLongitude - fMaxDistance)) return FALSE;
 
 	// Some bad ASCII art demonstrating the situation:
 	//

Index: map_hittest.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map_hittest.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- map_hittest.h	6 Oct 2005 00:00:53 -0000	1.1
+++ map_hittest.h	18 Oct 2005 03:05:25 -0000	1.2
@@ -29,7 +29,8 @@
 typedef enum {
 	MAP_HITTYPE_LOCATION,
 	MAP_HITTYPE_ROAD,
-	
+	MAP_HITTYPE_POLYGON,
+
 	// the following all use LocationSelectionHit in the union below
 	MAP_HITTYPE_LOCATIONSELECTION,	// hit somewhere on a locationselection graphic (info balloon)
 	MAP_HITTYPE_LOCATIONSELECTION_CLOSE,	// hit locationselection graphic close graphic (info balloon [X])
@@ -48,9 +49,13 @@
 		} LocationHit;
 
 		struct {
-			gint nRoadID;
+			gint nRoadID;	// XXX: change to nMapObjectID
 			mappoint_t ClosestPoint;
-		} RoadHit;
+		} RoadHit;			// XXX: Change to LineHit
+
+		struct {
+			gint nMapObjectID;
+		} PolygonHit;
 
 		struct {
 			gint nLocationID;

Index: map_math.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_math.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- map_math.c	11 Oct 2005 23:28:45 -0000	1.3
+++ map_math.c	18 Oct 2005 03:05:25 -0000	1.4
@@ -30,15 +30,29 @@
 // ========================================================
 
 // convert pixels to a span of degrees
-gdouble map_pixels_to_degrees(const map_t* pMap, gint16 nPixels, guint16 uZoomLevel)
+// gdouble map_pixels_to_degrees(const map_t* pMap, gint16 nPixels, guint16 uZoomLevel)
+// {
+//     gdouble fMonitorPixelsPerInch = 85.333; // XXX: don't hardcode this
+//     gdouble fPixelsPerMeter = fMonitorPixelsPerInch * INCHES_PER_METER;
+//     gdouble fMetersOfPixels = ((float)nPixels) / fPixelsPerMeter;
+//
+//     // If we had 3 meters of pixels (a very big monitor:) and the scale was 1000:1 then
+//     // we would want to show 3000 meters worth of world space
+//     gdouble fMetersOfWorld = ((float)g_sZoomLevels[uZoomLevel-1].uScale) * fMetersOfPixels;
+//
+//     //g_print("nPixels (%d) = fMetersOfPixels (%f) = fMetersOfWorld (%f) = fDegrees (%f)\n", nPixels, fMetersOfPixels, fMetersOfWorld, WORLD_METERS_TO_DEGREES(fMetersOfWorld));
+//     return WORLD_METERS_TO_DEGREES(fMetersOfWorld);
+// }
+
+gdouble map_math_pixels_to_degrees_at_scale(gint nPixels, gint nScale)
 {
 	gdouble fMonitorPixelsPerInch = 85.333;	// XXX: don't hardcode this
 	gdouble fPixelsPerMeter = fMonitorPixelsPerInch * INCHES_PER_METER;
-	gdouble fMetersOfPixels = ((float)nPixels) / fPixelsPerMeter;
+	gdouble fMetersOfPixels = ((gdouble)nPixels) / fPixelsPerMeter;
 
-	// If we had 3 meters of pixels (a very big monitor:) and the scale was 1000:1 then
+	// If we had 3 meters of pixels (a very big monitor:) and the scale was 1:1000 then
 	// we would want to show 3000 meters worth of world space
-	gdouble fMetersOfWorld = ((float)g_sZoomLevels[uZoomLevel-1].uScale) * fMetersOfPixels;
+	gdouble fMetersOfWorld = ((gdouble)nScale) * fMetersOfPixels;
 
 	//g_print("nPixels (%d) = fMetersOfPixels (%f) = fMetersOfWorld (%f) = fDegrees (%f)\n", nPixels, fMetersOfPixels, fMetersOfWorld, WORLD_METERS_TO_DEGREES(fMetersOfWorld));
 	return WORLD_METERS_TO_DEGREES(fMetersOfWorld);
@@ -61,9 +75,9 @@
 	gint16 nPixelDeltaY = (gint)(pScreenPoint->nY) - (pMap->MapDimensions.uHeight / 2);
 
 	// Convert pixels to world coordinates
-	pMapPoint->fLongitude = pMap->MapCenter.fLongitude + map_pixels_to_degrees(pMap, nPixelDeltaX, pMap->uZoomLevel);
+	pMapPoint->fLongitude = pMap->MapCenter.fLongitude + map_math_pixels_to_degrees_at_scale(nPixelDeltaX, map_get_scale(pMap));
 	// reverse the X, clicking above
-	pMapPoint->fLatitude = pMap->MapCenter.fLatitude - map_pixels_to_degrees(pMap, nPixelDeltaY, pMap->uZoomLevel);
+	pMapPoint->fLatitude = pMap->MapCenter.fLatitude - map_math_pixels_to_degrees_at_scale(nPixelDeltaY, map_get_scale(pMap));
 }
 
 EOverlapType map_rect_a_overlap_type_with_rect_b(const maprect_t* pA, const maprect_t* pB)
@@ -71,25 +85,30 @@
 	// First, quickly determine if there is no overlap
 	if(map_rects_overlap(pA,pB) == FALSE) return OVERLAP_NONE;
 
-	if(pA->A.fLatitude < pB->A.fLatitude) return OVERLAP_PARTIAL;
-	if(pA->B.fLatitude > pB->B.fLatitude) return OVERLAP_PARTIAL;
-
 	if(pA->A.fLongitude < pB->A.fLongitude) return OVERLAP_PARTIAL;
 	if(pA->B.fLongitude > pB->B.fLongitude) return OVERLAP_PARTIAL;
 
+	if(pA->A.fLatitude < pB->A.fLatitude) return OVERLAP_PARTIAL;
+	if(pA->B.fLatitude > pB->B.fLatitude) return OVERLAP_PARTIAL;
+
 	return OVERLAP_FULL;
 }
 
 gboolean map_rects_overlap(const maprect_t* p1, const maprect_t* p2)
 {
-	if(p1->B.fLatitude < p2->A.fLatitude) return FALSE;
+	if(p1->A.fLongitude > p2->B.fLongitude) return FALSE;
 	if(p1->B.fLongitude < p2->A.fLongitude) return FALSE;
 	if(p1->A.fLatitude > p2->B.fLatitude) return FALSE;
-	if(p1->A.fLongitude > p2->B.fLongitude) return FALSE;
+	if(p1->B.fLatitude < p2->A.fLatitude) return FALSE;
 
 	return TRUE;
 }
 
+// gboolean map_math_mappoint_in_maprect(mappoint_t* pPt, maprect_t* pRect)
+// {
+//     return(pPt->fLatitude >= pRect->A.fLatitude && pPt->fLatitude <= pRect->B.fLatitude && pPt->fLongitude >= pRect->A.fLongitude && pPt->fLongitude <= pRect->B.fLongitude);
+// }
+
 gboolean map_math_screenpoint_in_screenrect(screenpoint_t* pPt, screenrect_t* pRect)
 {
 	return(pPt->nX >= pRect->A.nX && pPt->nX <= pRect->B.nX && pPt->nY >= pRect->A.nY && pPt->nY <= pRect->B.nY);
@@ -100,6 +119,7 @@
 	gint nDelta = pRect->B.nX - pRect->A.nX;	// NOTE: this works no matter which point has bigger values
 	return abs(nDelta);
 }
+
 gint map_screenrect_height(const screenrect_t* pRect)
 {
 	gint nDelta = pRect->B.nY - pRect->A.nY;	// NOTE: this works no matter which point has bigger values
@@ -146,24 +166,6 @@
 	return sqrt((fDeltaX*fDeltaX) + (fDeltaY*fDeltaY));
 }
 
-gdouble map_get_distance_in_pixels(map_t* pMap, mappoint_t* p1, mappoint_t* p2)
-{
-	rendermetrics_t metrics;
-	map_get_render_metrics(pMap, &metrics);
-
-	gdouble fX1 = SCALE_X(&metrics, p1->fLongitude);
-	gdouble fY1 = SCALE_Y(&metrics, p1->fLatitude);
-
-	gdouble fX2 = SCALE_X(&metrics, p2->fLongitude);
-	gdouble fY2 = SCALE_Y(&metrics, p2->fLatitude);
-
-	gdouble fDeltaX = fX2 - fX1;
-	gdouble fDeltaY = fY2 - fY1;
-
-	return sqrt((fDeltaX*fDeltaX) + (fDeltaY*fDeltaY));
-}
-
-
 gboolean map_points_equal(mappoint_t* p1, mappoint_t* p2)
 {
 	return( p1->fLatitude == p2->fLatitude && p1->fLongitude == p2->fLongitude);
@@ -177,7 +179,7 @@
 //
 // clipping a map polygon (array of mappoints) to a maprect
 //
-typedef enum { EDGE_NORTH, EDGE_SOUTH, EDGE_EAST, EDGE_WEST, EDGE_FIRST=0, EDGE_LAST=3 } ERectEdge;
+typedef enum { EDGE_NORTH, EDGE_EAST, EDGE_SOUTH, EDGE_WEST, EDGE_FIRST=0, EDGE_LAST=3 } ERectEdge;
 
 // static map_math_clip_line_to_worldrect_edge_recursive(mappoint_t* pA, mappoint_t* pB, maprect_t* pRect, ERectEdge eEdge, GArray* pOutput)
 // {
@@ -193,32 +195,176 @@
 	return TRUE;
 }
 
-void map_math_clip_pointstring_to_worldrect(GArray* pMapPointsArray, maprect_t* pRect, GArray* pOutput)
+gboolean map_math_line_segments_overlap(const mappoint_t* pA1, const mappoint_t* pA2, const mappoint_t* pB1, const mappoint_t* pB2)
 {
-	gint nLen = pMapPointsArray->len;
-	if(nLen <= 2) return;
+	// XXX: unwritten
+	return FALSE;
+}
 
-	mappoint_t* pA = &g_array_index(pMapPointsArray, mappoint_t, 0);
-	mappoint_t* pB = NULL;
+gboolean map_math_mappoint_in_polygon(const mappoint_t* pPoint, const GArray* pMapPointsArray)
+{
+	gint i;
+	mappoint_t ptDistant = {1000.0, 1000.0};		// Outside of the world rect, so should do..?
 
-	gboolean bPointAIsInside = map_math_mappoint_in_maprect(pA, pRect);
+	gint nNumLineIntersections = 0;
 
-	gint i;
-	for(i=1 ; i<pMapPointsArray->len ; i++) {
-		gint iEdge;
-		for(iEdge=EDGE_FIRST ; iEdge<=EDGE_LAST ; iEdge++) {
-			switch(iEdge) {
-			case EDGE_NORTH:
-				break;
-			case EDGE_SOUTH:
-				break;
-			case EDGE_EAST:
-				break;
-			case EDGE_WEST:
-				break;
+	// Loop through all line segments in pMapPointsArray
+	for(i=0 ; i<(pMapPointsArray->len-1) ; i++) {
+		mappoint_t* pA = &g_array_index(pMapPointsArray, mappoint_t, i);
+		mappoint_t* pB = &g_array_index(pMapPointsArray, mappoint_t, i+1);
+
+		// If segment [pPoint,ptDistant] overlaps [pA,pB], add one to the intersection count
+		if(map_math_line_segments_overlap(pPoint, &ptDistant, pA, pB)) {
+			nNumLineIntersections++;
+		}
+	}
+
+	return ((nNumLineIntersections & 1) == 1);	// An odd count means point is in polygon
+}
+
+void map_math_get_intersection_of_line_segment_and_horizontal_line(const mappoint_t* pA, const mappoint_t* pB, gdouble fLineY, mappoint_t* pReturnPoint)
+{
+	// NOTE: this function ASSUMES a collision
+
+	gdouble fDeltaX = (pB->fLongitude - pA->fLongitude);
+	gdouble fDeltaY = (pB->fLatitude - pA->fLatitude);
+
+	// Very simple algorithm here: if the line is 30% of the way from A.y to B.y, it's also 30% of X!
+	//
+	//        /
+	// ------/--------
+	//      /
+	gdouble fCrossX = pA->fLongitude + (((fLineY - pA->fLatitude) / fDeltaY) * fDeltaX);
+
+	pReturnPoint->fLongitude = fCrossX;
+	pReturnPoint->fLatitude = fLineY;
+}
+
+void map_math_get_intersection_of_line_segment_and_vertical_line(const mappoint_t* pA, const mappoint_t* pB, gdouble fLineX, mappoint_t* pReturnPoint)
+{
+	gdouble fDeltaX = (pB->fLongitude - pA->fLongitude);
+	gdouble fDeltaY = (pB->fLatitude - pA->fLatitude);
+	gdouble fCrossY = pA->fLatitude + (((fLineX - pA->fLongitude) / fDeltaX) * fDeltaY);
+
+	pReturnPoint->fLongitude = fLineX;
+	pReturnPoint->fLatitude = fCrossY;
+}
+
+gboolean map_math_mappoints_equal(const mappoint_t* pA, const mappoint_t* pB)
+{
+	return (pA->fLatitude == pB->fLatitude && pA->fLongitude == pB->fLongitude);
+}
+
+typedef struct {
+	gint nPointsSeen;
+	mappoint_t ptFirst;
+	mappoint_t ptPrevious;
+	gboolean bPreviousWasInside;
+} clip_stage_data_t;
+
+typedef struct {
+	clip_stage_data_t aStageData[4];
+	GArray* pOutputArray;
+	maprect_t* pClipRect;
+} clip_data_t;
+
+static void map_math_clip_linesegment_to_worldrect_edge_recursive(clip_data_t* pClipData, const mappoint_t* pCurrent, gint nEdge)
+{
+	// A function pointer and argument for finding a crossing point (where a line segment crosses an axis-aligned line)
+	void (*segment_vs_axis_line_intersection_function)(const mappoint_t* pA, const mappoint_t* pB, gdouble fLinePosition, mappoint_t* pReturnPoint);
+	gdouble fLinePosition;
+
+	//g_debug("edge %d got point %f,%f", nEdge, pCurrent->fLongitude, pCurrent->fLatitude);
+
+	clip_stage_data_t* pStage = &pClipData->aStageData[nEdge];	// can obviously only access this if nEdge is valid
+
+	gboolean bCurrentIsInside;
+	switch(nEdge) {
+	case EDGE_NORTH:
+		bCurrentIsInside = (pCurrent->fLatitude < pClipData->pClipRect->B.fLatitude);
+		segment_vs_axis_line_intersection_function = map_math_get_intersection_of_line_segment_and_horizontal_line;
+		fLinePosition = pClipData->pClipRect->B.fLatitude;
+	break;
+	case EDGE_EAST:
+		bCurrentIsInside = (pCurrent->fLongitude < pClipData->pClipRect->B.fLongitude);
+		segment_vs_axis_line_intersection_function = map_math_get_intersection_of_line_segment_and_vertical_line;
+		fLinePosition = pClipData->pClipRect->B.fLongitude;
+	break;
+	case EDGE_SOUTH:
+		bCurrentIsInside = (pCurrent->fLatitude >= pClipData->pClipRect->A.fLatitude);
+		segment_vs_axis_line_intersection_function = map_math_get_intersection_of_line_segment_and_horizontal_line;
+		fLinePosition = pClipData->pClipRect->A.fLatitude;
+	break;
+	case EDGE_WEST:
+		bCurrentIsInside = (pCurrent->fLongitude >= pClipData->pClipRect->A.fLongitude);
+		segment_vs_axis_line_intersection_function = map_math_get_intersection_of_line_segment_and_vertical_line;
+		fLinePosition = pClipData->pClipRect->A.fLongitude;
+	break;
+	default:
+		// We get here when we've completed all four clipping planes.
+		g_array_append_val(pClipData->pOutputArray, *pCurrent);
+		return;
+	}
+
+	mappoint_t ptCrossing;
+	if(pStage->nPointsSeen == 0) {
+		// Just save the point.  We can't do anything with one point!
+		pStage->ptFirst = *pCurrent;
+	}
+	else {
+		if(bCurrentIsInside) {
+			if(pStage->bPreviousWasInside == FALSE) {
+				//g_debug("point entering");
+				segment_vs_axis_line_intersection_function(pCurrent, &(pStage->ptPrevious), fLinePosition, &ptCrossing);
+				map_math_clip_linesegment_to_worldrect_edge_recursive(pClipData, &ptCrossing, nEdge + 1);
 			}
+			map_math_clip_linesegment_to_worldrect_edge_recursive(pClipData, pCurrent, nEdge + 1);
+		}
+		else if(pStage->bPreviousWasInside) {
+			//g_debug("point leaving");
+			segment_vs_axis_line_intersection_function(pCurrent, &(pStage->ptPrevious), fLinePosition, &ptCrossing);
+			map_math_clip_linesegment_to_worldrect_edge_recursive(pClipData, &ptCrossing, nEdge + 1);
 		}
 	}
+	pStage->ptPrevious = *pCurrent;
+	pStage->bPreviousWasInside = bCurrentIsInside;
+	pStage->nPointsSeen++;
+}
+
+static void map_math_clip_linesegment_to_worldrect_edge_finalize_recursive(clip_data_t* pClipData, gint nEdge)
+{
+	if(nEdge > EDGE_LAST) return;	// end recursion
+
+	// Connect last point to first point for this stage
+	clip_stage_data_t* pStage = &(pClipData->aStageData[nEdge]);	// can obviously only access this if nEdge is valid
+	map_math_clip_linesegment_to_worldrect_edge_recursive(pClipData, &(pStage->ptFirst), nEdge);
+
+	// Continue cleanup, recursive
+	map_math_clip_linesegment_to_worldrect_edge_finalize_recursive(pClipData, nEdge + 1);
+}
+
+void map_math_clip_pointstring_to_worldrect(GArray* pMapPointsArray, maprect_t* pRect, GArray* pOutput)
+{
+	g_assert(EDGE_FIRST == 0);
+	g_assert(EDGE_LAST == 3);	// we make these assumptions with our array indexing and nEdge incrementing
+
+	if(pMapPointsArray->len <= 2) return;
+
+	// Initialize clip data (most of it defaults to 0s)
+	clip_data_t* pClipData = g_new0(clip_data_t, 1);
+	pClipData->pOutputArray = pOutput;
+	pClipData->pClipRect = pRect;
+
+	// Pass each point through the clippers (recursively)
+	gint i;
+	for(i=0 ; i<pMapPointsArray->len ; i++) {
+		mappoint_t* pCurrent = &g_array_index(pMapPointsArray, mappoint_t, i);
+		map_math_clip_linesegment_to_worldrect_edge_recursive(pClipData, pCurrent, EDGE_FIRST);
+	}
+
+	// Finalize clippers (recursively)
+	map_math_clip_linesegment_to_worldrect_edge_finalize_recursive(pClipData, EDGE_FIRST);
+	g_free(pClipData);
 }
 
 void static map_math_simplify_pointstring_recursive(const GArray* pInput, gint8* pabInclude, gdouble fTolerance, gint iFirst, gint iLast)
@@ -244,7 +390,7 @@
 			iFarthestIndex = i;
 		}
 	}
-	if(fBiggestDistanceSquared > (fTolerance * fTolerance) && (iFarthestIndex != -1)) {	// add last test just in case fTolerance == 0.0
+	if((fBiggestDistanceSquared > (fTolerance * fTolerance)) && (iFarthestIndex != -1)) {	// add last test just in case fTolerance == 0.0
 		// Mark for inclusion
 		pabInclude[iFarthestIndex] = 1;
 
@@ -255,7 +401,11 @@
 
 void map_math_simplify_pointstring(const GArray* pInput, gdouble fTolerance, GArray* pOutput)
 {
-	if(pInput->len < 2) return;
+	if(pInput->len <= 2) {
+		// Can't simplify this.
+		g_array_append_vals(pOutput, &g_array_index(pInput, mappoint_t, 0), pInput->len);
+		return;
+	}
 
 	gint8* pabInclude = g_new0(gint8, pInput->len + 20);
 
@@ -279,7 +429,6 @@
 	g_free(pabInclude);
 }
 
-// Does the given point come close enough to the line segment to be considered a hit?
 gdouble map_math_point_distance_squared_from_line(mappoint_t* pHitPoint, mappoint_t* pPoint1, mappoint_t* pPoint2)
 {
 	// Some bad ASCII art demonstrating the situation:
@@ -301,7 +450,10 @@
 	v.fLongitude = pPoint2->fLongitude - pPoint1->fLongitude;
 
 	gdouble fLengthV = sqrt((v.fLatitude*v.fLatitude) + (v.fLongitude*v.fLongitude));
-	if(fLengthV == 0.0) return FALSE;	// bad data: a line segment with no length?
+	if(fLengthV == 0.0) {
+		g_warning("fLengthV == 0.0 in map_math_point_distance_squared_from_line");
+		return 0.0;	// bad data: a line segment with no length?
+	}
 
 	//
 	// 2. Make a unit vector out of v (meaning same direction but length=1) by dividing v by v's length
@@ -325,7 +477,6 @@
 	mappoint_t a;
 	a.fLatitude = v.fLatitude * (fLengthAlongV / fLengthV);	// multiply each component by the percentage
 	a.fLongitude = v.fLongitude * (fLengthAlongV / fLengthV);
-	// NOTE: (a) is *not* where it actually hit on the *map*.  don't draw this point!  we'd have to translate it back away from the origin.
 
 	//
 	// 5. Calculate the distance from the end of (u) to (a).  If it's less than the fMaxDistance, it's a hit.
@@ -337,6 +488,57 @@
 	return fDistanceSquared;
 }
 
+// Attempt to add B onto A
+gboolean map_math_try_connect_linestrings(GArray* pA, const GArray* pB)
+{
+	if(pB->len < 2) return TRUE;	// nothing to do
+
+	if(pA->len == 0) {
+		// copy all
+        g_array_append_vals(pA, &g_array_index(pB, mappoint_t, 0), pB->len);
+		return TRUE;
+	}
+
+	// Does A end at B?
+	if(map_math_mappoints_equal(&g_array_index(pA, mappoint_t, pA->len-1), &g_array_index(pB, mappoint_t, 0))) {
+        g_array_append_vals(pA, &g_array_index(pB, mappoint_t, 0), pB->len);
+		return TRUE;
+	}
+	// Does B end at A?
+	if(map_math_mappoints_equal(&g_array_index(pB, mappoint_t, pB->len-1), &g_array_index(pB, mappoint_t, 0))) {
+        g_array_prepend_vals(pA, &g_array_index(pB, mappoint_t, 0), pB->len);
+		return TRUE;
+	}
+	// Do they start in the same place?
+	if(map_math_mappoints_equal(&g_array_index(pA, mappoint_t, 0), &g_array_index(pB, mappoint_t, 0))) {
+		// flip B and prepend to A
+		gint i;
+		for(i=pB->len-1 ; i>=1 ; i--) {	// NOTE the >=1 to skip the first point of B
+			g_array_prepend_val(pA, g_array_index(pB, mappoint_t, i));
+		}
+		return TRUE;
+	}
+	// Do they end in the same place?
+	if(map_math_mappoints_equal(&g_array_index(pA, mappoint_t, pA->len-1), &g_array_index(pB, mappoint_t, pB->len-1))) {
+		// flip B and append to A
+		gint i;
+		for(i=pB->len-2 ; i>=0 ; i--) {	// NOTE the -2 to skip the last point of B
+			g_array_append_val(pA, g_array_index(pB, mappoint_t, i));
+		}
+		return TRUE;
+	}
+	return FALSE;
+}
+
+// Update pA to include pB
+void map_util_bounding_box_union(maprect_t* pA, const maprect_t* pB)
+{
+	pA->A.fLatitude = MIN(pA->A.fLatitude, pB->A.fLatitude);
+	pA->A.fLongitude = MIN(pA->A.fLongitude, pB->A.fLongitude);
+	
+	pA->B.fLatitude = MAX(pA->B.fLatitude, pB->B.fLatitude);
+	pA->B.fLongitude = MAX(pA->B.fLongitude, pB->B.fLongitude);
+}
 
 #ifdef ROADSTER_DEAD_CODE
 /*
@@ -356,5 +558,49 @@
 			return 0;
 	}
 }
+
+gdouble map_get_distance_in_pixels(map_t* pMap, mappoint_t* p1, mappoint_t* p2)
+{
+	rendermetrics_t metrics;
+	map_get_render_metrics(pMap, &metrics);
+
+	// XXX: this can overflow, me thinks
+	gdouble fX1 = SCALE_X(&metrics, p1->fLongitude);
+	gdouble fY1 = SCALE_Y(&metrics, p1->fLatitude);
+
+	gdouble fX2 = SCALE_X(&metrics, p2->fLongitude);
+	gdouble fY2 = SCALE_Y(&metrics, p2->fLatitude);
+
+	gdouble fDeltaX = fX2 - fX1;
+	gdouble fDeltaY = fY2 - fY1;
+
+	return sqrt((fDeltaX*fDeltaX) + (fDeltaY*fDeltaY));
+}
+
+void map_util_calculate_bounding_box(const GArray* pMapPointsArray, maprect_t* pBoundingRect)
+{
+	// untested
+	g_assert_not_reacher();
+
+	g_assert(pMapPointsArray != NULL);
+	g_assert(pMapPointsArray->len > 0);
+	g_assert(pBoundingRect != NULL);
+
+	pBoundingRect->A.fLatitude = MAX_LATITUDE;
+	pBoundingRect->A.fLongitude = MAX_LONGITUDE;
+	pBoundingRect->B.fLatitude = MIN_LATITUDE;
+	pBoundingRect->B.fLongitude = MIN_LONGITUDE;
+
+	gint i = 0;
+	for(i=0 ; i<pMapPointsArray->len ; i++) {
+		mappoint_t* p = &g_array_index(pMapPointsArray, mappoint_t, i);
+
+		pBoundingRect->A.fLatitude = min(pBoundingRect->A.fLatitude, p->fLatitude);
+		pBoundingRect->B.fLatitude = max(pBoundingRect->B.fLatitude, p->fLatitude);
+		pBoundingRect->A.fLongitude = min(pBoundingRect->A.fLongitude, p->fLongitude);
+		pBoundingRect->B.fLongitude = max(pBoundingRect->B.fLongitude, p->fLongitude);
+	}
+}
+
 */
 #endif

Index: map_math.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map_math.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- map_math.h	11 Oct 2005 23:28:45 -0000	1.2
+++ map_math.h	18 Oct 2005 03:05:25 -0000	1.3
@@ -32,6 +32,8 @@
 
 gboolean map_math_screenpoint_in_screenrect(screenpoint_t* pPt, screenrect_t* pRect);
 gboolean map_math_maprects_equal(maprect_t* pA, maprect_t* pB);
+gboolean map_math_mappoint_in_polygon(const mappoint_t* pPoint, const GArray* pMapPointsArray);
+gboolean map_math_mappoint_in_maprect(const mappoint_t* pPoint, const maprect_t* pRect);
 
 EOverlapType map_rect_a_overlap_type_with_rect_b(const maprect_t* pA, const maprect_t* pB);
 gboolean map_rects_overlap(const maprect_t* p1, const maprect_t* p2);
@@ -39,4 +41,10 @@
 void map_math_simplify_pointstring(const GArray* pInput, gdouble fTolerance, GArray* pOutput);
 gdouble map_math_point_distance_squared_from_line(mappoint_t* pHitPoint, mappoint_t* pPoint1, mappoint_t* pPoint2);
 
+gdouble map_math_pixels_to_degrees_at_scale(gint nPixels, gint nScale);
+void map_math_clip_pointstring_to_worldrect(GArray* pMapPointsArray, maprect_t* pRect, GArray* pOutput);
+gboolean map_math_try_connect_linestrings(GArray* pA, const GArray* pB);
+void map_util_calculate_bounding_box(const GArray* pMapPointsArray, maprect_t* pBoundingRect);
+void map_util_bounding_box_union(maprect_t* pA, const maprect_t* pB);
+
 #endif

Index: map_tilemanager.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_tilemanager.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- map_tilemanager.c	10 Oct 2005 07:07:36 -0000	1.2
+++ map_tilemanager.c	18 Oct 2005 03:05:25 -0000	1.3
@@ -24,9 +24,13 @@
 #include <gtk/gtk.h>
 #include "util.h"
 #include "map_tilemanager.h"
+#include "map_math.h"
 #include "db.h"
 #include "road.h"
 
+#define ENABLE_ADD_FINAL_POLYGON_POINT
+#define ENABLE_RUN_TIME_ROAD_STITCHING
+
 // Prototypes
 static void _map_tilemanager_tile_load_map_objects(maptile_t* pTile, maprect_t* pRect, gint nLOD);
 static maptile_t* map_tilemanager_tile_cache_lookup(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD);
@@ -47,6 +51,7 @@
 maptilemanager_t* map_tilemanager_new()
 {
 	maptilemanager_t* pNew = g_new0(maptilemanager_t, 1);
+	g_assert(pNew);
 	
 	gint i;
 	for(i=0 ; i<MAP_NUM_LEVELS_OF_DETAIL ; i++) {
@@ -55,6 +60,7 @@
 	return pNew;
 }
 
+// Returns a newly allocated GPtrArray which must be freed by calling map_tilemanager_free_tile_list()
 GPtrArray* map_tilemanager_load_tiles_for_worldrect(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD)
 {
 	//
@@ -148,11 +154,20 @@
 	return pTileArray;
 }
 
+void map_tilemanager_free_tile_list(maptilemanager_t* pTileManager, GPtrArray* pTiles)
+{
+	g_ptr_array_free(pTiles, TRUE);
+}
+
+//
+// Private
+//
 static maptile_t* map_tilemanager_tile_new(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD)
 {
 	//g_print("New tile for (%f,%f),(%f,%f)\n", pRect->A.fLongitude, pRect->A.fLatitude, pRect->B.fLongitude, pRect->B.fLatitude);
 
 	maptile_t* pNewTile = g_new0(maptile_t, 1);
+	g_assert(pNewTile);
 	memcpy(&(pNewTile->rcWorldBoundingBox), pRect, sizeof(maprect_t));
 
 	gint i;
@@ -190,6 +205,15 @@
 	return NULL;
 }
 
+gboolean map_object_type_is_polygon(gint nType)
+{
+	// XXX: do this more robustly
+	return (nType == MAP_OBJECT_TYPE_PARK || 
+			nType == MAP_OBJECT_TYPE_LAKE ||
+			nType == MAP_OBJECT_TYPE_MISC_AREA || 
+			nType == MAP_OBJECT_TYPE_URBAN_AREA);
+}
+
 static void _map_tilemanager_tile_load_map_objects(maptile_t* pTile, maprect_t* pRect, gint nLOD)
 {
 	db_resultset_t* pResultSet = NULL;
@@ -203,11 +227,12 @@
 	gchar azCoord1[20], azCoord2[20], azCoord3[20], azCoord4[20], azCoord5[20], azCoord6[20], azCoord7[20], azCoord8[20];
 	gchar* pszSQL;
 	pszSQL = g_strdup_printf(
-		"SELECT 0 AS ID, %s.TypeID, AsBinary(%s.Coordinates), RoadName.Name, RoadName.SuffixID %s"
+		"SELECT 0 AS ID, %s.TypeID, AsBinary(%s.Coordinates), RoadName.Name, RoadName.SuffixID %s, RoadNameID"
 		" FROM %s "
 		" LEFT JOIN RoadName ON (%s.RoadNameID=RoadName.ID)"
 		" WHERE"
-		" MBRIntersects(GeomFromText('Polygon((%s %s,%s %s,%s %s,%s %s,%s %s))'), Coordinates)",
+		" MBRIntersects(GeomFromText('Polygon((%s %s,%s %s,%s %s,%s %s,%s %s))'), Coordinates)"
+		" ORDER BY TypeID, RoadNameID, X(StartPoint(Coordinates))",		// XXX: add sorting by MBR x or y?
 
 		//pszRoadTableName,	 no ID column 
 		pszRoadTableName, pszRoadTableName,
@@ -235,6 +260,10 @@
 
 	TIMER_SHOW(mytimer, "after query");
 
+	road_t* pPreviousRoad = NULL;
+	gint nPreviousRoadNameID = 0;
+	gint nPreviousRoadTypeID = 0;
+
 	guint32 uRowCount = 0;
 	if(pResultSet) {
 		while((aRow = db_fetch_row(pResultSet))) {
@@ -249,6 +278,7 @@
 			// aRow[6] is road address left end
 			// aRow[7] is road address right start 
 			// aRow[8] is road address right end
+			// aRow[9] is road name id
 
 			// Get layer type that this belongs on
 			gint nTypeID = atoi(aRow[1]);
@@ -257,9 +287,35 @@
 				continue;
 			}
 
-			//road_t* pNewRoad = NULL;
-			//road_alloc(&pNewRoad);
+			// XXX: perhaps let the wkb parser create the array (at the perfect size)
+			GArray* pPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
+			maprect_t rcBoundingBox;
+			db_parse_wkb_linestring(aRow[2], pPointsArray, &rcBoundingBox);
+
+			gint nRoadNameID = atoi(aRow[1]);
+
+#ifdef ENABLE_RUN_TIME_ROAD_STITCHING
+			// Check if we can stitch this road segment onto previous road
+			if(pPreviousRoad != NULL) {
+				if(nRoadNameID == nPreviousRoadNameID && nTypeID == nPreviousRoadTypeID) {
+					if(map_math_try_connect_linestrings(pPreviousRoad->pMapPointsArray, pPointsArray)) {
+						// Success!
+
+						// update bounding box for object
+						map_util_bounding_box_union(&(pPreviousRoad->rWorldBoundingBox), &(rcBoundingBox));
+
+						g_array_free(pPointsArray, TRUE);
+						continue;
+					}
+				}
+			}
+#endif
+			// Otherwise add a new road segment
 			road_t* pNewRoad = g_new0(road_t, 1);
+			g_assert(pNewRoad);
+
+			pNewRoad->pMapPointsArray = pPointsArray;
+			pNewRoad->rWorldBoundingBox = rcBoundingBox;
 
 			// Build name by adding suffix, if one is present
 			if(aRow[3] != NULL && aRow[4] != NULL) {
@@ -277,9 +333,13 @@
 				pNewRoad->nAddressRightEnd = atoi(aRow[8]);
 			}
 
-			// perhaps let the wkb parser create the array (at the perfect size)
-			pNewRoad->pMapPointsArray = g_array_new(FALSE, FALSE, sizeof(road_t));
-			db_parse_wkb_linestring(aRow[2], pNewRoad->pMapPointsArray, &(pNewRoad->rWorldBoundingBox));
+			// add first point to the end to complete the polygon
+#ifdef ENABLE_ADD_FINAL_POLYGON_POINT
+			if(map_object_type_is_polygon(nTypeID)) {
+				mappoint_t p = g_array_index(pNewRoad->pMapPointsArray, mappoint_t, 0);
+				g_array_append_val(pNewRoad->pMapPointsArray, p);
+			}
+#endif
 
 #ifdef ENABLE_RIVER_TO_LAKE_LOADTIME_HACK	// XXX: combine this and above hack and you get lakes with squiggly edges. whoops. :)
 			if(nTypeID == MAP_OBJECT_TYPE_RIVER) {
@@ -292,6 +352,10 @@
 			}
 #endif
 
+			pPreviousRoad = pNewRoad;
+			nPreviousRoadNameID = nRoadNameID;
+			nPreviousRoadTypeID = nTypeID;
+
 			// Add this item to layer's list of pointstrings
 			g_ptr_array_add(pTile->apMapObjectArrays[nTypeID], pNewRoad);
 		} // end while loop on rows

Index: map_tilemanager.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map_tilemanager.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- map_tilemanager.h	5 Oct 2005 06:09:36 -0000	1.1
+++ map_tilemanager.h	18 Oct 2005 03:05:25 -0000	1.2
@@ -41,5 +41,6 @@
 
 // returns GArray containing maptile_t types 
 GPtrArray* map_tilemanager_load_tiles_for_worldrect(maptilemanager_t* pTileManager, maprect_t* pWorldRect, gint nLOD);
+void map_tilemanager_free_tile_list(maptilemanager_t* pTileManager, GPtrArray* pTiles);
 
 #endif

Index: mapinfowindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/mapinfowindow.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- mapinfowindow.c	12 Oct 2005 03:58:44 -0000	1.1
+++ mapinfowindow.c	18 Oct 2005 03:05:25 -0000	1.2
@@ -108,7 +108,7 @@
 	gint nNewStateID = 0;
 	gint nNewCityID = 0;
 
-	gint nZoomScale = map_get_zoomlevel_scale(pMap);
+	gint nZoomScale = map_get_scale(pMap);
 
 	// Step 2. Set button text and drop-down menus
 

Index: search_city.h
===================================================================
RCS file: /cvs/cairo/roadster/src/search_city.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- search_city.h	24 Sep 2005 05:25:25 -0000	1.1
+++ search_city.h	18 Oct 2005 03:05:25 -0000	1.2
@@ -26,6 +26,7 @@
 
 G_BEGIN_DECLS
 
+void search_city_init();
 void search_city_execute(const gchar* pszSentence);
 
 G_END_DECLS

Index: search_location.h
===================================================================
RCS file: /cvs/cairo/roadster/src/search_location.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- search_location.h	31 Mar 2005 08:29:53 -0000	1.3
+++ search_location.h	18 Oct 2005 03:05:25 -0000	1.4
@@ -26,6 +26,7 @@
 
 G_BEGIN_DECLS
 
+void search_location_init();
 void search_location_execute(const gchar* pszSentence);
 
 G_END_DECLS

Index: search_road.h
===================================================================
RCS file: /cvs/cairo/roadster/src/search_road.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- search_road.h	3 Mar 2005 07:32:46 -0000	1.2
+++ search_road.h	18 Oct 2005 03:05:25 -0000	1.3
@@ -26,6 +26,7 @@
 
 G_BEGIN_DECLS
 
+void search_road_init();
 void search_road_execute(const gchar* pszSentence);
 
 G_END_DECLS

Index: test_poly.c
===================================================================
RCS file: /cvs/cairo/roadster/src/test_poly.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- test_poly.c	12 Oct 2005 03:04:05 -0000	1.2
+++ test_poly.c	18 Oct 2005 03:05:25 -0000	1.3
@@ -20,6 +20,7 @@
 	GtkDrawingArea* pDrawingArea;
 	GtkLabel* pLabel;
 	GtkCheckButton* pHideDrawingCheckButton;
+	GtkCheckButton* pClipCheckButton;
 	
 	GArray* pPointsArray;
 } g_Test_Poly;
@@ -37,6 +38,7 @@
 	GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pLabel, GTK_LABEL, "test_polylabel");
 	GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pDrawingArea, GTK_DRAWING_AREA, "test_polydrawingarea");
 	GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pHideDrawingCheckButton, GTK_CHECK_BUTTON, "test_polyhidecheck");
+	GLADE_LINK_WIDGET(pGladeXML, g_Test_Poly.pClipCheckButton, GTK_CHECK_BUTTON, "test_poly_clip");
 
 	g_Test_Poly.pPointsArray = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
 
@@ -73,7 +75,7 @@
 	return TRUE;
 }
 
-gboolean test_poly_on_hidecheck_toggled(GtkWidget* w, GdkEventButton *event)
+gboolean test_poly_on_time_to_queue_draw(GtkWidget* w, GdkEventButton *event)
 {
 	gtk_widget_queue_draw(GTK_WIDGET(g_Test_Poly.pDrawingArea));
 }
@@ -133,26 +135,58 @@
 	cairo_rectangle(pCairo, 0.0, 0.0, 1.0, 1.0);
 	cairo_fill(pCairo);
 
-	// Draw lines
-	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_Test_Poly.pHideDrawingCheckButton)) == FALSE) {
-		cairo_set_line_join(pCairo, CAIRO_LINE_JOIN_ROUND);
+	GArray* pSimplified = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
+
+	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_Test_Poly.pClipCheckButton)) == TRUE) {
+		maprect_t rcClipper;
+		rcClipper.A.fLatitude = rcClipper.A.fLongitude = 0.25;
+		rcClipper.B.fLatitude = rcClipper.B.fLongitude = 0.75;
+
+
+		if(g_Test_Poly.pPointsArray->len > 0) {
+			GArray* pClipped = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
+			mappoint_t ptFirst = g_array_index(g_Test_Poly.pPointsArray, mappoint_t, 0);
+			g_array_append_val(g_Test_Poly.pPointsArray, ptFirst);
+				map_math_clip_pointstring_to_worldrect(g_Test_Poly.pPointsArray, &rcClipper, pClipped);
+			g_array_remove_index(g_Test_Poly.pPointsArray, g_Test_Poly.pPointsArray->len-1);
+
+			// Simplify
+			map_math_simplify_pointstring(pClipped, fValue, pSimplified);
+
+			g_array_free(pClipped, TRUE);
+		}
+
+		// Draw clip rectangle
 		cairo_save(pCairo);
-		cairo_set_line_width(pCairo, 0.02);
-		cairo_set_source_rgba(pCairo, 1.0, 0.0, 0.0, 1.0);
-		test_poly_draw_array(pCairo, g_Test_Poly.pPointsArray);
+		cairo_set_source_rgba(pCairo, 0.0, 0.0, 0.0, 1.0);
+		cairo_set_line_width(pCairo, 0.005);
+		cairo_rectangle(pCairo, rcClipper.A.fLongitude, rcClipper.A.fLatitude, (rcClipper.B.fLongitude - rcClipper.A.fLongitude), (rcClipper.B.fLatitude - rcClipper.A.fLatitude));
 		cairo_stroke(pCairo);
 		cairo_restore(pCairo);
 	}
+	else {
+		// Simplify
+		map_math_simplify_pointstring(g_Test_Poly.pPointsArray, fValue, pSimplified);
+	}
 
+	// Draw pSimplified filled
 	cairo_save(pCairo);
-	GArray* pSimplified = g_array_new(FALSE, FALSE, sizeof(mappoint_t));
-	map_math_simplify_pointstring(g_Test_Poly.pPointsArray, fValue, pSimplified);
-	cairo_set_line_width(pCairo, 0.01);
-	cairo_set_source_rgba(pCairo, 0.0, 1.0, 0.0, 0.5);
+	cairo_set_source_rgba(pCairo, 0.0, 1.0, 0.0, 1.0);
 	test_poly_draw_array(pCairo, pSimplified);
 	cairo_fill(pCairo);
 	cairo_restore(pCairo);
 
+	// Draw lines
+	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_Test_Poly.pHideDrawingCheckButton)) == FALSE) {
+		cairo_save(pCairo);
+		cairo_set_line_join(pCairo, CAIRO_LINE_JOIN_ROUND);
+		cairo_set_line_width(pCairo, 0.02);
+		cairo_set_source_rgba(pCairo, 1.0, 0.0, 0.0, 1.0);
+		test_poly_draw_array(pCairo, g_Test_Poly.pPointsArray);
+		cairo_stroke(pCairo);
+		cairo_restore(pCairo);
+	}
+
 	cairo_destroy(pCairo);
 
 	if(g_Test_Poly.pPointsArray->len == 0) {

Index: util.c
===================================================================
RCS file: /cvs/cairo/roadster/src/util.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- util.c	12 Oct 2005 03:04:05 -0000	1.17
+++ util.c	18 Oct 2005 03:05:25 -0000	1.18
@@ -546,3 +546,66 @@
 	g_assert(pMemory != NULL);
 	g_free(pMemory);
 }
+
+EDirection util_match_border(gint nX, gint nY, gint nWidth, gint nHeight, gint nBorderSize)
+{
+	EDirection eDirection;
+
+	// Corner hit targets are L shaped and 1/3 of the two borders it touches
+	gint nXCorner = nWidth/3;
+	gint nYCorner = nHeight/3;
+
+	// LEFT EDGE?
+	if(nX <= nBorderSize) {
+		if(nY <= nYCorner) {
+			eDirection = DIRECTION_NW;
+		}
+		else if((nY+nYCorner) >= nHeight) {
+			eDirection = DIRECTION_SW;
+		}
+		else {
+			eDirection = DIRECTION_W;
+		}
+	}
+	// RIGHT EDGE?
+	else if((nX+nBorderSize) >= nWidth) {
+		if(nY <= nYCorner) {
+			eDirection = DIRECTION_NE;
+		}
+		else if((nY+nYCorner) >= nHeight) {
+			eDirection = DIRECTION_SE;
+		}
+		else {
+			eDirection = DIRECTION_E;
+		}
+	}
+	// TOP?
+	else if(nY <= nBorderSize) {
+		if(nX <= nXCorner) {
+			eDirection = DIRECTION_NW;
+		}
+		else if((nX+nXCorner) >= nWidth) {
+			eDirection = DIRECTION_NE;
+		}
+		else {
+			eDirection = DIRECTION_N;
+		}
+	}
+	// BOTTOM?
+	else if((nY+nBorderSize) >= nHeight) {
+		if(nX <= nXCorner) {
+			eDirection = DIRECTION_SW;
+		}
+		else if((nX+nXCorner) >= nWidth) {
+			eDirection = DIRECTION_SE;
+		}
+		else {
+			eDirection = DIRECTION_S;
+		}
+	}
+	// center.
+	else {
+		eDirection = DIRECTION_NONE;
+	}
+	return eDirection;
+}

Index: util.h
===================================================================
RCS file: /cvs/cairo/roadster/src/util.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- util.h	12 Oct 2005 03:04:05 -0000	1.17
+++ util.h	18 Oct 2005 03:05:25 -0000	1.18
@@ -49,6 +49,10 @@
 #define is_even(x)		(((x) & 1) == 0)
 #define is_odd(x)		(((x) & 1) == 1)
 
+typedef enum {
+	DIRECTION_NONE, DIRECTION_N, DIRECTION_NE, DIRECTION_E, DIRECTION_SE, DIRECTION_S, DIRECTION_SW, DIRECTION_W, DIRECTION_NW
+} EDirection;
+
 void util_close_parent_window(GtkWidget* pWidget, gpointer data);
 void util_open_uri(const char* pszURI);
 
@@ -89,4 +93,6 @@
 
 void util_g_free_with_param(gpointer pMemory, gpointer _unused);
 
+EDirection util_match_border(gint nX, gint nY, gint nWidth, gint nHeight, gint nBorderSize);
+
 #endif



More information about the cairo-commit mailing list