[cairo-commit] roadster/src Makefile.am, 1.23, 1.24 db.c, 1.32, 1.33 db.h, 1.14, 1.15 import_tiger.c, 1.21, 1.22 main.c, 1.32, 1.33 main.h, 1.5, 1.6 mainwindow.c, 1.48, 1.49 map.c, 1.51, 1.52 map.h, 1.25, 1.26 map_draw_cairo.c, 1.27, 1.28 map_draw_cairo.h, 1.1, 1.2 map_draw_gdk.c, 1.25, 1.26 map_draw_gdk.h, 1.1, 1.2 map_style.c, 1.4, 1.5 map_tile.c, 1.2, NONE map_tile.h, 1.1, NONE map_tilemanager.c, NONE, 1.1 map_tilemanager.h, NONE, 1.1 road.c, 1.8, 1.9 scenemanager.c, 1.15, 1.16 scenemanager.h, 1.7, 1.8 search_road.c, 1.28, 1.29

Ian McIntosh commit at pdx.freedesktop.org
Tue Oct 4 23:09:38 PDT 2005


Committed by: ian

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

Modified Files:
	Makefile.am db.c db.h import_tiger.c main.c main.h 
	mainwindow.c map.c map.h map_draw_cairo.c map_draw_cairo.h 
	map_draw_gdk.c map_draw_gdk.h map_style.c road.c 
	scenemanager.c scenemanager.h search_road.c 
Added Files:
	map_tilemanager.c map_tilemanager.h 
Removed Files:
	map_tile.c map_tile.h 
Log Message:
	* src/import_tiger.c:
	* src/search_road.c:
	* src/db.c: Add level of detail concept.
	* src/mainwindow.c: Add zoomtool.
	* src/map_draw_gdk.c: 
	* src/map_draw_cairo.c: Calculate bounding box on load instead of draw.  Update to tile drawing.
	* src/map.c: Begin splitting this file up more.  Add lots more zoom levels.
	* src/scenemanager.c: Remove empty module init.
	* src/main.c: Don't need to init scenemanager module.


Index: Makefile.am
===================================================================
RCS file: /cvs/cairo/roadster/src/Makefile.am,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- Makefile.am	1 Oct 2005 05:24:16 -0000	1.23
+++ Makefile.am	5 Oct 2005 06:09:36 -0000	1.24
@@ -25,11 +25,13 @@
 	mainwindow.c\
 	gotowindow.c\
 	map.c\
-	map_tile.c\
-	map_history.c\
-	map_style.c\
 	map_draw_cairo.c\
 	map_draw_gdk.c\
+	map_history.c\
+	map_hittest.c\
+	map_math.c\
+	map_style.c\
+	map_tilemanager.c\
 	import.c\
 	import_tiger.c\
 	importwindow.c\

Index: db.c
===================================================================
RCS file: /cvs/cairo/roadster/src/db.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- db.c	1 Oct 2005 01:42:12 -0000	1.32
+++ db.c	5 Oct 2005 06:09:36 -0000	1.33
@@ -256,11 +256,6 @@
 	return uRows;
 }
 
-gboolean db_is_empty()
-{
-	return (db_count_table_rows(DB_ROADS_TABLENAME) == 0);
-}
-
 /******************************************************
 ** data inserting
 ******************************************************/
@@ -285,9 +280,9 @@
 	return FALSE;
 }
 
-gboolean db_insert_road(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, GPtrArray* pPointsArray, gint* pReturnID)
 {
-	g_assert(pReturnID != NULL);
+//	g_assert(pReturnID != NULL);
 	if(!db_is_connected()) return FALSE;
 	if(pPointsArray->len == 0) return TRUE; 	// skip 0-length
 
@@ -307,23 +302,32 @@
 		nCount++;
 	}
 
-	gchar azQuery[MAX_SQLBUFFER_LEN];
-	g_snprintf(azQuery, MAX_SQLBUFFER_LEN,
-		"INSERT INTO %s SET RoadNameID=%d, TypeID=%d, Coordinates=GeometryFromText('LINESTRING(%s)')"
-		", AddressLeftStart=%d, AddressLeftEnd=%d, AddressRightStart=%d, AddressRightEnd=%d"
-		", CityLeftID=%d, CityRightID=%d"
-		", ZIPCodeLeft='%s', ZIPCodeRight='%s'",
-		DB_ROADS_TABLENAME, nRoadNameID, nLayerType, azCoordinateList,
-	    nAddressLeftStart, nAddressLeftEnd, nAddressRightStart, nAddressRightEnd,
-		nCityLeftID, nCityRightID,
-		pszZIPCodeLeft, pszZIPCodeRight);
-
-	if(MYSQL_RESULT_SUCCESS != mysql_query(g_pDB->pMySQLConnection, azQuery)) {
-		g_warning("db_insert_road failed: %s (SQL: %s)\n", mysql_error(g_pDB->pMySQLConnection), azQuery);
-		return FALSE;
+	gchar* pszQuery;
+	
+	if(nLOD == 0) {
+		pszQuery = g_strdup_printf(
+			"INSERT INTO %s%d SET RoadNameID=%d, TypeID=%d, Coordinates=GeometryFromText('LINESTRING(%s)')"
+			", AddressLeftStart=%d, AddressLeftEnd=%d, AddressRightStart=%d, AddressRightEnd=%d"
+			", CityLeftID=%d, CityRightID=%d"
+			", ZIPCodeLeft='%s', ZIPCodeRight='%s'",
+			DB_ROADS_TABLENAME, nLOD, nRoadNameID, nLayerType, azCoordinateList,
+			nAddressLeftStart, nAddressLeftEnd, nAddressRightStart, nAddressRightEnd,
+			nCityLeftID, nCityRightID,
+			pszZIPCodeLeft, pszZIPCodeRight);
 	}
+	else {
+		pszQuery = g_strdup_printf(
+			"INSERT INTO %s%d SET RoadNameID=%d, TypeID=%d, Coordinates=GeometryFromText('LINESTRING(%s)')",
+			DB_ROADS_TABLENAME, nLOD, nRoadNameID, nLayerType, azCoordinateList);
+	}
+
+	mysql_query(g_pDB->pMySQLConnection, pszQuery);
+	g_free(pszQuery);
+
 	// return the new ID
-	*pReturnID = mysql_insert_id(g_pDB->pMySQLConnection);
+	if(pReturnID != NULL) {
+		*pReturnID = mysql_insert_id(g_pDB->pMySQLConnection);
+	}
 	return TRUE;
 }
 
@@ -571,32 +575,43 @@
 //	db_query("ALTER TABLE RoadName ADD INDEX (NameSoundex);", NULL);
 
 	// Road
-	db_query("CREATE TABLE IF NOT EXISTS Road("
-		" ID INT4 UNSIGNED NOT NULL AUTO_INCREMENT,"	// XXX: can we get away with INT3 ?
+	db_query(
+		"CREATE TABLE IF NOT EXISTS Road0("
+//		" ID INT4 UNSIGNED NOT NULL AUTO_INCREMENT,"	// XXX: can we get away with INT3 ?
 		" TypeID INT1 UNSIGNED NOT NULL,"
-
 		" RoadNameID INT3 UNSIGNED NOT NULL,"		// NOTE: 3 bytes
-
 		" AddressLeftStart INT2 UNSIGNED NOT NULL,"
 		" AddressLeftEnd INT2 UNSIGNED NOT NULL,"
 		" AddressRightStart INT2 UNSIGNED NOT NULL,"
 		" AddressRightEnd INT2 UNSIGNED NOT NULL,"
-
 		" CityLeftID INT3 UNSIGNED NOT NULL,"		// NOTE: 3 bytes
 		" CityRightID INT3 UNSIGNED NOT NULL,"		// NOTE: 3 bytes
-
 		" ZIPCodeLeft CHAR(6) NOT NULL,"
 		" ZIPCodeRight CHAR(6) NOT NULL,"
-
 		" Coordinates point NOT NULL,"
 
 	    // lots of indexes:
-		" PRIMARY KEY (ID),"	// XXX: we'll probably want to keep a unique ID, but we don't use this for anything yet.
+//		" PRIMARY KEY (ID),"	// XXX: we'll probably want to keep a unique ID, but we don't use this for anything yet.
 		" INDEX(RoadNameID),"	// to get roads when we've matched a RoadName
 		" SPATIAL KEY (Coordinates));", NULL);
 
+	db_query(
+		"CREATE TABLE IF NOT EXISTS Road1("
+		" TypeID INT1 UNSIGNED NOT NULL,"
+		" RoadNameID INT3 UNSIGNED NOT NULL,"		// NOTE: 3 bytes
+		" Coordinates point NOT NULL,"
+		" SPATIAL KEY (Coordinates));", NULL);
+
+	db_query(
+		"CREATE TABLE IF NOT EXISTS Road2("
+		" TypeID INT1 UNSIGNED NOT NULL,"
+		" RoadNameID INT3 UNSIGNED NOT NULL,"		// NOTE: 3 bytes
+		" Coordinates point NOT NULL,"
+		" SPATIAL KEY (Coordinates));", NULL);
+
 	// RoadName
-	db_query("CREATE TABLE IF NOT EXISTS RoadName("
+	db_query(
+		"CREATE TABLE IF NOT EXISTS RoadName("
 		" ID INT3 UNSIGNED NOT NULL auto_increment,"	// NOTE: 3 bytes
 		" Name VARCHAR(30) NOT NULL,"
 		" NameSoundex CHAR(10) NOT NULL,"	// see soundex() function
@@ -607,8 +622,8 @@
 		,NULL);
 
 	// City
-	db_query("CREATE TABLE IF NOT EXISTS City("
-		// a unique ID for the value
+	db_query(
+		"CREATE TABLE IF NOT EXISTS City("
 		" ID INT3 UNSIGNED NOT NULL AUTO_INCREMENT,"	// NOTE: 3 bytes
 		" StateID INT2 UNSIGNED NOT NULL,"		// NOTE: 2 bytes
 		" Name CHAR(60) NOT NULL,"			// are city names ever 60 chars anyway??  TIGER think so
@@ -618,8 +633,8 @@
 	    ,NULL);
 
 	// State
-	db_query("CREATE TABLE IF NOT EXISTS State("
-		// a unique ID for the value
+	db_query(
+		"CREATE TABLE IF NOT EXISTS State("
 		" ID INT2 UNSIGNED NOT NULL AUTO_INCREMENT,"	// NOTE: 2 bytes (enough to go global..?)
 		" Name CHAR(40) NOT NULL,"
 		" Code CHAR(3) NOT NULL,"			// eg. "MA"
@@ -629,7 +644,8 @@
 	    ,NULL);
 
 	// Location
-	db_query("CREATE TABLE IF NOT EXISTS Location("
+	db_query(
+		"CREATE TABLE IF NOT EXISTS Location("
 		" ID INT4 UNSIGNED NOT NULL AUTO_INCREMENT,"
 		" LocationSetID INT3 NOT NULL,"				// NOTE: 3 bytes
 		" Coordinates point NOT NULL,"

Index: db.h
===================================================================
RCS file: /cvs/cairo/roadster/src/db.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- db.h	1 Oct 2005 01:42:12 -0000	1.14
+++ db.h	5 Oct 2005 06:09:36 -0000	1.15
@@ -52,8 +52,6 @@
 const gchar* db_get_connection_info(void);
 
 // utility
-gboolean db_is_empty(void);
-
 gboolean db_insert_roadname(const gchar* pszName, gint nSuffixID, gint* pnReturnID);
 
 //~ gboolean db_create_points_db(const gchar* name);
@@ -86,12 +84,7 @@
 void db_disable_keys(void);
 
 gboolean db_insert_city(const gchar* pszName, gint nStateID, gint* pnReturnCityID);
-gboolean db_insert_road(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, GPtrArray* 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: import_tiger.c
===================================================================
RCS file: /cvs/cairo/roadster/src/import_tiger.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- import_tiger.c	25 Sep 2005 19:02:37 -0000	1.21
+++ import_tiger.c	5 Oct 2005 06:09:36 -0000	1.22
@@ -155,6 +155,96 @@
 	gint nCityID;					// a database ID, stored here after it is inserted
 } tiger_record_rtc_t;
 
+// #define MAP_OBJECT_TYPE_NONE                    (0)
+// #define MAP_OBJECT_TYPE_MINORROAD               (1)
+// #define MAP_OBJECT_TYPE_MAJORROAD               (2)
+// #define MAP_OBJECT_TYPE_MINORHIGHWAY            (3)
+// #define MAP_OBJECT_TYPE_MINORHIGHWAY_RAMP       (4)
+// #define MAP_OBJECT_TYPE_MAJORHIGHWAY            (5) // Unused
+// #define MAP_OBJECT_TYPE_MAJORHIGHWAY_RAMP       (6) // Unused
+// #define MAP_OBJECT_TYPE_RAILROAD                (7)
+// #define MAP_OBJECT_TYPE_PARK                    (8)
+// #define MAP_OBJECT_TYPE_RIVER                   (9)
+// #define MAP_OBJECT_TYPE_LAKE                    (10)
+// #define MAP_OBJECT_TYPE_MISC_AREA               (11)
+// #define MAP_OBJECT_TYPE_URBAN_AREA              (12)
+
+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,16,0,0},	// river
+	{1,1,1,1},	// lake
+	{1,1,1,1},	// misc area
+	{1,1,1,1},	// urban area
+};
+
+gboolean object_type_exists_at_lod(gint nRecordType, gint nLOD)
+{
+	if(nRecordType < 0) {
+		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);
+}
+
+gint object_type_detail_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));
+}
+
+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)
 {
@@ -254,6 +344,8 @@
 	return TRUE;
 }
 
