[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, ¢erPoint)) return;
- if(map_get_distance_in_pixels(g_MainWindow.pMap, pPoint, ¢erPoint) < MAX_DISTANCE_FOR_AUTO_SLIDE_IN_PIXELS) {
+// if(map_get_distance_in_pixels(g_MainWindow.pMap, pPoint, ¢erPoint) < 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