+// NOTE: This function can return MAP_OBJECT_TYPE_NONE.  Lines of this type shouldn't be saved, but they
+// might be used for polygons, so we have to keep them in memory.
 static gboolean import_tiger_read_layer_type(gint8* pBuffer, gint* pValue)
 {
 	//g_print("%c%c%c\n", *(pBuffer), *(pBuffer+1), *(pBuffer+2));
@@ -282,7 +374,6 @@
 		}
 		else if(chCode == '5') {	// dirt roads
 			//*pValue = MAP_OBJECT_TYPE_TRAIL;
-			return FALSE;
 		}
 		else if(chCode == '6') {
 			if(chSubCode == '1') {
@@ -294,7 +385,6 @@
 			}
 			else if(chSubCode == '5') {
 				//*pValue = MAP_OBJECT_TYPE_FERRY_ROUTE;	// where a boat carrying cars goes
-				return FALSE;
 			}
 			else if(chSubCode == '7') {
 				g_print("found code A67: toll booth!\n");
@@ -587,8 +677,8 @@
 
 		// 22-24 is a CFCC (
 		gint nRecordType;
-
 		import_tiger_read_layer_type(&pLine[22-1], &nRecordType);
+
 		pRecord = g_new0(tiger_record_rt7_t, 1);
 		pRecord->nRecordType = nRecordType;
 
@@ -832,16 +922,26 @@
 			db_insert_roadname(pRecordRT1->achName, pRecordRT1->nRoadNameSuffixID, &nRoadNameID);
 		}
 
-		gint nRoadID;
-		db_insert_road(nRoadNameID,
-			pRecordRT1->nRecordType,
-			pRecordRT1->nAddressLeftStart,
-			pRecordRT1->nAddressLeftEnd,
-			pRecordRT1->nAddressRightStart,
-			pRecordRT1->nAddressRightEnd,
-			nCityLeftID, nCityRightID,
-			azZIPCodeLeft, azZIPCodeRight,
-			pTempPointsArray, &nRoadID);
+		gint 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);
+
+				db_insert_road(nLOD, nRoadNameID, pRecordRT1->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL, 
+							   pReducedPointsArray, NULL);
+			}
+			g_ptr_array_free(pReducedPointsArray, TRUE);
+		}
 	}
 	g_ptr_array_free(pTempPointsArray, TRUE);
 }
@@ -1012,12 +1112,6 @@
 			g_print("Found a polygon that doesn't loop %s\n", pRecordRT7->achName);
 		}
 
-		// XXX: looking up a city for a polygon?  unimplemented.
-		gint nCityLeftID = 0;
-		gchar* pszZIPCodeLeft = "";
-		gint nCityRightID = 0;
-		gchar* pszZIPCodeRight = "";
-
 		// insert record
 		if(pRecordRT7->nRecordType != MAP_OBJECT_TYPE_NONE) {
 			gint nRoadNameID = 0;
@@ -1026,14 +1120,34 @@
 				db_insert_roadname(pRecordRT7->achName, 0, &nRoadNameID);
 			}
 
-			gint nRoadID;
-			db_insert_road(
-				nRoadNameID,
-				pRecordRT7->nRecordType,
-				0,0,0,0,
-				nCityLeftID, nCityRightID,
-				pszZIPCodeLeft, pszZIPCodeRight,
-				pTempPointsArray, &nRoadID);
+			// 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;
+
+			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();
+
+				reduce_object_detail_for_lod(pRecordRT7->nRecordType, nLOD, pTempPointsArray, pReducedPointsArray);
+				if(pReducedPointsArray->len > 0) {
+					g_assert(pReducedPointsArray->len >= 2);
+
+					db_insert_road(nLOD, nRoadNameID, pRecordRT7->nRecordType, 0, 0, 0, 0, 0, 0, NULL, NULL, 
+								   pReducedPointsArray, NULL);
+				}
+				g_ptr_array_free(pReducedPointsArray, TRUE);
+			}
 
 		}
 	}

Index: main.c
===================================================================
RCS file: /cvs/cairo/roadster/src/main.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- main.c	1 Oct 2005 05:24:16 -0000	1.32
+++ main.c	5 Oct 2005 06:09:36 -0000	1.33
@@ -31,7 +31,6 @@
 #include "db.h"
 #include "map.h"
 #include "gpsclient.h"
-#include "scenemanager.h"
 #include "locationset.h"
 #include "location.h"
 #include "search.h"
@@ -142,9 +141,6 @@
 	g_print("initializing map\n");
 	map_init();
 
-	g_print("initializing scenemanager\n");
-	scenemanager_init();
-
 	g_print("initializing gpsclient\n");
 	gpsclient_init();
 

Index: main.h
===================================================================
RCS file: /cvs/cairo/roadster/src/main.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- main.h	25 Sep 2005 19:02:37 -0000	1.5
+++ main.h	5 Oct 2005 06:09:36 -0000	1.6
@@ -24,6 +24,8 @@
 #ifndef _MAIN_H_
 #define _MAIN_H_
 
+//#define G_DISABLE_ASSERT
+
 #include <gtk/gtk.h>
 
 #define USE_GNOME_VFS		// comment this out to get a faster single-threaded compile (can't import, though)

Index: mainwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/mainwindow.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- mainwindow.c	1 Oct 2005 19:09:05 -0000	1.48
+++ mainwindow.c	5 Oct 2005 06:09:36 -0000	1.49
@@ -27,7 +27,7 @@
 
 #include <gtk/gtk.h>
 #include <gtk/gtksignal.h>
-//#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
 //#include <gdk/gdkx.h>
 //#include <cairo.h>
 //#include <cairo-xlib.h>
@@ -39,6 +39,7 @@
 #include "gotowindow.h"
 #include "db.h"
 #include "map.h"
+#include "map_hittest.h"
 #include "map_style.h"
 #include "importwindow.h"
 #include "locationset.h"
@@ -89,6 +90,8 @@
 #define LOCATIONSETLIST_COLUMN_COUNT	(3)
 #define LOCATIONSETLIST_COLUMN_PIXBUF	(4)
 
+#define ZOOM_TOOL_THRESHOLD (5) // in pixels.  a box less than AxA will be ignored
+
 // Limits
 #define MAX_SEARCH_TEXT_LENGTH			(100)
 #define SPEED_LABEL_FORMAT				("<span font_desc='32'>%.0f</span>")
@@ -107,20 +110,20 @@
 #define MAX_DISTANCE_FOR_AUTO_SLIDE_IN_PIXELS	(3500.0)	// when selecting search results, we slide to them instead of jumping if they are within this distance
 
 // Types
-typedef struct {
-	GdkCursorType CursorType;
-	GdkCursor* pGdkCursor;
-} cursor_t;
+// typedef struct {
+//     GdkCursorType CursorType;
+//     GdkCursor* pGdkCursor;
+// } cursor_t;
 
-typedef struct {
-	char* szName;
-	cursor_t Cursor;
-} toolsettings_t;
+// typedef struct {
+//     char* szName;
+//     cursor_t Cursor;
+// } toolsettings_t;
 
-typedef enum {
-	kToolPointer = 0,
-	kToolZoom = 1,
-} EToolType;
+// typedef enum {
+//     MOUSE_TOOL_POINTER = 0,
+//     MOUSE_TOOL_ZOOM = 1,
+// } EMouseToolType;
 
 // Prototypes
 static void mainwindow_setup_selected_tool(void);
@@ -169,8 +172,8 @@
 
 	// Toolbar
 	GtkHBox* pToolbar;
-//	GtkToolButton* pPointerToolButton;
-//	GtkToolButton* pZoomToolButton;
+	GtkRadioButton* pPointerToolRadioButton;
+	GtkRadioButton* pZoomToolRadioButton;
 	GtkHScale* pZoomScale;
 	GtkEntry* pSearchBox;
 	GtkImage* pStatusbarGPSIcon;
@@ -214,7 +217,7 @@
 	tooltip_t* pTooltip;
 	map_t* pMap;
 
-	EToolType eSelectedTool;
+//     EToolType eSelectedTool;
 
 	gboolean bScrolling;
 	EDirection eScrollDirection;
@@ -236,6 +239,10 @@
 	mappoint_t ptSlideEndLocation;
 	animator_t* pAnimator;
 
+	// Zoom Tool
+	gboolean bDrawingZoomRect;
+	screenrect_t rcZoomRect;
+
 	// History (forward / back)
 	maphistory_t* pMapHistory;
 	GtkButton* pForwardButton;
@@ -252,17 +259,17 @@
 // XXX: Use GDK_HAND1 for the map
 
 // Data
-toolsettings_t g_Tools[] = {
-	{"Pointer Tool", {GDK_LEFT_PTR, NULL}},
-	{"Zoom Tool", {GDK_CIRCLE, NULL}},
-};
-void cursor_init()
-{
-	int i;
-	for(i=0 ; i<G_N_ELEMENTS(g_Tools) ; i++) {
-		g_Tools[i].Cursor.pGdkCursor = gdk_cursor_new(g_Tools[i].Cursor.CursorType);
-	}
-}
+// toolsettings_t g_Tools[] = {
+//     {"Pointer Tool", {GDK_LEFT_PTR, NULL}},
+//     {"Zoom Tool", {GDK_CIRCLE, NULL}},
+// };
+// void cursor_init()
+// {
+//     int i;
+//     for(i=0 ; i<G_N_ELEMENTS(g_Tools) ; i++) {
+//         g_Tools[i].Cursor.pGdkCursor = gdk_cursor_new(g_Tools[i].Cursor.CursorType);
+//     }
+// }
 
 static void util_set_image_to_stock(GtkImage* pImage, gchar* pszStockIconID, GtkIconSize nSize)
 {
@@ -294,6 +301,11 @@
 	return pCursor;
 }
 
+void mainwindow_draw_xor_rect(screenrect_t* pRect)
+{
+	map_draw_gdk_xor_rect(g_MainWindow.pMap, GTK_WIDGET(g_MainWindow.pDrawingArea)->window, pRect);
+}
+
 void mainwindow_set_not_busy(void** ppCursor)
 {
 	gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.pWindow)->window, NULL);
@@ -365,6 +377,10 @@
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pSidebarNotebook, GTK_NOTEBOOK, "sidebarnotebook");
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pContentBox, GTK_VBOX, "mainwindowcontentsbox");
 
+//     g_object_set(G_OBJECT(g_MainWindow.pSidebarNotebook), "show-border", FALSE, NULL);
+	g_object_set(G_OBJECT(g_MainWindow.pSidebarNotebook), "tab-border", 1, NULL);
+//     g_object_set(G_OBJECT(g_MainWindow.pSidebarNotebook), "tab-hborder", 0, NULL);
+
 	// View menu
    	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pViewSidebarMenuItem, GTK_CHECK_MENU_ITEM, "viewsidebarmenuitem");
    	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pViewFullscreenMenuItem, GTK_CHECK_MENU_ITEM, "viewfullscreenmenuitem");
@@ -384,8 +400,8 @@
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pMapPopupMenu, GTK_MENU, "mappopupmenu");
 
 	// Tools
-	//GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pPointerToolButton, GTK_TOOL_BUTTON, "pointertoolbutton");
-	//GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pZoomToolButton, GTK_TOOL_BUTTON, "zoomtoolbutton");
+	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pPointerToolRadioButton, GTK_RADIO_BUTTON, "pointertoolradiobutton");
+	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.pZoomToolRadioButton, GTK_RADIO_BUTTON, "zoomtoolradiobutton");
 
 	// GPS Widgets
 	GLADE_LINK_WIDGET(pGladeXML, g_MainWindow.GPS.pShowPositionCheckButton, GTK_CHECK_BUTTON, "gpsshowpositioncheckbutton");
@@ -446,8 +462,7 @@
 	map_new(&g_MainWindow.pMap, GTK_WIDGET(g_MainWindow.pDrawingArea));
 	map_style_load(g_MainWindow.pMap, MAP_STYLE_FILENAME);
 	
-
-	cursor_init();
+//     cursor_init();
 
 	mainwindow_configure_locationset_list();
 	mainwindow_refresh_locationset_list();
@@ -737,6 +752,13 @@
 	gtk_widget_set_sensitive(GTK_WIDGET(g_MainWindow.pZoomInMenuItem), map_can_zoom_in(g_MainWindow.pMap));
 	gtk_widget_set_sensitive(GTK_WIDGET(g_MainWindow.pZoomOutButton), map_can_zoom_out(g_MainWindow.pMap));
 	gtk_widget_set_sensitive(GTK_WIDGET(g_MainWindow.pZoomOutMenuItem), map_can_zoom_out(g_MainWindow.pMap));
+
+	// set zoomlevel scale but prevent it from calling handler (mainwindow_on_zoomscale_value_changed)
+    g_signal_handlers_block_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
+	gtk_range_set_value(GTK_RANGE(g_MainWindow.pZoomScale), map_get_zoomlevel(g_MainWindow.pMap));
+	g_signal_handlers_unblock_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
+
+	mainwindow_statusbar_update_zoomscale();
 }
 
 void mainwindow_set_zoomlevel(gint nZoomLevel)
@@ -744,11 +766,10 @@
 	map_set_zoomlevel(g_MainWindow.pMap, nZoomLevel);
 
 	// set zoomlevel scale but prevent it from calling handler (mainwindow_on_zoomscale_value_changed)
-    g_signal_handlers_block_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
-	gtk_range_set_value(GTK_RANGE(g_MainWindow.pZoomScale), nZoomLevel);
-	g_signal_handlers_unblock_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
+//     g_signal_handlers_block_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
+//     gtk_range_set_value(GTK_RANGE(g_MainWindow.pZoomScale), nZoomLevel);
+//     g_signal_handlers_unblock_by_func(g_MainWindow.pZoomScale, mainwindow_on_zoomscale_value_changed, NULL);
 
-	mainwindow_statusbar_update_zoomscale();
 	mainwindow_update_zoom_buttons();
 }
 
@@ -771,11 +792,11 @@
 //
 //
 //
-static void gui_set_tool(EToolType eTool)
-{
-	g_MainWindow.eSelectedTool = eTool;
-	gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.pDrawingArea)->window, g_Tools[eTool].Cursor.pGdkCursor);
-}
+// static void gui_set_tool(EToolType eTool)
+// {
+//     g_MainWindow.eSelectedTool = eTool;
+//     gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.pDrawingArea)->window, g_Tools[eTool].Cursor.pGdkCursor);
+// }
 
 //
 // Callbacks for About box
@@ -859,11 +880,18 @@
 	mainwindow_set_sidebox_visible(!mainwindow_get_sidebox_visible());
 }
 
+#define ZOOM_MAJOR_TICK_SIZE	(4)
+
 // Zoom buttons / menu items (shared callbacks)
 void mainwindow_on_zoomin_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
+	gint nNewZoomLevel = map_get_zoomlevel(g_MainWindow.pMap) - 1; 	// XXX: make zoomlevel 0-based and the -1 will go away
+	nNewZoomLevel -= (nNewZoomLevel % ZOOM_MAJOR_TICK_SIZE);
+	nNewZoomLevel += ZOOM_MAJOR_TICK_SIZE;
+	nNewZoomLevel += 1;	// XXX: make zoomlevel 0-based and the +1 will go away
+
 	// tell the map
-	map_set_zoomlevel(g_MainWindow.pMap, map_get_zoomlevel(g_MainWindow.pMap) + 1);
+	map_set_zoomlevel(g_MainWindow.pMap, nNewZoomLevel);
 	
 	// update the gui
 	mainwindow_set_zoomlevel(map_get_zoomlevel(g_MainWindow.pMap));
@@ -874,7 +902,12 @@
 
 void mainwindow_on_zoomout_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
-	map_set_zoomlevel(g_MainWindow.pMap, map_get_zoomlevel(g_MainWindow.pMap) - 1);
+	gint nNewZoomLevel = map_get_zoomlevel(g_MainWindow.pMap) - 1;
+	if((nNewZoomLevel % ZOOM_MAJOR_TICK_SIZE) == 0) nNewZoomLevel -= ZOOM_MAJOR_TICK_SIZE;
+	else nNewZoomLevel -= (nNewZoomLevel % ZOOM_MAJOR_TICK_SIZE);
+	nNewZoomLevel += 1;	// XXX: make zoomlevel 0-based and the +1 will go away
+
+	map_set_zoomlevel(g_MainWindow.pMap, nNewZoomLevel);
 	mainwindow_set_zoomlevel(map_get_zoomlevel(g_MainWindow.pMap));
 	mainwindow_draw_map(DRAWFLAG_GEOMETRY);
 	mainwindow_set_draw_pretty_timeout(DRAW_PRETTY_ZOOM_TIMEOUT_MS);
@@ -974,6 +1007,11 @@
 
 	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
@@ -982,7 +1020,7 @@
 	map_windowpoint_to_mappoint(g_MainWindow.pMap, &screenpoint, &mappoint);
 	
 	maphit_t* pHitStruct = NULL;
-	map_hit_test(g_MainWindow.pMap, &mappoint, &pHitStruct);
+	map_hittest(g_MainWindow.pMap, &mappoint, &pHitStruct);
 	// hitstruct free'd far below
 
 	if(event->button == MOUSE_BUTTON_LEFT) {
@@ -1004,6 +1042,14 @@
 
 				mainwindow_set_scroll_timeout();
 			}
+			else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_MainWindow.pZoomToolRadioButton))) {
+				//g_print("begin rect draw\n");
+				g_MainWindow.bDrawingZoomRect = TRUE;
+
+				// set both rect points to click point
+				g_MainWindow.rcZoomRect.A.nX = g_MainWindow.rcZoomRect.B.nX = nX;
+				g_MainWindow.rcZoomRect.A.nY = g_MainWindow.rcZoomRect.B.nY = nY;
+			}
 			else {
 				g_MainWindow.bMouseDragging = TRUE;
 				g_MainWindow.bMouseDragMovement = FALSE;
@@ -1048,6 +1094,27 @@
 				}
 			}
 
+			if(g_MainWindow.bDrawingZoomRect == TRUE) {
+				if((map_screenrect_width(&(g_MainWindow.rcZoomRect)) > ZOOM_TOOL_THRESHOLD) && (map_screenrect_height(&(g_MainWindow.rcZoomRect)) > ZOOM_TOOL_THRESHOLD)) {
+					map_zoom_to_screenrect(g_MainWindow.pMap, &(g_MainWindow.rcZoomRect));
+
+					// update GUI
+					mainwindow_update_zoom_buttons();
+					mainwindow_statusbar_update_position();
+
+					mainwindow_draw_map(DRAWFLAG_GEOMETRY);
+					mainwindow_set_draw_pretty_timeout(DRAW_PRETTY_ZOOM_TIMEOUT_MS);
+					mainwindow_add_history();
+				}
+				else {
+					// Since we're not redrawing the map, we need to erase the selection rectangle
+					mainwindow_draw_xor_rect(&(g_MainWindow.rcZoomRect));
+				}
+
+				// all done
+				g_MainWindow.bDrawingZoomRect = FALSE;
+			}
+
 			// end scrolling, if active
 			if(g_MainWindow.bScrolling == TRUE) {
 				// NOTE: don't restore cursor (mouse could *still* be over screen edge)
@@ -1086,7 +1153,7 @@
 			}
 		}
 		else if(event->type == GDK_2BUTTON_PRESS) {
-			// can only double click in the middle (not on a scroll border)
+			// can only double-click in the middle (not on a scroll border)
 			eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
 			if(eScrollDirection == DIRECTION_NONE) {
 				animator_destroy(g_MainWindow.pAnimator);
@@ -1108,7 +1175,6 @@
 		if(event->type == GDK_BUTTON_PRESS) {
 			GtkMenu* pMenu = g_MainWindow.pMapPopupMenu;	// default to generic map popup
 
-			g_print("here %s\n", pHitStruct);
 			if(pHitStruct != NULL) {
 				if(pHitStruct->eHitType == MAP_HITTYPE_LOCATION) {
 					// Use POI specific popup menu
@@ -1134,7 +1200,7 @@
 			//gtk_menu_popup(pMenu, NULL, NULL, NULL, NULL, event->button, event->time);
 		}
 	}
-	map_hitstruct_free(g_MainWindow.pMap, pHitStruct);
+	map_hittest_maphit_free(g_MainWindow.pMap, pHitStruct);
 	return TRUE;
 }
 
@@ -1154,7 +1220,17 @@
 	gint nWidth = GTK_WIDGET(g_MainWindow.pDrawingArea)->allocation.width;
 	gint nHeight = GTK_WIDGET(g_MainWindow.pDrawingArea)->allocation.height;
 
-	gint nCursor = GDK_LEFT_PTR;
+	// nX and nY clipped to screen
+	gint nClippedX = (nX < 0) ? 0 : ((nX > nWidth-1) ? nWidth-1 : nX);
+	gint nClippedY = (nY < 0) ? 0 : ((nY > nHeight-1) ? nHeight-1 : nY);
+
+	gint nCursor;
+	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g_MainWindow.pZoomToolRadioButton))) {
+		nCursor = GDK_SIZING;
+	}
+	else {
+		nCursor = GDK_LEFT_PTR;
+	}
 
 	if(g_MainWindow.bMouseDragging) {
 		g_MainWindow.bMouseDragMovement = TRUE;
@@ -1183,6 +1259,15 @@
 		// update direction if actively scrolling
 		g_MainWindow.eScrollDirection = eScrollDirection;
 	}
+	else if(g_MainWindow.bDrawingZoomRect) {
+		//g_print("updating rect\n");
+		mainwindow_draw_xor_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
+	}
 	else {
 		// If not dragging or scrolling, user is just moving mouse around.
 		// Update tooltip and mouse cursor based on what we're pointing at.
@@ -1199,7 +1284,7 @@
 	
 			// try to "hit" something on the map. a road, a location, whatever!
 			maphit_t* pHitStruct = NULL;
-			if(map_hit_test(g_MainWindow.pMap, &mappoint, &pHitStruct)) {
+			if(map_hittest(g_MainWindow.pMap, &mappoint, &pHitStruct)) {
 				// A hit!  Move the tooltip here, format the text, and show it.
 				tooltip_set_upper_left_corner(g_MainWindow.pTooltip, (gint)(event->x_root) + TOOLTIP_OFFSET_X, (gint)(event->y_root) + TOOLTIP_OFFSET_Y);
 
@@ -1240,7 +1325,7 @@
 					g_print("url: %s\n", pHitStruct->URLHit.pszURL);
 				}
 
-				map_hitstruct_free(g_MainWindow.pMap, pHitStruct);
+				map_hittest_maphit_free(g_MainWindow.pMap, pHitStruct);
 			}
 			else {
 				// no hit. hide the tooltip
@@ -1293,14 +1378,27 @@
 	}
 }
 
-static gboolean mainwindow_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
+static gboolean mainwindow_on_key_press(GtkWidget *widget, GdkEventKey *pEvent, gpointer user_data)
 {
-	g_print("key_press\n");
+	//g_print("key_press\n");
+	if(pEvent->keyval == GDK_F1) {
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g_MainWindow.pPointerToolRadioButton), TRUE);
+	}
+	else if(pEvent->keyval == GDK_F2) {
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g_MainWindow.pZoomToolRadioButton), TRUE);
+	}
+	else if(pEvent->keyval == GDK_Escape) {
+		if(g_MainWindow.bDrawingZoomRect == TRUE) {
+			// cancel zoom-rect
+			mainwindow_draw_xor_rect(&(g_MainWindow.rcZoomRect));
+			g_MainWindow.bDrawingZoomRect = FALSE;
+		}
+	}
 	return FALSE;
 }
 static gboolean mainwindow_on_key_release(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 {
-	g_print("key_release\n");
+	//g_print("key_release\n");
 	return FALSE;
 }
 

Index: map.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map.c,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- map.c	1 Oct 2005 05:24:16 -0000	1.51
+++ map.c	5 Oct 2005 06:09:36 -0000	1.52
@@ -22,12 +22,12 @@
  */
 
 #include <gdk/gdkx.h>
-//#include <cairo.h>
 #include <gtk/gtk.h>
 #include <math.h>
 
 #include "main.h"
 #include "map_style.h"
+#include "map_tilemanager.h"
 #include "gui.h"
[...1286 lines suppressed...]
+			mappoint_t* pNewPoint = NULL;
+			callback_alloc_point(&pNewPoint);
+			gdouble fDistanceFromPoint1 = (j+1) * fDistanceBetweenPoints;
+
+			pNewPoint->fLongitude = pPoint1->fLongitude + (fDistanceFromPoint1 * fNormalizedX);
+			pNewPoint->fLatitude = pPoint1->fLatitude + (fDistanceFromPoint1 * fNormalizedY);
+
+			gdouble fRandomMovementLength = fMaxRandomDistance * g_random_double_range(-1.0, 1.0);
+			pNewPoint->fLongitude += (fPerpendicularNormalizedX * fRandomMovementLength);	// move each component
+			pNewPoint->fLatitude += (fPerpendicularNormalizedY * fRandomMovementLength);
+
+			g_ptr_array_add(pDestArray, pNewPoint);
+		}
+	}
+	// add last point
+	g_ptr_array_add(pDestArray, g_ptr_array_index(pSourceArray, pSourceArray->len-1));
+//g_print("pDestArray->len = %d\n", pDestArray->len);
 }
+*/
+#endif

Index: map.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- map.h	1 Oct 2005 01:42:12 -0000	1.25
+++ map.h	5 Oct 2005 06:09:36 -0000	1.26
@@ -24,6 +24,7 @@
 #ifndef _MAP_H_
 #define _MAP_H_
 
+#include <math.h>
 #include "gfreelist.h"
 
 //
@@ -48,6 +49,9 @@
 #define MAP_OBJECT_TYPE_FIRST					(1)
 #define MAP_OBJECT_TYPE_LAST					(12)
 
+#define MAP_LEVEL_OF_DETAIL_BEST	(0)
+#define MAP_LEVEL_OF_DETAIL_WORST	(3)
+#define MAP_NUM_LEVELS_OF_DETAIL	(4)
 
 //
 // Line CAP styles
@@ -101,9 +105,9 @@
 struct GtkWidget;
 
 #define MIN_ZOOM_LEVEL					(1)
-#define MAX_ZOOM_LEVEL					(5)
-#define NUM_ZOOM_LEVELS					(5)
-#define MIN_ZOOM_LEVEL_FOR_LOCATIONS	(6)		// don't show POI above this level
+#define MAX_ZOOM_LEVEL					(41)
+#define NUM_ZOOM_LEVELS					(41)
+#define MIN_ZOOM_LEVEL_FOR_LOCATIONS	(25)		// don't show POI above this level
 
 #include "scenemanager.h"
 
@@ -153,7 +157,10 @@
 	EDistanceUnits eScaleMetricUnit;
 	gint nScaleMetricNumber;
 
-	gchar* szName;
+	//gchar* szName;
+	
+	gint nStyleZoomLevel;				// pretend we're zoomlevel X because there are more real zoomlevels than in the map layer style definitions
+	gint nLevelOfDetail;				// pretend we're zoomlevel X because there are more real zoomlevels than in the map layer style definitions
 } zoomlevel_t;
 
 extern zoomlevel_t g_sZoomLevels[];
@@ -173,19 +180,22 @@
 	maprect_t rWorldBoundingBox;
 	gint nWindowWidth;
 	gint nWindowHeight;
+	gint nLevelOfDetail;
 } rendermetrics_t;
 
 #define SCALE_X(p, x)  ((((x) - (p)->rWorldBoundingBox.A.fLongitude) / (p)->fScreenLongitude) * (p)->nWindowWidth)
 #define SCALE_Y(p, y)  ((p)->nWindowHeight - ((((y) - (p)->rWorldBoundingBox.A.fLatitude) / (p)->fScreenLatitude) * (p)->nWindowHeight))
 
-typedef struct {
-	GPtrArray* pRoadsArray;
-} maplayer_data_t;
+// typedef struct {
+//     GPtrArray* pRoadsArray;
+// } maplayer_data_t;
 
 typedef struct {
 	GPtrArray* pLocationsArray;
 } maplayer_locations_t;
 
+#include "map_tilemanager.h"
+
 typedef struct {
 	mappoint_t 		MapCenter;
 	dimensions_t 	MapDimensions;
@@ -195,7 +205,9 @@
 
 	// data
 	GArray			*pTracksArray;
-	maplayer_data_t	*apLayerData[ MAP_NUM_OBJECT_TYPES + 1 ];
+//	maplayer_data_t	*apLayerData[ MAP_NUM_OBJECT_TYPES + 1 ];
+
+	maptilemanager_t* pTileManager;
 
 	// Locationsets
 	GHashTable		*pLocationArrayHashTable;
@@ -209,42 +221,6 @@
 } map_t;
 
 typedef enum {
-	MAP_HITTYPE_LOCATION,
-	MAP_HITTYPE_ROAD,
-	
-	// 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])
-	MAP_HITTYPE_LOCATIONSELECTION_EDIT,	// hit locationselection graphic edit graphic (info balloon "edit")
-
-	MAP_HITTYPE_URL,
-} EMapHitType;
-
-typedef struct {
-	EMapHitType eHitType;
-	gchar* pszText;
-	union {
-		struct {
-			gint nLocationID;
-			mappoint_t Coordinates;
-		} LocationHit;
-
-		struct {
-			gint nRoadID;
-			mappoint_t ClosestPoint;
-		} RoadHit;
-
-		struct {
-			gint nLocationID;
-		} LocationSelectionHit;
-
-		struct {
-			gchar* pszURL;
-		} URLHit;
-	};
-} maphit_t;
-
-typedef enum {
 	MAP_LAYER_RENDERTYPE_LINES,
 	MAP_LAYER_RENDERTYPE_POLYGONS,
 	MAP_LAYER_RENDERTYPE_LINE_LABELS,
@@ -287,8 +263,9 @@
 
 #define DRAWFLAG_ALL 		(1|2)
 
-#define NUM_SUBLAYER_TO_DRAW (21) //(24)
-extern draworder_t layerdraworder[NUM_SUBLAYER_TO_DRAW];	//
+// #define NUM_SUBLAYER_TO_DRAW (21) //(24)
+// extern draworder_t layerdraworder[NUM_SUBLAYER_TO_DRAW];    //
+
 
 void map_init(void);
 gboolean map_new(map_t** ppMap, GtkWidget* pTargetWidget);
@@ -331,9 +308,6 @@
 void map_draw(map_t* pMap, GdkPixmap* pTargetPixmap, gint nDrawFlags);
 void map_add_track(map_t* pMap, gint hTrack);
 
-gboolean map_hit_test(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct);
-void map_hitstruct_free(map_t* pMap, maphit_t* pHitStruct);
-
 gboolean map_location_selection_add(map_t* pMap, gint nLocationID);
 gboolean map_location_selection_remove(map_t* pMap, gint nLocationID);
 
@@ -344,4 +318,9 @@
 
 gboolean map_rects_overlap(const maprect_t* p1, const maprect_t* p2);
 
+void map_zoom_to_screenrect(map_t* pMap, const screenrect_t* pRect);
+gint map_screenrect_width(const screenrect_t* pRect);
+gint map_screenrect_height(const screenrect_t* pRect);
+void map_get_screenrect_centerpoint(const screenrect_t* pRect, screenpoint_t* pPoint);
+
 #endif

Index: map_draw_cairo.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_cairo.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- map_draw_cairo.c	1 Oct 2005 05:24:16 -0000	1.27
+++ map_draw_cairo.c	5 Oct 2005 06:09:36 -0000	1.28
@@ -99,7 +99,7 @@
 	cairo_set_source_rgba(pCairo, pColor->fRed, pColor->fGreen, pColor->fBlue, pColor->fAlpha);
 }
 
-void map_draw_cairo(map_t* pMap, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags)
+void map_draw_cairo(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags)
 {
 	// 1. Set draw target to X Drawable
 	Display* dpy;
@@ -143,32 +143,38 @@
 		for(i=pMap->pLayersArray->len-1 ; i>=0 ; i--) {
 			maplayer_t* pLayer = g_ptr_array_index(pMap->pLayersArray, i);
 
+			gint nStyleZoomLevel = g_sZoomLevels[pRenderMetrics->nZoomLevel-1].nStyleZoomLevel;
+
 			if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LINES) {
 				if(nDrawFlags & DRAWFLAG_GEOMETRY) {
-					map_draw_cairo_layer_roads(pMap, pCairo, pRenderMetrics,
-											   pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
-											   pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);
+//                     map_draw_cairo_layer_roads(pMap, pCairo, pRenderMetrics,
+//                                                pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
+//                                                pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
 				}
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGONS) {
 				if(nDrawFlags & DRAWFLAG_GEOMETRY) {
-					map_draw_cairo_layer_polygons(pMap, pCairo, pRenderMetrics,
-												  pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
-												  pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);
+//                     map_draw_cairo_layer_polygons(pMap, pCairo, pRenderMetrics,
+//                                                   pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
+//                                                   pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
 				}
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LINE_LABELS) {
 				if(nDrawFlags & DRAWFLAG_LABELS) {
-					map_draw_cairo_layer_road_labels(pMap, pCairo, pRenderMetrics,
-													 pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
-													 pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);
+					gint iTile;
+					for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+						maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
+						map_draw_cairo_layer_road_labels(pMap, pCairo, pRenderMetrics,
+														 pTile->apMapObjectArrays[pLayer->nDataSource],               // data
+														 pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
+					}
 				}
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGON_LABELS) {
 				if(nDrawFlags & DRAWFLAG_LABELS) {
-					map_draw_cairo_layer_polygon_labels(pMap, pCairo, pRenderMetrics,
-														pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
-														pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);
+//                     map_draw_cairo_layer_polygon_labels(pMap, pCairo, pRenderMetrics,
+//                                                         pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,
+//                                                         pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);
 				}
 			}
 		}
@@ -246,6 +252,11 @@
 
 	for(i=0 ; i<pRoadsArray->len ; i++) {
 		road_t* pRoad = g_ptr_array_index(pRoadsArray, i);
+		
+		if(!map_rects_overlap(&(pRoad->rWorldBoundingBox), &(pRenderMetrics->rWorldBoundingBox))) {
+			continue;
+		}
+
 		if(pRoad->pszName[0] != '\0') {
 			map_draw_cairo_road_label(pMap, pCairo, pLayerStyle, pRenderMetrics, pRoad->pMapPointsArray, pRoad->pszName);
 		}
@@ -480,26 +491,11 @@
 		mappoint_t* pTmp = pMapPoint1; pMapPoint1 = pMapPoint2; pMapPoint2 = pTmp;
 	}
 
-	// find extents
-	gdouble fMaxLat = max(pMapPoint1->fLatitude, pMapPoint2->fLatitude);
-	gdouble fMinLat = min(pMapPoint1->fLatitude, pMapPoint2->fLatitude);
-	gdouble fMaxLon = max(pMapPoint1->fLongitude, pMapPoint2->fLongitude);
-	gdouble fMinLon = min(pMapPoint1->fLongitude, pMapPoint2->fLongitude);
-
 	gdouble fX1 = SCALE_X(pRenderMetrics, pMapPoint1->fLongitude);
 	gdouble fY1 = SCALE_Y(pRenderMetrics, pMapPoint1->fLatitude);
 	gdouble fX2 = SCALE_X(pRenderMetrics, pMapPoint2->fLongitude);
 	gdouble fY2 = SCALE_Y(pRenderMetrics, pMapPoint2->fLatitude);
 
-	// 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;
-	}
-
 	gdouble fRise = fY2 - fY1;
 	gdouble fRun = fX2 - fX1;
 	gdouble fLineLengthSquared = (fRun*fRun) + (fRise*fRise);
@@ -1276,7 +1272,7 @@
 
 static void map_draw_cairo_map_scale(map_t* pMap, cairo_t *pCairo, rendermetrics_t* pRenderMetrics)
 {
-	zoomlevel_t* pZoomLevel = &g_sZoomLevels[pRenderMetrics->nZoomLevel];
+	zoomlevel_t* pZoomLevel = &g_sZoomLevels[pRenderMetrics->nZoomLevel-1];
 
 	// Imperial
 	gdouble fImperialLength = 0;

Index: map_draw_cairo.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_cairo.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- map_draw_cairo.h	4 Mar 2005 02:31:55 -0000	1.1
+++ map_draw_cairo.h	5 Oct 2005 06:09:36 -0000	1.2
@@ -26,6 +26,6 @@
 
 #include <cairo.h>
 
-void map_draw_cairo(map_t* pMap, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags);
+void map_draw_cairo(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags);
 
 #endif

Index: map_draw_gdk.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_gdk.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- map_draw_gdk.c	1 Oct 2005 05:24:16 -0000	1.25
+++ map_draw_gdk.c	5 Oct 2005 06:09:36 -0000	1.26
@@ -1,5 +1,5 @@
 /***************************************************************************
- *            map_draw_cairo.c
+ *            map_draw_gdk.c
  *
  *  Copyright  2005  Ian McIntosh
  *  ian_mcintosh at linuxadvocate.org
@@ -69,7 +69,24 @@
 	gdk_gc_set_rgb_fg_color(pGC, &clr);
 }
 
-void map_draw_gdk(map_t* pMap, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags)
+void map_draw_gdk_xor_rect(map_t* pMap, GdkDrawable* pTargetDrawable, screenrect_t* pRect)
+{
+	GdkGC* pGC = pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)];
+
+	GdkGCValues gcValues;
+	gdk_gc_get_values(pGC, &gcValues);
+
+	GdkColor clrWhite = {0, 32000, 32000, 32000};
+	gdk_gc_set_function(pGC, GDK_XOR);
+	gdk_gc_set_rgb_fg_color(pGC, &clrWhite);
+	gdk_draw_rectangle(pTargetDrawable, pGC, FALSE, 
+					   min(pRect->A.nX, pRect->B.nX), min(pRect->A.nY, pRect->B.nY),	// x,y
+					   map_screenrect_width(pRect), map_screenrect_height(pRect));		// w,h
+
+	gdk_gc_set_values(pGC, &gcValues, GDK_GC_FUNCTION | GDK_GC_FOREGROUND);
+}
+
+void map_draw_gdk(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags)
 {
 	TIMER_BEGIN(maptimer, "BEGIN RENDER MAP (gdk)");
 
@@ -86,29 +103,40 @@
 		// 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 )
 		for(i=pMap->pLayersArray->len-1 ; i>=0 ; i--) {
 			maplayer_t* pLayer = g_ptr_array_index(pMap->pLayersArray, i);
 
 			if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_FILL) {
 				map_draw_gdk_layer_fill(pMap, pPixmap,  pRenderMetrics,
-										 pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);       // style
+										 pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);       // style
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LINES) {
-				map_draw_gdk_layer_lines(pMap, pPixmap, pRenderMetrics,
-										 pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,               // data
-										 pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);       // style
+				gint iTile;
+				for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+					maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
+					map_draw_gdk_layer_lines(pMap, pPixmap, pRenderMetrics,
+											 pTile->apMapObjectArrays[pLayer->nDataSource],               // data
+											 pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);       // style
+				}
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGONS) {
-				map_draw_gdk_layer_polygons(pMap, pPixmap, pRenderMetrics,
-											pMap->apLayerData[pLayer->nDataSource]->pRoadsArray,          // data
-											pLayer->paStylesAtZoomLevels[pRenderMetrics->nZoomLevel-1]);    // style
+				gint iTile;
+				for(iTile=0 ; iTile < pTiles->len ; iTile++) {
+					maptile_t* pTile = g_ptr_array_index(pTiles, iTile);
+					map_draw_gdk_layer_polygons(pMap, pPixmap, pRenderMetrics,
+												pTile->apMapObjectArrays[pLayer->nDataSource],          // data
+												pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]);    // style
+				}
 			}
 			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LOCATIONS) {
-				map_draw_gdk_locations(pMap, pPixmap, pRenderMetrics);
+//                 map_draw_gdk_locations(pMap, pPixmap, pRenderMetrics);
 			}
-			else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_LOCATION_LABELS) {
-				//map_draw_gdk_locations(pMap, pPixmap, pRenderMetrics);
+			else {
+//                 g_print("pLayer->nDrawType = %d\n", pLayer->nDrawType);
+//                 g_assert_not_reached();
 			}
 		}
 	}
@@ -148,7 +176,6 @@
 		map_draw_gdk_set_color(pGC, &(pLayerStyle->clrPrimary));
 	}
 
-
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
 		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
@@ -156,25 +183,27 @@
 			continue;
 		}
 
-		if(pRoad->pMapPointsArray->len >= 2) {
-			GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS];
+		if(pRoad->pMapPointsArray->len < 3) {
+			//g_warning("not drawing polygon with < 3 points\n");
+			continue;
+		}
 
-			if(pRoad->pMapPointsArray->len > MAX_GDK_LINE_SEGMENTS) {
-				g_warning("not drawing line with > %d segments\n", MAX_GDK_LINE_SEGMENTS);
-				continue;
-			}
+		if(pRoad->pMapPointsArray->len > MAX_GDK_LINE_SEGMENTS) {
+			//g_warning("not drawing polygon with > %d points\n", MAX_GDK_LINE_SEGMENTS);
+			continue;
+		}
 
-			// XXX: the bounding box should be pre-calculated!!!!
-			for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
-				pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);
+		GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS];
 
-				aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude);
-				aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude);
-			}
+		for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
+			pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);
 
-			gdk_draw_polygon(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)],
-				TRUE, aPoints, pRoad->pMapPointsArray->len);
-   		}
+			aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude);
+			aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude);
+		}
+
+		gdk_draw_polygon(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)],
+			TRUE, aPoints, pRoad->pMapPointsArray->len);
 	}
 	if(pLayerStyle->pGlyphFill != NULL) {
 		// Restore fill style
@@ -259,23 +288,26 @@
 		}
 
 		if(pRoad->pMapPointsArray->len > MAX_GDK_LINE_SEGMENTS) {
-			//g_warning("not drawing line with > %d segments\n", MAX_GDK_LINE_SEGMENTS);
+			//g_warning("not drawing line with > %d points\n", MAX_GDK_LINE_SEGMENTS);
 			continue;
 		}
 
-		if(pRoad->pMapPointsArray->len >= 2) {
-			// Copy all points into this array.  Yuuup this is slow. :)
-			GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS];
+		if(pRoad->pMapPointsArray->len < 2) {
+			//g_warning("not drawing line with < 2 points\n");
+			continue;
+		}
 
-			for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
-				pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);
+		// Copy all points into this array.  Yuuup this is slow. :)
+		GdkPoint aPoints[MAX_GDK_LINE_SEGMENTS];
 
-				aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude);
-				aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude);
-			}
+		for(iPoint=0 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) {
+			pPoint = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint);
 
-			gdk_draw_lines(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], aPoints, pRoad->pMapPointsArray->len);
-   		}
+			aPoints[iPoint].x = pLayerStyle->nPixelOffsetX + (gint)SCALE_X(pRenderMetrics, pPoint->fLongitude);
+			aPoints[iPoint].y = pLayerStyle->nPixelOffsetY + (gint)SCALE_Y(pRenderMetrics, pPoint->fLatitude);
+		}
+
+		gdk_draw_lines(pPixmap, pMap->pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->pTargetWidget)], aPoints, pRoad->pMapPointsArray->len);
 	}
 }
 

Index: map_draw_gdk.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_gdk.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- map_draw_gdk.h	4 Mar 2005 02:31:55 -0000	1.1
+++ map_draw_gdk.h	5 Oct 2005 06:09:36 -0000	1.2
@@ -26,6 +26,7 @@
 
 #include <gdk/gdk.h>
 
-void map_draw_gdk(map_t* pMap, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags);
+void map_draw_gdk(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetrics, GdkPixmap* pPixmap, gint nDrawFlags);
+void map_draw_gdk_xor_rect(map_t* pMap, GdkDrawable* pTargetDrawable, screenrect_t* pRect);
 
 #endif

Index: map_style.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_style.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- map_style.c	1 Oct 2005 05:24:16 -0000	1.4
+++ map_style.c	5 Oct 2005 06:09:36 -0000	1.5
@@ -30,6 +30,9 @@
 #include "glyph.h"
 #include "map_style.h"
 
+#define MIN_STYLE_LEVEL (1)
+#define MAX_STYLE_LEVEL	(10)
+
 // utility functions for iterating through lists of XML things
 #define EACH_ATTRIBUTE_OF_NODE(a,n)		(a) = (n)->properties ; (a) != NULL ; (a) = (a)->next
 #define EACH_CHILD_OF_NODE(c,n)			(c) = (n)->children ; (c) != NULL ; (c) = (c)->next
@@ -127,12 +130,12 @@
 		nMin = nMax = atoi(pszStr);
 	}
 
-	if(nMin < MIN_ZOOM_LEVEL || nMin > MAX_ZOOM_LEVEL) {
-		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
+	if(nMin < MIN_STYLE_LEVEL || nMin > MAX_STYLE_LEVEL) {
+		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_STYLE_LEVEL, MAX_STYLE_LEVEL);
 		bReturn = FALSE;
 	}
-	else if(nMax < MIN_ZOOM_LEVEL || nMax > MAX_ZOOM_LEVEL) {
-		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL);
+	else if(nMax < MIN_STYLE_LEVEL || nMax > MAX_STYLE_LEVEL) {
+		g_warning("zoom-level '%s' out of valid range (%d to %d)\n", pszZoomLevel, MIN_STYLE_LEVEL, MAX_STYLE_LEVEL);
 		bReturn = FALSE;
 	}
 	else {
@@ -375,8 +378,8 @@
 		}
 	}
 
-	gint nMinZoomLevel = MIN_ZOOM_LEVEL;
-	gint nMaxZoomLevel = MAX_ZOOM_LEVEL;
+	gint nMinZoomLevel = MIN_STYLE_LEVEL;
+	gint nMaxZoomLevel = MAX_STYLE_LEVEL;
 	if(pszZoomLevel != NULL) {
 		map_style_parse_zoomlevel(pszZoomLevel, &nMinZoomLevel, &nMaxZoomLevel);
 	}

--- map_tile.c DELETED ---

--- map_tile.h DELETED ---

--- NEW FILE: map_tilemanager.c ---
/***************************************************************************
 *            map_tilemanager.c
 *
 *  Copyright  2005  Ian McIntosh
 *  ian_mcintosh at linuxadvocate.org
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <gtk/gtk.h>
#include "util.h"
#include "map_tilemanager.h"
#include "db.h"
#include "road.h"

// 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);
static maptile_t* map_tilemanager_tile_new(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD);

struct {
	gdouble fShift;					// the units we care about (eg. 1000 = 1000ths of a degree)
	gint nModulus;					// how many of the above units each tile is on a side
	gdouble fWidth;					// width and height of a tile, in degrees
} g_aTileSizeAtLevelOfDetail[MAP_NUM_LEVELS_OF_DETAIL] = {
	{1000.0, 	70, 	70.0 / 1000.0},
	{100.0, 	35, 	35.0 / 100.0},
	{10.0, 		35, 	35.0 / 10.0},
	{1.0, 		100, 	100.0 / 1.0},
};

// Public API
maptilemanager_t* map_tilemanager_new()
{
	maptilemanager_t* pNew = g_new0(maptilemanager_t, 1);
	
	gint i;
	for(i=0 ; i<MAP_NUM_LEVELS_OF_DETAIL ; i++) {
		pNew->apTileCachedArrays[i] = g_ptr_array_new();
	}
	return pNew;
}

GPtrArray* map_tilemanager_load_tiles_for_worldrect(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD)
{
	//
	// Break the worldrect up into the aligned squares that we load
	//
	gdouble fTileShift = g_aTileSizeAtLevelOfDetail[nLOD].fShift;
	gint nTileModulus = g_aTileSizeAtLevelOfDetail[nLOD].nModulus;
	gdouble fTileWidth = g_aTileSizeAtLevelOfDetail[nLOD].fWidth;

	gint32 nLatStart = (gint32)(pRect->A.fLatitude * fTileShift);
	// round it DOWN (south)
	if(pRect->A.fLatitude > 0) {
		nLatStart -= (nLatStart % nTileModulus);
	}
	else {
		nLatStart -= (nLatStart % nTileModulus);
		nLatStart -= nTileModulus;
	}

	gint32 nLonStart = (gint32)(pRect->A.fLongitude * fTileShift);
	// round it DOWN (west)
	if(pRect->A.fLongitude > 0) {
		nLonStart -= (nLonStart % nTileModulus);
	}
	else {
		nLonStart -= (nLonStart % nTileModulus);
		nLonStart -= nTileModulus;
	}

	gint32 nLatEnd = (gint32)(pRect->B.fLatitude * fTileShift);
	// round it UP (north)
	if(pRect->B.fLatitude > 0) {
		nLatEnd -= (nLatEnd % nTileModulus);
		nLatEnd += nTileModulus;
	}
	else {
		nLatEnd -= (nLatEnd % nTileModulus);
	}

	gint32 nLonEnd = (gint32)(pRect->B.fLongitude * fTileShift);
	// round it UP (east)
	if(pRect->B.fLongitude > 0) {
		nLonEnd -= (nLonEnd % nTileModulus);
		nLonEnd += nTileModulus;
	}
	else {
		nLonEnd -= (nLonEnd % nTileModulus);
	}

	// how many tiles are we loading in each direction?
	gint nLatNumTiles = (nLatEnd - nLatStart) / nTileModulus;
	gint nLonNumTiles = (nLonEnd - nLonStart) / nTileModulus;

	gdouble fLatStart = (gdouble)nLatStart / fTileShift;
	gdouble fLonStart = (gdouble)nLonStart / fTileShift;

	if(fLatStart > pRect->A.fLatitude) {
		g_print("fLatStart %f > pRect->A.fLatitude %f\n", fLatStart, pRect->A.fLatitude);
		g_assert(fLatStart <= pRect->A.fLatitude);
	}
	if(fLonStart > pRect->A.fLongitude) {
		g_print("fLonStart %f > pRect->A.fLongitude %f!!\n", fLonStart, pRect->A.fLongitude);
		g_assert_not_reached();
	}

	GPtrArray* pTileArray = g_ptr_array_new();
	g_assert(pTileArray);

	gint nLat,nLon;
	for(nLat = 0 ; nLat < nLatNumTiles ; nLat++) {
		for(nLon = 0 ; nLon < nLonNumTiles ; nLon++) {

			maprect_t rect;
			rect.A.fLatitude = fLatStart + ((gdouble)(nLat) * fTileWidth);
			rect.A.fLongitude = fLonStart + ((gdouble)(nLon) * fTileWidth);
			rect.B.fLatitude = fLatStart + ((gdouble)(nLat+1) * fTileWidth);
			rect.B.fLongitude = fLonStart + ((gdouble)(nLon+1) * fTileWidth);

			maptile_t* pTile = map_tilemanager_tile_cache_lookup(pTileManager, &rect, nLOD);
			if(pTile) {
				// cache hit
				g_ptr_array_add(pTileArray, pTile);
			}
			else {
				// cache miss
				pTile = map_tilemanager_tile_new(pTileManager, &rect, nLOD);
				g_ptr_array_add(pTileArray, pTile);
			}
		}
	}
	return pTileArray;
}

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);
	memcpy(&(pNewTile->rcWorldBoundingBox), pRect, sizeof(maprect_t));

	gint i;
	for(i=0 ; i<MAP_NUM_OBJECT_TYPES ; i++) {
		pNewTile->apMapObjectArrays[i] = g_ptr_array_new();
	}
	g_print("(");
	_map_tilemanager_tile_load_map_objects(pNewTile, pRect, nLOD);
//	_map_tilemanager_tile_load_locations(pNewTile, pRect);
	g_print(")");

	// Add to cache
	g_ptr_array_add(pTileManager->apTileCachedArrays[nLOD], pNewTile);
	return pNewTile;
}

//
// Private functions
//
static maptile_t* map_tilemanager_tile_cache_lookup(maptilemanager_t* pTileManager, maprect_t* pRect, gint nLOD)
{
	// XXX: this should not match on rect, it should match on LOD and Tile ID only
	GPtrArray* pArray = pTileManager->apTileCachedArrays[nLOD];

	gint i;
	for(i=0 ; i<pArray->len ; i++) {
		maptile_t* pTile = g_ptr_array_index(pArray, i);

		if(map_math_maprects_equal(&(pTile->rcWorldBoundingBox), pRect)) {
			//g_print("Cache hit\n");
			return pTile;
		}
	}
	//g_print("cache miss for (%f,%f),(%f,%f)\n", pRect->A.fLongitude, pRect->A.fLatitude, pRect->B.fLongitude, pRect->B.fLatitude);
	return NULL;
}

static void _map_tilemanager_tile_load_map_objects(maptile_t* pTile, maprect_t* pRect, gint nLOD)
{
	db_resultset_t* pResultSet = NULL;
	db_row_t aRow;

	TIMER_BEGIN(mytimer, "BEGIN Geometry LOAD");

	gchar* pszRoadTableName = g_strdup_printf("Road%d", nLOD);

	// generate SQL
	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"
		" 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)",

		//pszRoadTableName,	 no ID column 
		pszRoadTableName, pszRoadTableName,

		// Load all details for LOD 0
		(nLOD == 0) ? ", AddressLeftStart, AddressLeftEnd, AddressRightStart, AddressRightEnd" : "",
		pszRoadTableName, pszRoadTableName,

		// upper left
		g_ascii_dtostr(azCoord1, 20, pRect->A.fLatitude), g_ascii_dtostr(azCoord2, 20, pRect->A.fLongitude), 
		// upper right
		g_ascii_dtostr(azCoord3, 20, pRect->A.fLatitude), g_ascii_dtostr(azCoord4, 20, pRect->B.fLongitude), 
		// bottom right
		g_ascii_dtostr(azCoord5, 20, pRect->B.fLatitude), g_ascii_dtostr(azCoord6, 20, pRect->B.fLongitude), 
		// bottom left
		g_ascii_dtostr(azCoord7, 20, pRect->B.fLatitude), g_ascii_dtostr(azCoord8, 20, pRect->A.fLongitude), 
		// upper left again
		azCoord1, azCoord2);

	//g_print("sql: %s\n", pszSQL);

	db_query(pszSQL, &pResultSet);
	g_free(pszSQL);
	g_free(pszRoadTableName);

	TIMER_SHOW(mytimer, "after query");

	guint32 uRowCount = 0;
	if(pResultSet) {
		while((aRow = db_fetch_row(pResultSet))) {
			uRowCount++;

			// aRow[0] is ID
			// aRow[1] is TypeID
			// aRow[2] is Coordinates in mysql's text format
			// aRow[3] is road name
			// aRow[4] is road name suffix id
			// aRow[5] is road address left start
			// aRow[6] is road address left end
			// aRow[7] is road address right start 
			// aRow[8] is road address right end

			// Get layer type that this belongs on
			gint nTypeID = atoi(aRow[1]);
			if(nTypeID < MAP_OBJECT_TYPE_FIRST || nTypeID > MAP_OBJECT_TYPE_LAST) {
				g_warning("geometry record '%s' has bad type '%s'\n", aRow[0], aRow[1]);
				continue;
			}

			//road_t* pNewRoad = NULL;
			//road_alloc(&pNewRoad);
			road_t* pNewRoad = g_new0(road_t, 1);

			// Build name by adding suffix, if one is present
			if(aRow[3] != NULL && aRow[4] != NULL) {
				const gchar* pszSuffix = road_suffix_itoa(atoi(aRow[4]), ROAD_SUFFIX_LENGTH_SHORT);
				pNewRoad->pszName = g_strdup_printf("%s%s%s", aRow[3], (pszSuffix[0] != '\0') ? " " : "", pszSuffix);
			}
			else {
				pNewRoad->pszName = g_strdup("");	// XXX: could we maybe not do this?
			}
			// We only load this st
			if(nLOD == MAP_LEVEL_OF_DETAIL_BEST) {
				pNewRoad->nAddressLeftStart = atoi(aRow[5]);
				pNewRoad->nAddressLeftEnd = atoi(aRow[6]);
				pNewRoad->nAddressRightStart = atoi(aRow[7]);
				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));

#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) {
				mappoint_t* pPointA = &g_array_index(pNewRoad->pMapPointsArray, mappoint_t, 0);
				mappoint_t* pPointB = &g_array_index(pNewRoad->pMapPointsArray, mappoint_t, pNewRoad->pMapPointsArray->len-1);

				if(pPointA->fLatitude == pPointB->fLatitude && pPointA->fLongitude == pPointB->fLongitude) {
					nTypeID = MAP_OBJECT_TYPE_LAKE;
				}
			}
#endif

			// Add this item to layer's list of pointstrings
			g_ptr_array_add(pTile->apMapObjectArrays[nTypeID], pNewRoad);
		} // end while loop on rows
		//g_print("[%d rows]\n", uRowCount);
		TIMER_SHOW(mytimer, "after rows retrieved");

		db_free_result(pResultSet);
		TIMER_SHOW(mytimer, "after free results");
		TIMER_END(mytimer, "END Geometry LOAD");
	}
}

// static gboolean map_data_load_locations(map_t* pMap, maprect_t* pRect)
// {
//     g_return_val_if_fail(pMap != NULL, FALSE);
//     g_return_val_if_fail(pRect != NULL, FALSE);
//
// //     if(map_get_zoomlevel(pMap) < MIN_ZOOM_LEVEL_FOR_LOCATIONS) {
// //         return TRUE;
// //     }
//
//     TIMER_BEGIN(mytimer, "BEGIN Locations LOAD");
//
//     // generate SQL
//     gchar* pszSQL;
//     gchar azCoord1[20], azCoord2[20], azCoord3[20], azCoord4[20], azCoord5[20], azCoord6[20], azCoord7[20], azCoord8[20];
//     pszSQL = g_strdup_printf(
//         "SELECT Location.ID, Location.LocationSetID, AsBinary(Location.Coordinates), LocationAttributeValue_Name.Value" // LocationAttributeValue_Name.Value is the "Name" field of this Location
//         " FROM Location"
//         " LEFT JOIN LocationAttributeValue AS LocationAttributeValue_Name ON (LocationAttributeValue_Name.LocationID=Location.ID AND LocationAttributeValue_Name.AttributeNameID=%d)"
//         " WHERE"
//         " MBRIntersects(GeomFromText('Polygon((%s %s,%s %s,%s %s,%s %s,%s %s))'), Coordinates)",
//         LOCATION_ATTRIBUTE_ID_NAME, // attribute ID for 'name'
//         // upper left
//         g_ascii_dtostr(azCoord1, 20, pRect->A.fLatitude), g_ascii_dtostr(azCoord2, 20, pRect->A.fLongitude),
//         // upper right
//         g_ascii_dtostr(azCoord3, 20, pRect->A.fLatitude), g_ascii_dtostr(azCoord4, 20, pRect->B.fLongitude),
//         // bottom right
//         g_ascii_dtostr(azCoord5, 20, pRect->B.fLatitude), g_ascii_dtostr(azCoord6, 20, pRect->B.fLongitude),
//         // bottom left
//         g_ascii_dtostr(azCoord7, 20, pRect->B.fLatitude), g_ascii_dtostr(azCoord8, 20, pRect->A.fLongitude),
//         // upper left again
//         azCoord1, azCoord2);
//     //g_print("sql: %s\n", pszSQL);
//
//     db_resultset_t* pResultSet = NULL;
//     db_query(pszSQL, &pResultSet);
//     g_free(pszSQL);
//
//     TIMER_SHOW(mytimer, "after query");
//
//     guint32 uRowCount = 0;
//     if(pResultSet) {
//         db_row_t aRow;
//         while((aRow = db_fetch_row(pResultSet))) {
//             uRowCount++;
//
//             // aRow[0] is ID
//             // aRow[1] is LocationSetID
//             // aRow[2] is Coordinates in mysql's binary format
//             // aRow[3] is Name
//
//             // Get layer type that this belongs on
//             gint nLocationSetID = atoi(aRow[1]);
//
//             // Extract
//             location_t* pNewLocation = NULL;
//             location_alloc(&pNewLocation);
//
//             pNewLocation->nID = atoi(aRow[0]);
//
//             // Parse coordinates
//             db_parse_wkb_point(aRow[2], &(pNewLocation->Coordinates));
//
//             // make a copy of the name field, or "" (never leave it == NULL)
//             pNewLocation->pszName = g_strdup(aRow[3] != NULL ? aRow[3] : "");
//             map_store_location(pMap, pNewLocation, nLocationSetID);
//         } // end while loop on rows
//         //g_print("[%d rows]\n", uRowCount);
//         TIMER_SHOW(mytimer, "after rows retrieved");
//
//         db_free_result(pResultSet);
//         TIMER_END(mytimer, "END Locations LOAD");
//         return TRUE;
//     }
//     else {
//         TIMER_END(mytimer, "END Locations LOAD (0 results)");
//         return FALSE;
//     }
// }
//
// static void map_data_clear(map_t* pMap)
// {
//     // Clear layers
//     gint i,j;
//     for(i=0 ; i<G_N_ELEMENTS(pMap->apLayerData) ; i++) {
//         maplayer_data_t* pLayerData = pMap->apLayerData[i];
//
//         // Free each
//         for(j = (pLayerData->pRoadsArray->len - 1) ; j>=0 ; j--) {
//             road_t* pRoad = g_ptr_array_remove_index_fast(pLayerData->pRoadsArray, j);
//             g_array_free(pRoad->pMapPointsArray, TRUE);
//             g_free(pRoad);
//         }
//         g_assert(pLayerData->pRoadsArray->len == 0);
//     }
//
//     // Clear locations
//     map_init_location_hash(pMap);
// }

--- NEW FILE: map_tilemanager.h ---
/***************************************************************************
 *            map_tilemanager.h
 *
 *  Copyright  2005  Ian McIntosh
 *  ian_mcintosh at linuxadvocate.org
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef _MAP_TILEMANAGER_H_
#define _MAP_TILEMANAGER_H_

#include <gtk/gtk.h>

typedef struct {
	GPtrArray* apTileCachedArrays[4];	// MAP_NUM_LEVELS_OF_DETAIL
} maptilemanager_t;

#include "map.h"

typedef struct {
	maprect_t rcWorldBoundingBox;
	GPtrArray* apMapObjectArrays[ MAP_NUM_OBJECT_TYPES + 1 ];
} maptile_t;

maptilemanager_t* map_tilemanager_new();

// returns GArray containing maptile_t types 
GPtrArray* map_tilemanager_load_tiles_for_worldrect(maptilemanager_t* pTileManager, maprect_t* pWorldRect, gint nLOD);

#endif

Index: road.c
===================================================================
RCS file: /cvs/cairo/roadster/src/road.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- road.c	1 Oct 2005 00:56:20 -0000	1.8
+++ road.c	5 Oct 2005 06:09:36 -0000	1.9
@@ -22,11 +22,7 @@
  */
 
 #include <gtk/gtk.h>
-#include "main.h"
 #include "road.h"
-#include "util.h"
-#include "map.h"
-#include "gfreelist.h"
 
 struct {
 	gchar* pszLong;

Index: scenemanager.c
===================================================================
RCS file: /cvs/cairo/roadster/src/scenemanager.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- scenemanager.c	25 Sep 2005 19:02:37 -0000	1.15
+++ scenemanager.c	5 Oct 2005 06:09:36 -0000	1.16
@@ -21,23 +21,18 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <gtk/gtk.h>
-
-#include "main.h"
-#include "scenemanager.h"
-
-#define ENABLE_NO_DUPLICATE_LABELS
-
 /*
 Goals:
  - Keep text labels and other screen objects from overlapping
  - Prevent the same text from showing up too often (currently not more than once)
 */
 
-void scenemanager_init(void)
-{
-	
-}
+#include <gtk/gtk.h>
+
+#include "main.h"
+#include "scenemanager.h"
+
+#define ENABLE_NO_DUPLICATE_LABELS
 
 void scenemanager_new(scenemanager_t** ppReturn)
 {

Index: scenemanager.h
===================================================================
RCS file: /cvs/cairo/roadster/src/scenemanager.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- scenemanager.h	25 Sep 2005 19:02:37 -0000	1.7
+++ scenemanager.h	5 Oct 2005 06:09:36 -0000	1.8
@@ -38,7 +38,6 @@
 	GHashTable* pLabelHash;
 } scenemanager_t;
 
-void scenemanager_init(void);
 void scenemanager_new(scenemanager_t** ppReturn);
 void scenemanager_set_screen_dimensions(scenemanager_t* pSceneManager, gint nWindowWidth, gint nWindowHeight);
 

Index: search_road.c
===================================================================
RCS file: /cvs/cairo/roadster/src/search_road.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- search_road.c	1 Oct 2005 01:42:12 -0000	1.28
+++ search_road.c	5 Oct 2005 06:09:36 -0000	1.29
@@ -34,7 +34,7 @@
 #include "glyph.h"
 #include "searchwindow.h"		// for defines about glyph size
 
-#define ROAD_RESULT_SUGGESTED_ZOOMLEVEL		(4)
+#define ROAD_RESULT_SUGGESTED_ZOOMLEVEL		(37)
 
 #define FORMAT_ROAD_RESULT_WITHOUT_NUMBER 	("%s %s\n%s")
 #define FORMAT_ROAD_RESULT_WITH_NUMBER 		("%d %s %s\n%s")
@@ -214,10 +214,10 @@
 	if(pRoadSearch->nNumber != ROADSEARCH_NUMBER_NONE) {
 		pszAddressClause = g_strdup_printf(
 			" AND ("
-			"(%d BETWEEN Road.AddressLeftStart AND Road.AddressLeftEnd)"
-			" OR (%d BETWEEN Road.AddressLeftEnd AND Road.AddressLeftStart)"
-			" OR (%d BETWEEN Road.AddressRightStart AND Road.AddressRightEnd)"
-			" OR (%d BETWEEN Road.AddressRightEnd AND Road.AddressRightStart)"
+			"(%d BETWEEN Road0.AddressLeftStart AND Road0.AddressLeftEnd)"
+			" OR (%d BETWEEN Road0.AddressLeftEnd AND Road0.AddressLeftStart)"
+			" OR (%d BETWEEN Road0.AddressRightStart AND Road0.AddressRightEnd)"
+			" OR (%d BETWEEN Road0.AddressRightEnd AND Road0.AddressRightStart)"
 			")", pRoadSearch->nNumber, pRoadSearch->nNumber,
 				 pRoadSearch->nNumber, pRoadSearch->nNumber);
 	}
@@ -238,7 +238,7 @@
 	gchar* pszZIPClause;
 	if(pRoadSearch->pszZIPCode != NULL) {
 		gchar* pszSafeZIP = db_make_escaped_string(pRoadSearch->pszZIPCode);
-		pszZIPClause = g_strdup_printf(" AND (Road.ZIPCodeLeft='%s' OR Road.ZIPCodeRight='%s')", pszSafeZIP, pszSafeZIP);
+		pszZIPClause = g_strdup_printf(" AND (Road0.ZIPCodeLeft='%s' OR Road0.ZIPCodeRight='%s')", pszSafeZIP, pszSafeZIP);
 		db_free_escaped_string(pszSafeZIP);
 	}
 	else {
@@ -247,7 +247,7 @@
 
 	gchar* pszCityClause;
 	if(pRoadSearch->nCityID != 0) {
-		pszCityClause = g_strdup_printf(" AND (Road.CityLeftID=%d OR Road.CityRightID=%d)", pRoadSearch->nCityID, pRoadSearch->nCityID);
+		pszCityClause = g_strdup_printf(" AND (Road0.CityLeftID=%d OR Road0.CityRightID=%d)", pRoadSearch->nCityID, pRoadSearch->nCityID);
 	}
 	else {
 		pszCityClause = g_strdup("");
@@ -280,19 +280,19 @@
 	//pszRoadNameCondition = g_strdup_printf("RoadName.NameSoundex = SUBSTRING(SOUNDEX('%s') FROM 1 FOR 10)", pszSafeRoadName);
 
 	gchar* pszQuery = g_strdup_printf(
-		"SELECT Road.ID, RoadName.Name, RoadName.SuffixID, AsBinary(Road.Coordinates), Road.AddressLeftStart, Road.AddressLeftEnd, Road.AddressRightStart, Road.AddressRightEnd, CityLeft.Name, CityRight.Name"
-		", StateLeft.Code, StateRight.Code, Road.ZIPCodeLeft, Road.ZIPCodeRight"
+		"SELECT 0 AS ID, RoadName.Name, RoadName.SuffixID, AsBinary(Road0.Coordinates), Road0.AddressLeftStart, Road0.AddressLeftEnd, Road0.AddressRightStart, Road0.AddressRightEnd, CityLeft.Name, CityRight.Name"
+		", StateLeft.Code, StateRight.Code, Road0.ZIPCodeLeft, Road0.ZIPCodeRight"
 		" FROM RoadName"
-		" LEFT JOIN Road ON (RoadName.ID=Road.RoadNameID%s)"					// address # clause
+		" LEFT JOIN Road0 ON (RoadName.ID=Road0.RoadNameID%s)"					// address # clause
 		// left side
-	    " LEFT JOIN City AS CityLeft ON (Road.CityLeftID=CityLeft.ID)"
+	    " LEFT JOIN City AS CityLeft ON (Road0.CityLeftID=CityLeft.ID)"
 		" LEFT JOIN State AS StateLeft ON (CityLeft.StateID=StateLeft.ID)"
 		// right side
-		" LEFT JOIN City AS CityRight ON (Road.CityRightID=CityRight.ID)"
+		" LEFT JOIN City AS CityRight ON (Road0.CityRightID=CityRight.ID)"
 		" LEFT JOIN State AS StateRight ON (CityRight.StateID=StateRight.ID)"
 		" WHERE %s"
 //		" WHERE RoadName.Name='%s'"
-		" AND Road.ID IS NOT NULL"	// don't include rows where the Road didn't match
+		" AND Road0.TypeID IS NOT NULL"	// (any field will do) don't include rows where the Road didn't match
 		// begin clauses
 		"%s"
 		"%s"
@@ -353,7 +353,7 @@
 				db_parse_wkb_linestring(aRow[3], pMapPointsArray, &r);
 				search_road_filter_result(aRow[1], pRoadSearch->nNumber, atoi(aRow[2]), atoi(aRow[4]), atoi(aRow[5]), atoi(aRow[6]), atoi(aRow[7]), aRow[8], aRow[9], aRow[10], aRow[11], aRow[12], aRow[13], pMapPointsArray);
 				//g_print("%03d: Road.ID='%s' RoadName.Name='%s', Suffix=%s, L:%s-%s, R:%s-%s\n", nCount, aRow[0], aRow[1], aRow[3], aRow[4], aRow[5], aRow[6], aRow[7]);
-				
+
 				g_array_free(pMapPointsArray, TRUE);
 			}
 		}



More information about the cairo-commit mailing list