diff options
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | data/roadster.glade | 40 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/db.c | 22 | ||||
-rw-r--r-- | src/db.h | 3 | ||||
-rw-r--r-- | src/geometryset.c | 232 | ||||
-rw-r--r-- | src/geometryset.h | 48 | ||||
-rw-r--r-- | src/glyph.c | 14 | ||||
-rw-r--r-- | src/gotowindow.c | 2 | ||||
-rw-r--r-- | src/import_tiger.c | 3 | ||||
-rw-r--r-- | src/layers.c | 66 | ||||
-rw-r--r-- | src/layers.h | 42 | ||||
-rw-r--r-- | src/main.c | 24 | ||||
-rw-r--r-- | src/mainwindow.c | 155 | ||||
-rw-r--r-- | src/mainwindow.h | 3 | ||||
-rw-r--r-- | src/map.c | 807 | ||||
-rw-r--r-- | src/map.h | 153 | ||||
-rw-r--r-- | src/road.c | 221 | ||||
-rw-r--r-- | src/road.h | 84 | ||||
-rw-r--r-- | src/scenemanager.c | 52 | ||||
-rw-r--r-- | src/scenemanager.h | 20 | ||||
-rw-r--r-- | src/search.c | 10 | ||||
-rw-r--r-- | src/search_location.c | 5 | ||||
-rw-r--r-- | src/search_road.c | 54 | ||||
-rw-r--r-- | src/searchwindow.c | 4 | ||||
-rw-r--r-- | src/util.h | 2 |
26 files changed, 1067 insertions, 1028 deletions
@@ -1,16 +1,37 @@ +2005-03-01 Ian McIntosh <ian_mcintosh@linuxadvocate.org> + + * road.c: + * road.h: Added with code removed from map module. + * geometryset.c: + * geometryset.h: Removed. + * map.c: Moved static data to road.c. Removed global map object and moved to allocated map object (all map_* functions take a map pointer now). Trying to switch to threaded rendering (currently disabled). + * db.c: Added support for locking. + * mainwindow.c: Now owns an allocated map object. Switched from single-click to double-click to move around. + * gotowindow.c: Talk to mainwindow only, not map. + * layers.c: Don't store loaded map data in the layers settings structure. (Stored in map object now.) + * main.c: Changed main_init() to return boolean. + * scenemanager.c: Removed global data, switched to allocated (a scenemanager is owned by a map). + * search.c: Can now deal with search strings containing newlines and other whitespace junk. + * search_road.c: Perform exact-match for street names of 3 or fewer chars for speed and results quality. + 2005-02-28 Nathan Fredrickson <nathan@silverorange.com> * README: Update dependency list. * configure.ac: Re-add -lmygcc. Clean up. 2005-02-28 Nathan Fredrickson <nathan@silverorange.com> * main.c: Make main_init() return a value. - * mainwindow.c: Add missing prototype. + * mainwindow.c: Add missing prototype. * configure.ac: Add pkgconfig check for libsvg and libsvg-cairo. * src/Makefile.am: Remove the hacky inclusion of libsvg-cairo. 2005-02-27 Ian McIntosh <ian_mcintosh@linuxadvocate.org> - * configure.ac: Added libsvg-cairo as dependency. (Not quite correct. Nate will fix it.:) + * glyph.c: + * glyph.h: Added. + +2005-02-27 Ian McIntosh <ian_mcintosh@linuxadvocate.org> + + * configure.ac: Added libsvg-cairo as dependency. (Not quite correct? Nate will fix it.:) * Makefile.am: Added glyph.c. * datasetwindow.c: Removed Import button. * db.c: Removed debugging comments. City with the same name are no longer shared between states. diff --git a/data/roadster.glade b/data/roadster.glade index 32bbc7a..13aabcd 100644 --- a/data/roadster.glade +++ b/data/roadster.glade @@ -335,44 +335,6 @@ </child> <child> - <widget class="GtkToolItem" id="toolitem17"> - <property name="visible">True</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - <property name="is_important">False</property> - - <child> - <widget class="GtkToolButton" id="gotobutton"> - <property name="label" translatable="yes"></property> - <property name="use_underline">True</property> - <property name="stock_id">gtk-jump-to</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - <property name="is_important">False</property> - <signal name="clicked" handler="on_gotobutton_clicked" last_modification_time="Thu, 09 Sep 2004 20:11:08 GMT"/> - </widget> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - - <child> - <widget class="GtkSeparatorToolItem" id="separatortoolitem2"> - <property name="sensitive">False</property> - <property name="draw">True</property> - <property name="visible_horizontal">True</property> - <property name="visible_vertical">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - - <child> <widget class="GtkToolItem" id="toolitem20"> <property name="visible">True</property> <property name="visible_horizontal">True</property> @@ -489,7 +451,7 @@ <property name="has_frame">True</property> <property name="invisible_char" translatable="yes">*</property> <property name="activates_default">True</property> - <property name="width_chars">28</property> + <property name="width_chars">23</property> </widget> </child> </widget> diff --git a/src/Makefile.am b/src/Makefile.am index 18069b9..9e66cac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,6 @@ roadster_SOURCES = \ mainwindow.c\ gotowindow.c\ map.c\ - geometryset.c\ layers.c\ import.c\ import_tiger.c\ @@ -42,7 +41,8 @@ roadster_SOURCES = \ point.c\ pointstring.c\ track.c\ - glyph.c + glyph.c\ + road.c roadster_LDADD = \ $(GNOME_LIBS) \ @@ -37,7 +37,6 @@ #include "db.h" #include "mainwindow.h" -#include "geometryset.h" #include "util.h" #include "layers.h" #include "locationset.h" @@ -54,12 +53,23 @@ #define MYSQL_GET_RESULT(x) mysql_store_result((x)) db_connection_t* g_pDB = NULL; +GMutex* g_pDBMutex = NULL; + +void db_lock(void) +{ + g_mutex_lock(g_pDBMutex); +} + +void db_unlock(void) +{ + g_mutex_unlock(g_pDBMutex); +} gboolean db_query(const gchar* pszSQL, db_resultset_t** ppResultSet) { g_assert(pszSQL != NULL); if(g_pDB == NULL) return FALSE; - + if(mysql_query(g_pDB->m_pMySQLConnection, pszSQL) != MYSQL_RESULT_SUCCESS) { g_warning("db_query: %s (SQL: %s)\n", mysql_error(g_pDB->m_pMySQLConnection), pszSQL); return FALSE; @@ -67,7 +77,7 @@ gboolean db_query(const gchar* pszSQL, db_resultset_t** ppResultSet) // get result? if(ppResultSet != NULL) { - *ppResultSet = (db_resultset_t*)MYSQL_GET_RESULT(g_pDB->m_pMySQLConnection); + *ppResultSet = (db_resultset_t*)MYSQL_GET_RESULT(g_pDB->m_pMySQLConnection); } return TRUE; } @@ -76,7 +86,7 @@ static gboolean db_insert(const gchar* pszSQL, gint* pnReturnRowsInserted) { g_assert(pszSQL != NULL); if(g_pDB == NULL) return FALSE; - + if(mysql_query(g_pDB->m_pMySQLConnection, pszSQL) != MYSQL_RESULT_SUCCESS) { g_warning("db_query: %s (SQL: %s)\n", mysql_error(g_pDB->m_pMySQLConnection), pszSQL); return FALSE; @@ -182,6 +192,8 @@ gboolean db_is_empty() // call once on program start-up void db_init() { + g_pDBMutex = g_mutex_new(); + #ifdef HAVE_MYSQL_EMBED gchar* pszDataDir = g_strdup_printf("%s/.roadster/data", g_get_home_dir()); gchar* pszSetDataDirCommand = g_strdup_printf("--datadir=%s", pszDataDir); @@ -572,7 +584,7 @@ void db_create_tables() " Name VARCHAR(30) NOT NULL," " SuffixID INT1 UNSIGNED NOT NULL," " PRIMARY KEY (ID)," - " UNIQUE KEY (Name(30), SuffixID));", NULL); + " UNIQUE KEY (Name(15), SuffixID));", NULL); // Road_RoadName db_query("CREATE TABLE IF NOT EXISTS Road_RoadName(" @@ -93,4 +93,7 @@ gboolean db_insert_road(gint nLayerType, gboolean db_city_get_id(const gchar* pszName, gint nStateID, gint* pnReturnID); gboolean db_state_get_id(const gchar* pszName, gint* pnReturnID); +void db_lock(void); +void db_unlock(void); + #endif diff --git a/src/geometryset.c b/src/geometryset.c deleted file mode 100644 index 706dfa7..0000000 --- a/src/geometryset.c +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************** - * geometryset.c - * - * Copyright 2005 Ian McIntosh - * ian_mcintosh@linuxadvocate.org - ****************************************************************************/ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - A GeometrySet holds an array of geometry objects (used for roads, railroads and parks right now) -*/ - -#include <gtk/gtk.h> -#include <string.h> -#include <stdlib.h> -#include "geometryset.h" -#include "map.h" -#include "util.h" -#include "point.h" -#include "pointstring.h" -#include "db.h" -#include "layers.h" - - -/******************************************************* -** construction / destruction -*******************************************************/ -gboolean geometryset_new(geometryset_t** ppGeometrySet) -{ - g_return_val_if_fail(ppGeometrySet != NULL, FALSE); - g_return_val_if_fail(*ppGeometrySet == NULL, FALSE); // must be a pointer to a NULL pointer - - // create geometryset - geometryset_t* pNew = g_new0(geometryset_t, 1); - - // initialize it - pNew->m_pPointStringsArray = g_ptr_array_sized_new(20); - g_return_val_if_fail(pNew->m_pPointStringsArray != NULL, FALSE); - - *ppGeometrySet = pNew; - return TRUE; -} - -// free all shapes -void geometryset_clear(geometryset_t* pGeometrySet) -{ - int i; - - // Free each pointstring - for(i = (pGeometrySet->m_pPointStringsArray->len - 1) ; i>=0 ; i--) { - pointstring_t* pPointString = g_ptr_array_remove_index_fast(pGeometrySet->m_pPointStringsArray, i); - pointstring_free(pPointString); - } -} - -void geometryset_free(geometryset_t* pGeometrySet) -{ - g_assert("FALSE"); // not used/tested/written yet - - g_return_if_fail(pGeometrySet != NULL); - g_return_if_fail(pGeometrySet->m_pPointStringsArray != NULL); - - // Empty it first... - geometryset_clear(pGeometrySet); - - g_assert(pGeometrySet->m_pPointStringsArray->len == 0); - - // Free the data structures themselves - g_ptr_array_free(pGeometrySet->m_pPointStringsArray, FALSE); // FALSE means don't delete items - pGeometrySet->m_pPointStringsArray = NULL; -} - -gboolean geometryset_load_geometry(maprect_t* pRect) -{ - g_return_val_if_fail(pRect != NULL, FALSE); - - db_resultset_t* pResultSet = NULL; - db_row_t aRow; - - gint nZoomLevel = map_get_zoomlevel(); - - TIMER_BEGIN(mytimer, "BEGIN Geometry LOAD"); - - // HACKY: make a list of layer IDs "2,3,5,6" - gchar azLayerNumberList[200] = {0}; - gint nActiveLayerCount = 0; - gint i; - for(i=LAYER_FIRST ; i <= LAYER_LAST ;i++) { - if(g_aLayers[i].m_Style.m_aSubLayers[0].m_afLineWidths[nZoomLevel-1] != 0.0 || - g_aLayers[i].m_Style.m_aSubLayers[1].m_afLineWidths[nZoomLevel-1] != 0.0) - { - gchar azLayerNumber[10]; - - if(nActiveLayerCount > 0) g_snprintf(azLayerNumber, 10, ",%d", i); - else g_snprintf(azLayerNumber, 10, "%d", i); - - g_strlcat(azLayerNumberList, azLayerNumber, 200); - nActiveLayerCount++; - } - } - if(nActiveLayerCount == 0) { - g_print("no visible layers!\n"); - layers_clear(); - return TRUE; - } - - // generate SQL - gchar* pszSQL = g_strdup_printf( - "SELECT Road.ID, Road.TypeID, AsText(Road.Coordinates), RoadName.Name, RoadName.SuffixID" - " FROM Road " - " LEFT JOIN Road_RoadName ON (Road.ID=Road_RoadName.RoadID)" - " LEFT JOIN RoadName ON (Road_RoadName.RoadNameID=RoadName.ID)" - " WHERE" - " TypeID IN (%s) AND" - " MBRIntersects(GeomFromText('Polygon((%f %f,%f %f,%f %f,%f %f,%f %f))'), Coordinates)", - azLayerNumberList, - pRect->m_A.m_fLatitude, pRect->m_A.m_fLongitude, // upper left - pRect->m_A.m_fLatitude, pRect->m_B.m_fLongitude, // upper right - pRect->m_B.m_fLatitude, pRect->m_B.m_fLongitude, // bottom right - pRect->m_B.m_fLatitude, pRect->m_A.m_fLongitude, // bottom left - pRect->m_A.m_fLatitude, pRect->m_A.m_fLongitude // upper left again - ); - //g_print("sql: %s\n", pszSQL); - - db_query(pszSQL, &pResultSet); - g_free(pszSQL); - - TIMER_SHOW(mytimer, "after query"); - - guint32 uRowCount = 0; - if(pResultSet) { - // HACK: empty out old data, since we don't know how to merge yet - layers_clear(); - TIMER_SHOW(mytimer, "after clear layers"); - while((aRow = db_fetch_row(pResultSet))) { - uRowCount++; - - // aRow[0] is ID - // aRow[1] is TypeID - // aRow[2] is Coordinates in mysql's text format - // aRow[3] is road name - // aRow[4] is road name suffix id -// g_print("data: %s, %s, %s, %s, %s\n", aRow[0], aRow[1], aRow[2], aRow[3], aRow[4]); - - // Get layer type that this belongs on - gint nTypeID = atoi(aRow[1]); - if(nTypeID < LAYER_FIRST || nTypeID > LAYER_LAST) { - g_warning("geometry record '%s' has bad type '%s'\n", aRow[0], aRow[1]); - continue; - } - - // Extract points - pointstring_t* pNewPointString = NULL; - if(!pointstring_alloc(&pNewPointString)) { - g_warning("out of memory loading pointstrings\n"); - continue; - } - db_parse_pointstring(aRow[2], pNewPointString, point_alloc); - - // Build name by adding suffix, if one is present - gchar azFullName[100] = ""; - - // does it have a name? - if(aRow[3] != NULL && aRow[4] != NULL) { - gint nSuffixID = atoi(aRow[4]); - const gchar* pszSuffix = map_road_suffix_itoa(nSuffixID, SUFFIX_LENGTH_SHORT); - g_snprintf(azFullName, 100, "%s%s%s", - aRow[3], (pszSuffix[0] != '\0') ? " " : "", pszSuffix); - } - pNewPointString->m_pszName = g_strdup(azFullName); - - // Add this item to layer's list of pointstrings - g_ptr_array_add(g_aLayers[nTypeID].m_pGeometrySet->m_pPointStringsArray, pNewPointString); - } // end while loop on rows - g_print("[%d rows]\n", uRowCount); - TIMER_SHOW(mytimer, "after rows retrieved"); - - db_free_result(pResultSet); - TIMER_SHOW(mytimer, "after free results"); - TIMER_END(mytimer, "END Geometry LOAD"); - - return TRUE; - } - else { - g_print(" no rows\n"); - return FALSE; - } -} - -#ifdef ROADSTER_DEAD_CODE -/******************************************************* -** Debug functions -*******************************************************/ -/* -void geometryset_debug_print(geometryset_t* pGeometrySet) -{ - if(pGeometrySet->m_pPointStringsArray == NULL) { - g_print("m_pPointStringsArray is NULL\n"); - } - else { - g_print("pointstring list (%d items):\n", pGeometrySet->m_pPointStringsArray->len); - int i; - for(i=0 ; i<pGeometrySet->m_pPointStringsArray->len ; i++) { - pointstring_t* pPointString = g_ptr_array_index(pGeometrySet->m_pPointStringsArray, i); - - g_print("- string (%d items): ", pPointString->m_pPointsArray->len); - int j; - for(j=0 ; j<pPointString->m_pPointsArray->len ; j++) { - mappoint_t* pPoint = g_ptr_array_index(pPointString->m_pPointsArray, j); - g_print("(%.5f,%.5f), ", pPoint->m_fLatitude, pPoint->m_fLongitude); - } - g_print("\n"); - } - } -} -*/ -#endif diff --git a/src/geometryset.h b/src/geometryset.h deleted file mode 100644 index 6de9920..0000000 --- a/src/geometryset.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * geometryset.h - * - * Copyright 2005 Ian McIntosh - * ian_mcintosh@linuxadvocate.org - ****************************************************************************/ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef __GEOMETRYSET_H__ -#define __GEOMETRYSET_H__ - -// a geometry set holds all the geometry for a layer -typedef struct geometryset { - GPtrArray* m_pPointStringsArray; -} geometryset_t; - -#include "map.h" - -void geometryset_init(void); -void geometryset_free(geometryset_t* pGeometrySet); -void geometryset_clear(geometryset_t* pGeometrySet); - -gboolean geometryset_new(geometryset_t** ppGeometrySet); - -//gboolean geometryset_util_new_point(mappoint_t** ppPoint); -//gboolean geometryset_util_new_pointstring(pointstring_t** ppPointString); -//void geometryset_util_free_pointstring(pointstring_t* pPointString); - -gboolean geometryset_load_geometry(maprect_t* pRect); - -//void geometryset_debug_print(geometryset_t* pGeometrySet); - -#endif diff --git a/src/glyph.c b/src/glyph.c index 08451f1..fa4abf1 100644 --- a/src/glyph.c +++ b/src/glyph.c @@ -42,7 +42,7 @@ struct { void glyph_init(void) { g_Glyph.m_pGlyphArray = g_ptr_array_new(); - g_ptr_array_add(g_Glyph.m_pGlyphArray, NULL); // index 0 is taken! + g_ptr_array_add(g_Glyph.m_pGlyphArray, NULL); // index 0 is taken! (it's the "no glyph" value) } gint glyph_load(const gchar* pszPath) @@ -85,17 +85,17 @@ static gboolean glyph_lookup(gint nGlyphHandle, glyph_t** ppReturnGlyph) void glyph_draw_centered(cairo_t* pCairo, gint nGlyphHandle, gdouble fX, gdouble fY) { + if(nGlyphHandle == 0) return; + glyph_t* pGlyph = NULL; if(!glyph_lookup(nGlyphHandle, &pGlyph)) { - // use a default glyph? - return; + g_assert_not_reached(); } cairo_save(pCairo); -// cairo_scale(pCairo, 2, 2); - cairo_set_alpha(pCairo, 0.5); - cairo_translate(pCairo, (fX - (pGlyph->m_nWidth/2)), (fY - (pGlyph->m_nHeight/2))); - svg_cairo_render(pGlyph->m_pCairoSVG, pCairo); + cairo_set_alpha(pCairo, 0.5); + cairo_translate(pCairo, (fX - (pGlyph->m_nWidth/2)), (fY - (pGlyph->m_nHeight/2))); + svg_cairo_render(pGlyph->m_pCairoSVG, pCairo); cairo_restore(pCairo); } diff --git a/src/gotowindow.c b/src/gotowindow.c index cd1c050..dd441d6 100644 --- a/src/gotowindow.c +++ b/src/gotowindow.c @@ -153,7 +153,7 @@ static gboolean gotowindow_go(void) // TODO: error checking for 0 (meaning either bad text "3a21" or "000" etc. - map_set_centerpoint(&pt); + mainwindow_set_centerpoint(&pt); mainwindow_draw_map(); mainwindow_statusbar_update_position(); return TRUE; diff --git a/src/import_tiger.c b/src/import_tiger.c index ca0a3e2..260d473 100644 --- a/src/import_tiger.c +++ b/src/import_tiger.c @@ -31,6 +31,7 @@ #include "util.h" #include "import_tiger.h" #include "importwindow.h" +#include "road.h" #define TIGER_RT1_LINE_LENGTH (230) #define TIGER_RT2_LINE_LENGTH (210) @@ -494,7 +495,7 @@ static gboolean import_tiger_parse_table_1(gchar* pBuffer, gint nLength, GHashTa gchar achType[5]; import_tiger_read_string(&pLine[50-1], 4, &achType[0]); // g_print("%30s is type %s\n", pRecord->m_achName, achType); - map_road_suffix_atoi(achType, &pRecord->m_nRoadNameSuffixID); + road_suffix_atoi(achType, &pRecord->m_nRoadNameSuffixID); if(achType[0] != '\0' && pRecord->m_nRoadNameSuffixID == ROAD_SUFFIX_NONE) { g_print("type '%s' couldn't be looked up\n", achType); diff --git a/src/layers.c b/src/layers.c index dc2a420..c5dddfa 100644 --- a/src/layers.c +++ b/src/layers.c @@ -43,8 +43,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,0,0,0,0}, /* font size */ {0,0,0,0,0,0,0,0,0,0}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 1 */ {LAYER_MINORSTREET, "Minor Roads", {{ @@ -53,11 +53,11 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5, 10.0, 16.0,32.0}, {255/255.0, 251/255.0, 255/255.0, 1.00}, 0, CAIRO_LINE_JOIN_MITER, CAIRO_LINE_CAP_ROUND} }}, - {{0,0,0,0,0,0,0,10,18,32}, /* font size */ + {{0,0,0,0,0,0,0,10,14,32}, /* font size */ {0,0,0,0,0,0,0,0,0,0}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 2 */ {LAYER_MAJORSTREET, "Major Roads", {{ @@ -68,8 +68,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,8,10,12,20,34}, /* font size */ {0,0,0,0,0,0,0,0,1,1}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 3 */ {LAYER_MINORHIGHWAY, "Minor Highways", {{ @@ -80,8 +80,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,6,12,16,18,26}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 4 */ {LAYER_MINORHIGHWAY_RAMP, "Minor Highway Ramps", {{ @@ -92,8 +92,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,0,0,0,0}, /* font size */ {0,0,0,0,0,0,0,0,0,0}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 5 */ {LAYER_MAJORHIGHWAY, "Major Highways", {{ @@ -104,8 +104,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,6,8,10,16,26}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 6 */ {LAYER_MAJORHIGHWAY_RAMP, "Major Highway Ramps", {{ @@ -116,8 +116,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,0,0,0,0}, /* font size */ {0,0,0,0,0,0,0,0,0,0}, /* bold */ {0,0,0,0,0,0,0,0,0,0}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 7 */ {LAYER_RAILROAD, "Railroads", {{ @@ -128,8 +128,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,10,10,10,10}, /* font size */ {0,0,0,0,0,0,0,0,0,0}, /* bold */ {0,0,0,0,0,0,4,4,4,4}, /* halo */ - {0,0,0,0}}, - NULL}, + {0,0,0,0}} + }, /* 8 */ {LAYER_PARK, "Parks", {{ @@ -140,8 +140,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,10,12,12,14}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,3,3,3,3}, /* halo */ - {0.1,0.1,0.1, 1.0}}, - NULL}, + {0.1,0.1,0.1, 1.0}} + }, /* 9 */{LAYER_RIVER, "Rivers", {{ @@ -152,8 +152,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,10,12,12,14}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,3,3,3,3}, /* halo */ - {128/255.0, 158/255.0, 180/255.0, 1.0}}, - NULL}, + {128/255.0, 158/255.0, 180/255.0, 1.0}} + }, /* 10 */{LAYER_LAKE, "Lakes", {{ @@ -164,8 +164,8 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,10,12,12,14}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,3,3,3,3}, /* halo */ - {0.1,0.1,0.1, 1.0}}, - NULL}, + {0.1,0.1,0.1, 1.0}} + }, /* 11 */{LAYER_MISC_AREA, "Misc Areas", {{ @@ -176,22 +176,6 @@ layer_t g_aLayers[NUM_LAYERS + 1] = { {{0,0,0,0,0,0,10,12,12,14}, /* font size */ {0,0,0,0,0,0,1,1,1,1}, /* bold */ {0,0,0,0,0,0,3,3,3,3}, /* halo */ - {0.25,0.25,0.25,1.0}}, - NULL}, + {0.25,0.25,0.25,1.0}} + }, }; - -void layers_init() -{ - gint i; - for(i=LAYER_FIRST ; i<=LAYER_LAST ; i++) { - geometryset_new(&(g_aLayers[i].m_pGeometrySet)); - } -} - -void layers_clear() -{ - gint i; - for(i=LAYER_FIRST ; i<=LAYER_LAST ; i++) { - geometryset_clear(g_aLayers[i].m_pGeometrySet); - } -} diff --git a/src/layers.h b/src/layers.h index 2cc06af..7c92013 100644 --- a/src/layers.h +++ b/src/layers.h @@ -21,11 +21,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _LAYERS_H -#define _LAYERS_H +#ifndef _LAYERS_H_ +#define _LAYERS_H_ #include <gtk/gtk.h> -#include "geometryset.h" #ifdef __cplusplus extern "C" @@ -34,23 +33,25 @@ extern "C" #define LAYER_NONE (0) -#define LAYER_MINORSTREET (1) -#define LAYER_MAJORSTREET (2) -#define LAYER_MINORHIGHWAY (3) -#define LAYER_MINORHIGHWAY_RAMP (4) -#define LAYER_MAJORHIGHWAY (5) // used? -#define LAYER_MAJORHIGHWAY_RAMP (6) // used? -#define LAYER_RAILROAD (7) +#define LAYER_MINORSTREET (1) +#define LAYER_MAJORSTREET (2) +#define LAYER_MINORHIGHWAY (3) +#define LAYER_MINORHIGHWAY_RAMP (4) +#define LAYER_MAJORHIGHWAY (5) // used? +#define LAYER_MAJORHIGHWAY_RAMP (6) // used? +#define LAYER_RAILROAD (7) #define LAYER_PARK (8) #define LAYER_RIVER (9) #define LAYER_LAKE (10) -#define LAYER_MISC_AREA (11) +#define LAYER_MISC_AREA (11) #define NUM_LAYERS (11) - + #define LAYER_FIRST (1) #define LAYER_LAST (11) +#include "map.h" + typedef struct color { gfloat m_fRed; gfloat m_fGreen; @@ -74,21 +75,12 @@ typedef struct sublayerstyle { gint m_nCapStyle; } sublayerstyle_t; - //~ gint m_nMinZoomLevel; - //~ gdouble m_fTopLineWidthPercent; - //~ gdouble m_afLineWidths[10]; - //~ color_t m_clrLowDetail; - //~ color_t m_clrFill; - //~ color_t m_clrOutline; - //~ gint m_nDashStyle; // index into dashes table - typedef struct textlabelstyle { gdouble m_afFontSizeAtZoomLevel[MAX_ZOOM_LEVEL]; gint m_abBoldAtZoomLevel[MAX_ZOOM_LEVEL]; // 0s or 1s gint m_afHaloAtZoomLevel[MAX_ZOOM_LEVEL]; // stroke width color_t m_clrColor; // font family... - // font style... } textlabelstyle_t; // defines the look of a layer @@ -100,17 +92,13 @@ typedef struct layer { gint nLayerIndex; gchar* m_pszName; layerstyle_t m_Style; - textlabelstyle_t m_TextLabelStyle; - geometryset_t* m_pGeometrySet; + textlabelstyle_t m_TextLabelStyle; } layer_t; extern layer_t g_aLayers[NUM_LAYERS+1]; -void layers_init(void); -void layers_clear(void); - #ifdef __cplusplus } #endif -#endif /* _LAYERS_H */ +#endif /* _LAYERS_H_ */ @@ -28,7 +28,6 @@ #include <gnome.h> #include "gui.h" #include "db.h" -#include "geometryset.h" #include "mainwindow.h" #include "map.h" #include "import.h" @@ -39,7 +38,7 @@ #include "pointstring.h" #include "track.h" -static int main_init(void); +static gboolean main_init(void); static void main_deinit(void); int main (int argc, char *argv[]) @@ -52,21 +51,23 @@ int main (int argc, char *argv[]) #endif gnome_init(PACKAGE, VERSION, argc, argv); - ret = main_init(); - - if (ret) - return ret; + if(!main_init()) { + return 1; + } gui_run(); main_deinit(); // usually doesn't get here return 0; } -int main_init(void) +gboolean main_init(void) { + // Initialize GLib thread system + // g_thread_init(NULL); + if(!gnome_vfs_init()) { g_warning("gnome_vfs_init failed\n"); - return 1; + return FALSE; } gchar* pszApplicationDir = g_strdup_printf("%s/.roadster", g_get_home_dir()); if(GNOME_VFS_OK != gnome_vfs_make_directory(pszApplicationDir, 0700)) { @@ -84,18 +85,19 @@ int main_init(void) track_init(); g_print("initializing glyphs\n"); glyph_init(); + g_print("initializing map\n"); + map_init(); g_print("initializing scenemanager\n"); scenemanager_init(); //geometryset_init(); + g_print("initializing locationsets\n"); locationset_init(); g_print("initializing gpsclient\n"); gpsclient_init(); g_print("initializing gui\n"); gui_init(); - g_print("initializing layers\n"); - layers_init(); g_print("initializing db\n"); db_init(); @@ -107,7 +109,7 @@ int main_init(void) g_print("initialization complete\n"); - return 0; + return TRUE; } static void main_deinit(void) diff --git a/src/mainwindow.c b/src/mainwindow.c index 28b071c..7928ece 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -59,9 +59,8 @@ #define LAYERLIST_COLUMN_NAME (1) // Limits -#define MAX_SEARCH_TEXT_LENGTH (100) - -#define SPEED_LABEL_FORMAT ("<span font_desc='32'>%.0f</span>") +#define MAX_SEARCH_TEXT_LENGTH (100) +#define SPEED_LABEL_FORMAT ("<span font_desc='32'>%.0f</span>") // Settings #define TIMER_GPS_REDRAW_INTERVAL_MS (2500) // lower this (to 1?) when it's faster to redraw track @@ -105,17 +104,16 @@ struct { GtkImage* m_pStatusbarGPSIcon; GtkWidget *m_pSidebox; - // Sidebar - + // "Draw" Sidebar GtkTreeView* m_pLayersListTreeView; GtkTreeView* m_pLocationSetsTreeView; - + // "GPS" sidebar GtkLabel* m_pSpeedLabel; GtkProgressBar* m_pGPSSignalStrengthProgressBar; - + // Statusbar GtkVBox* m_pStatusbar; GtkLabel* m_pPositionLabel; @@ -128,14 +126,16 @@ struct { // Drawing area // GtkWidget* m_pDrawWidget; GtkDrawingArea* m_pDrawingArea; - GdkPixmap* m_pOffscreenPixmap; - + + map_t* m_pMap; + EToolType m_eSelectedTool; gint m_nCurrentGPSPath; gint m_nGPSLocationGlyph; } g_MainWindow = {0}; + // Data toolsettings_t g_Tools[] = { {"Pointer Tool", {GDK_LEFT_PTR, NULL}}, @@ -220,6 +220,9 @@ void mainwindow_init(GladeXML* pGladeXML) // create drawing area g_MainWindow.m_pDrawingArea = GTK_DRAWING_AREA(gtk_drawing_area_new()); + g_print("creating map\n"); + map_new(&g_MainWindow.m_pMap, GTK_WIDGET(g_MainWindow.m_pDrawingArea)); + // add signal handlers to drawing area gtk_widget_add_events(GTK_WIDGET(g_MainWindow.m_pDrawingArea), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); g_signal_connect(G_OBJECT(g_MainWindow.m_pDrawingArea), "expose_event", G_CALLBACK(mainwindow_on_expose_event), NULL); @@ -292,18 +295,18 @@ void mainwindow_init(GladeXML* pGladeXML) mainwindow_load_locationset_list(); /* add some data to the layers list */ - GtkTreeIter iter; - - int i; - for(i=LAYER_FIRST ; i<=LAYER_LAST ; i++) { - gboolean bEnabled = TRUE; - - gtk_list_store_append(GTK_LIST_STORE(pLayersListStore), &iter); - gtk_list_store_set(GTK_LIST_STORE(pLayersListStore), &iter, - LAYERLIST_COLUMN_ENABLED, bEnabled, - LAYERLIST_COLUMN_NAME, g_aLayers[i].m_pszName, - -1); - } +// GtkTreeIter iter; +// +// int i; +// for(i=LAYER_FIRST ; i<=LAYER_LAST ; i++) { +// gboolean bEnabled = TRUE; +// +// gtk_list_store_append(GTK_LIST_STORE(pLayersListStore), &iter); +// gtk_list_store_set(GTK_LIST_STORE(pLayersListStore), &iter, +// LAYERLIST_COLUMN_ENABLED, bEnabled, +// LAYERLIST_COLUMN_NAME, g_aLayers[i].m_pszName, +// -1); +// } g_timeout_add(TIMER_GPS_REDRAW_INTERVAL_MS, (GSourceFunc)mainwindow_callback_on_gps_redraw_timeout, @@ -393,7 +396,7 @@ gboolean mainwindow_get_statusbar_visible(void) void mainwindow_statusbar_update_zoomscale(void) { char buf[200]; - guint32 uZoomLevelScale = map_get_zoomlevel_scale(); + guint32 uZoomLevelScale = map_get_zoomlevel_scale(g_MainWindow.m_pMap); snprintf(buf, 199, "1:%d", uZoomLevelScale); mainwindow_set_statusbar_zoomscale(buf); @@ -403,7 +406,7 @@ void mainwindow_statusbar_update_position(void) { char buf[200]; mappoint_t pt; - map_get_centerpoint(&pt); + map_get_centerpoint(g_MainWindow.m_pMap, &pt); g_snprintf(buf, 200, "Lat: %.5f, Lon: %.5f", pt.m_fLatitude, pt.m_fLongitude); mainwindow_set_statusbar_position(buf); } @@ -517,7 +520,7 @@ void on_zoomscale_value_changed(GtkRange *range, gpointer user_data) gint16 nValue = (gint16)fValue; gtk_range_set_value(range, (gdouble)nValue); - map_set_zoomlevel(nValue); + map_set_zoomlevel(g_MainWindow.m_pMap, nValue); mainwindow_statusbar_update_zoomscale(); mainwindow_draw_map(); @@ -528,16 +531,16 @@ void on_zoomscale_value_changed(GtkRange *range, gpointer user_data) // static void zoom_in_one(void) { - map_set_zoomlevel( map_get_zoomlevel() + 1); + map_set_zoomlevel(g_MainWindow.m_pMap, map_get_zoomlevel(g_MainWindow.m_pMap) + 1); - gtk_range_set_value(GTK_RANGE(g_MainWindow.m_pZoomScale), map_get_zoomlevel()); + gtk_range_set_value(GTK_RANGE(g_MainWindow.m_pZoomScale), map_get_zoomlevel(g_MainWindow.m_pMap)); } static void zoom_out_one(void) { - map_set_zoomlevel( map_get_zoomlevel() - 1 ); + map_set_zoomlevel(g_MainWindow.m_pMap, map_get_zoomlevel(g_MainWindow.m_pMap) - 1 ); - gtk_range_set_value(GTK_RANGE(g_MainWindow.m_pZoomScale), map_get_zoomlevel()); + gtk_range_set_value(GTK_RANGE(g_MainWindow.m_pZoomScale), map_get_zoomlevel(g_MainWindow.m_pMap)); } static void gui_set_tool(EToolType eTool) @@ -614,10 +617,10 @@ void mainwindow_on_gotomenuitem_activate(GtkMenuItem *menuitem, gpointer user_da gotowindow_show(); } -void on_gotobutton_clicked(GtkToolButton *toolbutton, gpointer user_data) -{ - gotowindow_show(); -} +// void on_gotobutton_clicked(GtkToolButton *toolbutton, gpointer user_data) +// { +// gotowindow_show(); +// } static gboolean mainwindow_on_mouse_button_click(GtkWidget* w, GdkEventButton *event) { @@ -626,14 +629,14 @@ static gboolean mainwindow_on_mouse_button_click(GtkWidget* w, GdkEventButton *e gdk_window_get_pointer(w->window, &nX, &nY, NULL); - // Left-click - if(event->button == 1 && event->type == GDK_BUTTON_PRESS) { + // Left double-click + if(event->button == 1 && event->type == GDK_2BUTTON_PRESS) { if(g_MainWindow.m_eSelectedTool == kToolZoom) { - map_center_on_windowpoint(nX, nY); + map_center_on_windowpoint(g_MainWindow.m_pMap, nX, nY); zoom_in_one(); } else if(g_MainWindow.m_eSelectedTool == kToolPointer) { - map_center_on_windowpoint(nX, nY); + map_center_on_windowpoint(g_MainWindow.m_pMap, nX, nY); } else { g_assert(FALSE); @@ -642,16 +645,16 @@ static gboolean mainwindow_on_mouse_button_click(GtkWidget* w, GdkEventButton *e mainwindow_statusbar_update_position(); } // Right-click? - else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) - { - // Save click location for use by callback - g_MainWindow.m_ptClickLocation.m_nX = nX; - g_MainWindow.m_ptClickLocation.m_nY = nY; - - // Show popup! - gtk_menu_popup(g_MainWindow.m_pMapPopupMenu, NULL, NULL, NULL, NULL, event->button, event->time); - return TRUE; - } +// else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) +// { +// // Save click location for use by callback +// g_MainWindow.m_ptClickLocation.m_nX = nX; +// g_MainWindow.m_ptClickLocation.m_nY = nY; +// +// // Show popup! +// gtk_menu_popup(g_MainWindow.m_pMapPopupMenu, NULL, NULL, NULL, NULL, event->button, event->time); +// return TRUE; +// } // map_redraw_if_needed(); return TRUE; } @@ -714,53 +717,27 @@ void on_toolbutton_clicked(GtkToolButton *toolbutton, gpointer user_data) void mainwindow_draw_map(void) { -// g_print("mainwindow_draw_map()\n"); - - void* pBusy = mainwindow_set_busy(); - - Display* dpy; - Drawable drawable; - - dpy = gdk_x11_drawable_get_xdisplay(g_MainWindow.m_pOffscreenPixmap); - drawable = gdk_x11_drawable_get_xid(g_MainWindow.m_pOffscreenPixmap); - - cairo_t *pCairoInstance; - pCairoInstance = cairo_create (); - // draw on an off-screen buffer - cairo_set_target_drawable(pCairoInstance, dpy, drawable); - map_draw(pCairoInstance); - - pointstring_t* pTrackPointString = track_get_pointstring(g_MainWindow.m_nCurrentGPSPath); - if(pTrackPointString) { - map_draw_gps_trail(pCairoInstance, pTrackPointString); - } - - // glyph_draw_centered(pCairoInstance, g_MainWindow.m_nGPSLocationGlyph, 200, 200); - cairo_destroy(pCairoInstance); - - gtk_widget_queue_draw(GTK_WIDGET(g_MainWindow.m_pDrawingArea)); - - mainwindow_set_not_busy(&pBusy); + map_draw_thread_begin(g_MainWindow.m_pMap, GTK_WIDGET(g_MainWindow.m_pDrawingArea)); } static gint mainwindow_on_configure_event(GtkWidget *pDrawingArea, GdkEventConfigure *event) { // Create a new backing pixmap of the appropriate size - if(g_MainWindow.m_pOffscreenPixmap != NULL) { - gdk_pixmap_unref(g_MainWindow.m_pOffscreenPixmap); - } - g_MainWindow.m_pOffscreenPixmap = gdk_pixmap_new( - GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, - GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.width, - GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.height, - -1); +// if(g_MainWindow.m_pOffscreenPixmap != NULL) { +// gdk_pixmap_unref(g_MainWindow.m_pOffscreenPixmap); +// } +// g_MainWindow.m_pOffscreenPixmap = gdk_pixmap_new( +// GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, +// GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.width, +// GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.height, +// -1); // tell the map how big to draw dimensions_t dim; dim.m_uWidth = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.width; dim.m_uHeight = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.height; - map_set_dimensions(&dim); + map_set_dimensions(g_MainWindow.m_pMap, &dim); mainwindow_draw_map(); return TRUE; @@ -769,23 +746,26 @@ static gint mainwindow_on_configure_event(GtkWidget *pDrawingArea, GdkEventConfi static gboolean mainwindow_on_expose_event(GtkWidget *pDrawingArea, GdkEventExpose *event, gpointer data) { // g_print("mainwindow_on_expose_event(x=%d,y=%d,w=%d,h=%d)\n", event->area.x, event->area.y, event->area.width, event->area.height); + GdkPixmap* pMapPixmap = map_get_pixmap(g_MainWindow.m_pMap); // Copy relevant portion of off-screen bitmap to window // TIMER_BEGIN(mytimer, "BEGIN EXPOSE"); gdk_draw_pixmap(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, GTK_WIDGET(g_MainWindow.m_pDrawingArea)->style->fg_gc[GTK_WIDGET_STATE(g_MainWindow.m_pDrawingArea)], - g_MainWindow.m_pOffscreenPixmap, + pMapPixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); // TIMER_END(mytimer, "END EXPOSE"); + + map_release_pixmap(g_MainWindow.m_pMap); return FALSE; } void mainwindow_on_addpointmenuitem_activate(GtkWidget *_unused, gpointer* __unused) { mappoint_t point; - map_windowpoint_to_mappoint(&g_MainWindow.m_ptClickLocation, &point); + map_windowpoint_to_mappoint(g_MainWindow.m_pMap, &g_MainWindow.m_ptClickLocation, &point); gint nLocationSetID = 1; gint nNewLocationID; @@ -804,7 +784,7 @@ static gboolean mainwindow_callback_on_gps_redraw_timeout(gpointer __unused) // NOTE: we're setting tooltips on the image's GtkWidget* pWidget = gtk_widget_get_parent(GTK_WIDGET(g_MainWindow.m_pStatusbarGPSIcon)); - gpsdata_t* pData = gpsclient_getdata(); + const gpsdata_t* pData = gpsclient_getdata(); if(pData->m_eStatus == GPS_STATUS_LIVE) { if(g_MainWindow.m_nCurrentGPSPath == 0) { @@ -871,7 +851,10 @@ static gboolean mainwindow_callback_on_gps_redraw_timeout(gpointer __unused) return TRUE; } - +void mainwindow_set_centerpoint(mappoint_t* pPoint) +{ + map_set_centerpoint(g_MainWindow.m_pMap, pPoint); +} #ifdef ROADSTER_DEAD_CODE diff --git a/src/mainwindow.h b/src/mainwindow.h index f917a54..94dd183 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -25,6 +25,7 @@ #define _MAINWINDOW_H #include <glade/glade.h> +#include "map.h" #ifdef __cplusplus extern "C" @@ -93,6 +94,8 @@ void mainwindow_on_gotomenuitem_activate(GtkMenuItem *menuitem, gpointer use void mainwindow_on_addpointmenuitem_activate(GtkWidget *_unused, gpointer* __unused); void mainwindow_on_datasetmenuitem_activate(GtkWidget *pWidget, gpointer* p); +void mainwindow_set_centerpoint(mappoint_t* pPoint); + #ifdef __cplusplus } #endif @@ -33,271 +33,54 @@ #include "gui.h" #include "map.h" -#include "geometryset.h" #include "mainwindow.h" #include "util.h" #include "db.h" +#include "road.h" +#include "point.h" #include "layers.h" #include "locationset.h" #include "scenemanager.h" -struct { - mappoint_t m_MapCenter; // XXX - dimensions_t m_MapDimensions; // XXX - guint16 m_uZoomLevel; // XXX - gboolean m_bRedrawNeeded; -} g_Map = -{ - {0.0,0.0}, // starting position - {0,0}, // map dimensions - 7, // starting zoomlevel - TRUE -}; - // ADD: // 'Mal' - ? // 'Trce - Trace -struct { - gchar* m_pszLong; - gchar* m_pszShort; -} g_RoadNameSuffix[] = { - {"",""}, - {"Road", "Rd"}, - {"Street", "St"}, - {"Drive", "Dr"}, - {"Boulevard", "Bvd"}, - {"Avenue", "Ave"}, - {"Circle", "Crl"}, - {"Square", "Sq"}, - {"Path", "Pth"}, - {"Way", "Wy"}, - {"Plaza", "Plz"}, - {"Trail", "Trl"}, - {"Lane", "Ln"}, - {"Crossing", "Xing"}, - {"Place", "Pl"}, - {"Court", "Ct"}, - {"Turnpike", "Tpke"}, - {"Terrace", "Ter"}, - {"Row", "Row"}, - {"Parkway", "Pky"}, - - {"Bridge", "Brg"}, - {"Highway", "Hwy"}, - {"Run", "Run"}, - {"Pass", "Pass"}, - - {"Freeway", "Fwy"}, - {"Alley", "Aly"}, - {"Crescent", "Cres"}, - {"Tunnel", "Tunl"}, - {"Walk", "Walk"}, - {"Terrace", "Trce"}, - {"Branch", "Br"}, - {"Cove", "Cv"}, - {"Bypass", "Byp"}, - {"Loop", "Loop"}, - {"Spur", "Spur"}, - {"Ramp", "Ramp"}, - {"Pike", "Pike"}, - {"Grade", "Grd"}, - {"Route", "Rte"}, - {"Arc", "Arc"}, -}; - -struct { - gchar* m_pszName; - gint m_nID; -} g_RoadNameSuffixLookup[] = { - {"Rd", ROAD_SUFFIX_ROAD}, - {"Road", ROAD_SUFFIX_ROAD}, - - {"St", ROAD_SUFFIX_STREET}, - {"Street", ROAD_SUFFIX_STREET}, - - {"Dr", ROAD_SUFFIX_DRIVE}, - {"Drive", ROAD_SUFFIX_DRIVE}, - - {"Blv", ROAD_SUFFIX_BOULEVARD}, - {"Blvd", ROAD_SUFFIX_BOULEVARD}, - {"Boulevard", ROAD_SUFFIX_BOULEVARD}, - - {"Av", ROAD_SUFFIX_AVENUE}, - {"Ave", ROAD_SUFFIX_AVENUE}, - {"Avenue", ROAD_SUFFIX_AVENUE}, - - {"Cir", ROAD_SUFFIX_CIRCLE}, - {"Crl", ROAD_SUFFIX_CIRCLE}, - {"Circle", ROAD_SUFFIX_CIRCLE}, - - {"Sq", ROAD_SUFFIX_SQUARE}, - {"Square", ROAD_SUFFIX_SQUARE}, - - {"Pl", ROAD_SUFFIX_PLACE}, - {"Place", ROAD_SUFFIX_PLACE}, - - {"Xing", ROAD_SUFFIX_CROSSING}, - {"Crossing", ROAD_SUFFIX_CROSSING}, - - {"Ct", ROAD_SUFFIX_COURT}, - {"Court", ROAD_SUFFIX_COURT}, - - {"Tpke", ROAD_SUFFIX_TURNPIKE}, - {"Turnpike", ROAD_SUFFIX_TURNPIKE}, - - {"Ter", ROAD_SUFFIX_TERRACE}, - {"Terrace", ROAD_SUFFIX_TERRACE}, - - {"Row", ROAD_SUFFIX_ROW}, - - {"Pth", ROAD_SUFFIX_PATH}, - {"Path", ROAD_SUFFIX_PATH}, - - {"Wy", ROAD_SUFFIX_WAY}, - {"Way", ROAD_SUFFIX_WAY}, - - {"Plz", ROAD_SUFFIX_PLAZA}, - {"Plaza", ROAD_SUFFIX_PLAZA}, - - {"Trl", ROAD_SUFFIX_TRAIL}, - {"Trail", ROAD_SUFFIX_TRAIL}, - - {"Ln", ROAD_SUFFIX_LANE}, - {"Lane", ROAD_SUFFIX_LANE}, - - {"Pky", ROAD_SUFFIX_PARKWAY}, - {"Parkway", ROAD_SUFFIX_PARKWAY}, - - {"Brg", ROAD_SUFFIX_BRIDGE}, - {"Bridge", ROAD_SUFFIX_BRIDGE}, - - {"Hwy", ROAD_SUFFIX_HIGHWAY}, - {"Highway", ROAD_SUFFIX_HIGHWAY}, - - {"Run", ROAD_SUFFIX_RUN}, - - {"Pass", ROAD_SUFFIX_PASS}, - - {"Freeway", ROAD_SUFFIX_FREEWAY}, - {"Fwy", ROAD_SUFFIX_FREEWAY}, - - {"Alley", ROAD_SUFFIX_ALLEY}, - {"Aly", ROAD_SUFFIX_ALLEY}, - - {"Crescent", ROAD_SUFFIX_CRESCENT}, - {"Cres", ROAD_SUFFIX_CRESCENT}, - - {"Tunnel", ROAD_SUFFIX_TUNNEL}, - {"Tunl", ROAD_SUFFIX_TUNNEL}, - - {"Walk", ROAD_SUFFIX_WALK}, - {"Walk", ROAD_SUFFIX_WALK}, - - {"Branch", ROAD_SUFFIX_BRANCE}, - {"Br", ROAD_SUFFIX_BRANCE}, - - {"Cove", ROAD_SUFFIX_COVE}, - {"Cv", ROAD_SUFFIX_COVE}, - - {"Bypass", ROAD_SUFFIX_BYPASS}, - {"Byp", ROAD_SUFFIX_BYPASS}, - - {"Loop", ROAD_SUFFIX_LOOP}, - - {"Spur", ROAD_SUFFIX_SPUR}, - - {"Ramp", ROAD_SUFFIX_RAMP}, - - {"Pike", ROAD_SUFFIX_PIKE}, - - {"Grade", ROAD_SUFFIX_GRADE}, - {"Grd", ROAD_SUFFIX_GRADE}, - - {"Route", ROAD_SUFFIX_ROUTE}, - {"Rte", ROAD_SUFFIX_ROUTE}, - - {"Arc", ROAD_SUFFIX_ARC}, - -}; - #define SCALE_X(p, x) ((((x) - (p)->m_rWorldBoundingBox.m_A.m_fLongitude) / (p)->m_fScreenLongitude) * (p)->m_nWindowWidth) #define SCALE_Y(p, y) ((p)->m_nWindowHeight - ((((y) - (p)->m_rWorldBoundingBox.m_A.m_fLatitude) / (p)->m_fScreenLatitude) * (p)->m_nWindowHeight)) -typedef enum { - kSublayerBottom, - kSublayerTop, -} ESubLayer; - -#define MIN_LINE_LENGTH_FOR_LABEL (40) -#define LABEL_PIXELS_ABOVE_LINE (2) -#define LABEL_PIXEL_RELIEF_INSIDE_LINE (2) // when drawing a label inside a line, only do so if we would have at least this much blank space above+below the text - -//void map_draw_layer_railroad(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, sublayerstyle_t* pSubLayerStyle); - -// For road names: Bitstream Vera Sans Mono ? - -#define INCHES_PER_METER (39.37007) - -#define MIN_ZOOMLEVEL (1) -#define MAX_ZOOMLEVEL (10) -#define NUM_ZOOMLEVELS (10) - -#define WORLD_CIRCUMFERENCE_IN_METERS (40076000) -#define WORLD_METERS_PER_DEGREE (WORLD_CIRCUMFERENCE_IN_METERS / 360.0) -#define WORLD_METERS_TO_DEGREES(x) ((x) / WORLD_METERS_PER_DEGREE) -#define WORLD_DEGREES_TO_METERS(x) ((x) * WORLD_METERS_PER_DEGREE) -#define KILOMETERS_PER_METER (1000) -#define WORLD_KILOMETERS_TO_DEGREES(x) ((x * KILOMETERS_PER_METER) / WORLD_METERS_PER_DEGREE) - -#define WORLD_CIRCUMFERENCE_IN_FEET (131482939.8324) -#define WORLD_FEET_PER_DEGREE (WORLD_CIRCUMFERENCE_IN_FEET / 360.0) -#define WORLD_FEET_TO_DEGREES(X) ((X) / WORLD_FEET_PER_DEGREE) -#define FEET_PER_MILE (5280) -#define WORLD_MILES_TO_DEGREES(x) ((x * FEET_PER_MILE) / WORLD_FEET_PER_DEGREE) - -// Earth is slightly egg shaped so there are infinite radius measurements: - -// at poles: ? -// average: 6,371,010 -// at equator: 6,378,136 meters - -#define RADIUS_OF_WORLD_IN_METERS (6371010) - -#define DEG2RAD(x) ((x) * (M_PI / 180.0)) -#define RAD2DEG(x) ((x) * (180.0 / M_PI)) - - /* Prototypes */ -static void map_draw_layer_polygons(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); -static void map_draw_layer_lines(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); -static void map_draw_layer_line_labels(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); -static void map_draw_layer_polygon_labels(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); -static void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, const gchar* pszLabel); -static void map_draw_layer_points(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray); -static void map_draw_crosshair(cairo_t* pCairo, rendermetrics_t* pRenderMetrics); +static void map_draw_layer_polygons(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); +static void map_draw_layer_lines(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); +static void map_draw_layer_line_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); +static void map_draw_layer_polygon_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle); +static void map_draw_polygon_label(map_t* pMap, cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, const gchar* pszLabel); +static void map_draw_layer_points(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray); +static void map_draw_crosshair(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics); +static gboolean map_data_load(map_t* pMap, maprect_t* pRect); +static void map_data_clear(map_t* pMap); // Each zoomlevel has a scale and an optional name (name isn't used for anything) zoomlevel_t g_sZoomLevels[NUM_ZOOMLEVELS+1] = { - {1,"undefined"}, // no zoom level 0 - - { 1600000, ""}, // 1 - { 800000, ""}, // 2 - { 400000, ""}, // 3 - { 200000, ""}, // 4 - { 100000, ""}, // 5 - { 50000, ""}, // 6 - { 25000, ""}, // 7 - { 10000, ""}, // 8 - { 4000, ""}, // 9 - { 1800, ""}, //10 + {1,"undefined"}, // no zoom level 0 + + { 1600000, ""}, // 1 + { 800000, ""}, // 2 + { 400000, ""}, // 3 + { 200000, ""}, // 4 + { 100000, ""}, // 5 + { 50000, ""}, // 6 + { 25000, ""}, // 7 + { 10000, ""}, // 8 + { 4000, ""}, // 9 + { 1800, ""}, // 10 }; struct { gint nLayer; gint nSubLayer; - void (*pFunc)(cairo_t*, rendermetrics_t*, geometryset_t*, sublayerstyle_t*, textlabelstyle_t*); + void (*pFunc)(map_t*, cairo_t*, rendermetrics_t*, GPtrArray*, sublayerstyle_t*, textlabelstyle_t*); } layerdraworder[] = { {LAYER_MISC_AREA, 0, map_draw_layer_polygons}, @@ -337,28 +120,151 @@ struct { }; // ======================================================== +// Init +// ======================================================== + +// init the module +void map_init(void) +{ +} + + +gboolean map_new(map_t** ppMap, GtkWidget* pTargetWidget) +{ + g_assert(ppMap != NULL); + g_assert(*ppMap == NULL); // must be a pointer to null pointer + + // create a new map struct + map_t* pMap = g_new0(map_t, 1); + + pMap->m_pDataMutex = g_mutex_new(); + pMap->m_pPixmapMutex = g_mutex_new(); + + pMap->m_pTargetWidget = pTargetWidget; + + scenemanager_new(&(pMap->m_pSceneManager)); + g_assert(pMap->m_pSceneManager); + + pMap->m_uZoomLevel = 7; + + // init containers for geometry data + gint i; + for(i=0 ; i<NUM_ELEMS(pMap->m_apLayerData) ; i++) { + maplayer_data_t* pLayer = g_new0(maplayer_data_t, 1); + pLayer->m_pPointStringsArray = g_ptr_array_new(); + pMap->m_apLayerData[i] = pLayer; + } + + // save it + *ppMap = pMap; + return TRUE; +} + +// pointstring_t* pTrackPointString = track_get_pointstring(g_MainWindow.m_nCurrentGPSPath); +// if(pTrackPointString) { +// map_draw_gps_trail(pCairoInstance, pTrackPointString); +// } + +gpointer map_draw_thread(gpointer); + +void map_draw_thread_begin(map_t* pMap, GtkWidget* pTargetWidget) +{ +// g_thread_create(map_draw_thread, pMap, FALSE, NULL); + map_draw_thread(pMap); +} + +gpointer map_draw_thread(gpointer pData) +{ +//g_print("THREAD: begin\n"); + map_t* pMap = (map_t*)pData; + g_assert(pMap != NULL); + + db_lock(); + g_mutex_lock(pMap->m_pDataMutex); + + // create pixel buffer of appropriate size + GdkPixmap* pPixmapTemp = gdk_pixmap_new(pMap->m_pTargetWidget->window, pMap->m_MapDimensions.m_uWidth, pMap->m_MapDimensions.m_uHeight, -1); + g_assert(pPixmapTemp); + + Display* dpy; + Drawable drawable; + dpy = gdk_x11_drawable_get_xdisplay(pPixmapTemp); + drawable = gdk_x11_drawable_get_xid(pPixmapTemp); + + cairo_t* pCairo = cairo_create (); +//g_print("THREAD: cairo created\n"); + + // draw on the off-screen buffer + cairo_set_target_drawable(pCairo, dpy, drawable); +//g_print("THREAD: drawing...\n"); + map_draw(pMap, pCairo); +//g_print("THREAD: destroying cairo...\n"); + cairo_destroy(pCairo); + + // Copy final image to (pMap->m_pPixmap) +//g_print("THREAD: copying pixmap\n"); + g_mutex_lock(pMap->m_pPixmapMutex); + + gdk_draw_pixmap(pMap->m_pPixmap, + pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], + pPixmapTemp, + 0, 0, + 0, 0, + pMap->m_MapDimensions.m_uWidth, pMap->m_MapDimensions.m_uWidth); + + gdk_pixmap_unref(pPixmapTemp); + + g_mutex_unlock(pMap->m_pDataMutex); + g_mutex_unlock(pMap->m_pPixmapMutex); + db_unlock(); + +//g_print("THREAD: done drawing\n"); + + gtk_widget_queue_draw(pMap->m_pTargetWidget); +} + +// ======================================================== +// Get and release the map image +// ======================================================== + +GdkPixmap* map_get_pixmap(map_t* pMap) +{ + g_mutex_lock(pMap->m_pPixmapMutex); + return pMap->m_pPixmap; +} + +void map_release_pixmap(map_t* pMap) +{ + g_mutex_unlock(pMap->m_pPixmapMutex); +} + + +// ======================================================== // Get/Set Functions // ======================================================== -void map_set_zoomlevel(guint16 uZoomLevel) +void map_set_zoomlevel(map_t* pMap, guint16 uZoomLevel) { + g_mutex_lock(pMap->m_pDataMutex); + if(uZoomLevel > MAX_ZOOMLEVEL) uZoomLevel = MAX_ZOOMLEVEL; else if(uZoomLevel < MIN_ZOOMLEVEL) uZoomLevel = MIN_ZOOMLEVEL; - if(uZoomLevel != g_Map.m_uZoomLevel) { - g_Map.m_uZoomLevel = uZoomLevel; - map_set_redraw_needed(TRUE); + if(uZoomLevel != pMap->m_uZoomLevel) { + pMap->m_uZoomLevel = uZoomLevel; +// map_set_redraw_needed(TRUE); } + g_mutex_unlock(pMap->m_pDataMutex); } -guint16 map_get_zoomlevel() +guint16 map_get_zoomlevel(map_t* pMap) { - return g_Map.m_uZoomLevel; // between MIN_ZOOMLEVEL and MAX_ZOOMLEVEL + return pMap->m_uZoomLevel; // between MIN_ZOOMLEVEL and MAX_ZOOMLEVEL } -guint32 map_get_zoomlevel_scale() +guint32 map_get_zoomlevel_scale(map_t* pMap) { - return g_sZoomLevels[g_Map.m_uZoomLevel].m_uScale; // returns "5000" for 1:5000 scale + return g_sZoomLevels[pMap->m_uZoomLevel].m_uScale; // returns "5000" for 1:5000 scale } // ======================================================== @@ -372,7 +278,7 @@ gchar* g_aDistanceUnitNames[] = { "Kilometers", }; -gdouble map_distance_in_units_to_degrees(gdouble fDistance, gint nDistanceUnit) +gdouble map_distance_in_units_to_degrees(map_t* pMap, gdouble fDistance, gint nDistanceUnit) { switch(nDistanceUnit) { case UNIT_FEET: @@ -390,7 +296,7 @@ gdouble map_distance_in_units_to_degrees(gdouble fDistance, gint nDistanceUnit) } // convert pixels to a span of degrees -static double map_pixels_to_degrees(gint16 nPixels, guint16 uZoomLevel) +static double map_pixels_to_degrees(map_t* pMap, gint16 nPixels, guint16 uZoomLevel) { double fMonitorPixelsPerInch = 85 + 1/3; double fPixelsPerMeter = fMonitorPixelsPerInch * INCHES_PER_METER; @@ -403,7 +309,7 @@ static double map_pixels_to_degrees(gint16 nPixels, guint16 uZoomLevel) return WORLD_METERS_TO_DEGREES(fMetersOfWorld); } -static double map_degrees_to_pixels(gdouble fDegrees, guint16 uZoomLevel) +static double map_degrees_to_pixels(map_t* pMap, gdouble fDegrees, guint16 uZoomLevel) { double fMonitorPixelsPerInch = 85 + 1/3; @@ -413,144 +319,113 @@ static double map_degrees_to_pixels(gdouble fDegrees, guint16 uZoomLevel) return fResultInPixels; } -void map_windowpoint_to_mappoint(screenpoint_t* pScreenPoint, mappoint_t* pMapPoint) +void map_windowpoint_to_mappoint(map_t* pMap, screenpoint_t* pScreenPoint, mappoint_t* pMapPoint) { // Calculate the # of pixels away from the center point the click was - gint16 nPixelDeltaX = (gint)(pScreenPoint->m_nX) - (g_Map.m_MapDimensions.m_uWidth / 2); - gint16 nPixelDeltaY = (gint)(pScreenPoint->m_nY) - (g_Map.m_MapDimensions.m_uHeight / 2); + gint16 nPixelDeltaX = (gint)(pScreenPoint->m_nX) - (pMap->m_MapDimensions.m_uWidth / 2); + gint16 nPixelDeltaY = (gint)(pScreenPoint->m_nY) - (pMap->m_MapDimensions.m_uHeight / 2); // Convert pixels to world coordinates - pMapPoint->m_fLongitude = g_Map.m_MapCenter.m_fLongitude + map_pixels_to_degrees(nPixelDeltaX, g_Map.m_uZoomLevel); + pMapPoint->m_fLongitude = pMap->m_MapCenter.m_fLongitude + map_pixels_to_degrees(pMap, nPixelDeltaX, pMap->m_uZoomLevel); // reverse the X, clicking above - pMapPoint->m_fLatitude = g_Map.m_MapCenter.m_fLatitude - map_pixels_to_degrees(nPixelDeltaY, g_Map.m_uZoomLevel); + pMapPoint->m_fLatitude = pMap->m_MapCenter.m_fLatitude - map_pixels_to_degrees(pMap, nPixelDeltaY, pMap->m_uZoomLevel); } // Call this to pan around the map -void map_center_on_windowpoint(guint16 uX, guint16 uY) +void map_center_on_windowpoint(map_t* pMap, guint16 uX, guint16 uY) { // Calculate the # of pixels away from the center point the click was - gint16 nPixelDeltaX = uX - (g_Map.m_MapDimensions.m_uWidth / 2); - gint16 nPixelDeltaY = uY - (g_Map.m_MapDimensions.m_uHeight / 2); + gint16 nPixelDeltaX = uX - (pMap->m_MapDimensions.m_uWidth / 2); + gint16 nPixelDeltaY = uY - (pMap->m_MapDimensions.m_uHeight / 2); // Convert pixels to world coordinates - double fWorldDeltaX = map_pixels_to_degrees(nPixelDeltaX, g_Map.m_uZoomLevel); + double fWorldDeltaX = map_pixels_to_degrees(pMap, nPixelDeltaX, pMap->m_uZoomLevel); // reverse the X, clicking above - double fWorldDeltaY = -map_pixels_to_degrees(nPixelDeltaY, g_Map.m_uZoomLevel); + double fWorldDeltaY = -map_pixels_to_degrees(pMap, nPixelDeltaY, pMap->m_uZoomLevel); // g_message("panning %d,%d pixels (%.10f,%.10f world coords)\n", nPixelDeltaX, nPixelDeltaY, fWorldDeltaX, fWorldDeltaY); mappoint_t pt; - pt.m_fLatitude = g_Map.m_MapCenter.m_fLatitude + fWorldDeltaY; - pt.m_fLongitude = g_Map.m_MapCenter.m_fLongitude + fWorldDeltaX; - map_set_centerpoint(&pt); + pt.m_fLatitude = pMap->m_MapCenter.m_fLatitude + fWorldDeltaY; + pt.m_fLongitude = pMap->m_MapCenter.m_fLongitude + fWorldDeltaX; + map_set_centerpoint(pMap, &pt); } -void map_set_centerpoint(const mappoint_t* pPoint) +void map_set_centerpoint(map_t* pMap, const mappoint_t* pPoint) { g_assert(pPoint != NULL); - g_Map.m_MapCenter.m_fLatitude = pPoint->m_fLatitude; - g_Map.m_MapCenter.m_fLongitude = pPoint->m_fLongitude; + pMap->m_MapCenter.m_fLatitude = pPoint->m_fLatitude; + pMap->m_MapCenter.m_fLongitude = pPoint->m_fLongitude; - map_set_redraw_needed(TRUE); +// map_set_redraw_needed(TRUE); } -void map_get_centerpoint(mappoint_t* pReturnPoint) +void map_get_centerpoint(map_t* pMap, mappoint_t* pReturnPoint) { g_assert(pReturnPoint != NULL); - pReturnPoint->m_fLatitude = g_Map.m_MapCenter.m_fLatitude; - pReturnPoint->m_fLongitude = g_Map.m_MapCenter.m_fLongitude; + pReturnPoint->m_fLatitude = pMap->m_MapCenter.m_fLatitude; + pReturnPoint->m_fLongitude = pMap->m_MapCenter.m_fLongitude; } // -void map_set_dimensions(const dimensions_t* pDimensions) +void map_set_dimensions(map_t* pMap, const dimensions_t* pDimensions) { g_assert(pDimensions != NULL); - g_Map.m_MapDimensions.m_uWidth = pDimensions->m_uWidth; - g_Map.m_MapDimensions.m_uHeight = pDimensions->m_uHeight; -} + g_mutex_lock(pMap->m_pDataMutex); + g_mutex_lock(pMap->m_pPixmapMutex); -#if ROADSTER_DEAD_CODE -static double map_get_distance_in_meters(mappoint_t* pA, mappoint_t* pB) -{ - g_assert_not_reached(); // unused/tested + pMap->m_MapDimensions.m_uWidth = pDimensions->m_uWidth; + pMap->m_MapDimensions.m_uHeight = pDimensions->m_uHeight; - // This functions calculates the length of the arc of the "greatcircle" that goes through - // the two points A and B and whos center is the center of the sphere, O. - - // When we multiply this angle (in radians) by the radius, we get the length of the arc. - - // NOTE: This algorithm wrongly assumes that Earth is a perfect sphere. - // It is actually slightly egg shaped. But it's good enough. - - // All trig functions expect arguments in radians. - double fLonA_Rad = DEG2RAD(pA->m_fLongitude); - double fLonB_Rad = DEG2RAD(pB->m_fLongitude); - double fLatA_Rad = DEG2RAD(pA->m_fLatitude); - double fLatB_Rad = DEG2RAD(pB->m_fLatitude); - - // Step 1. Calculate AOB (in radians). - // An explanation of this equation is at http://mathforum.org/library/drmath/view/51722.html - double fAOB_Rad = acos((cos(fLatA_Rad) * cos(fLatB_Rad) * cos(fLonB_Rad - fLonA_Rad)) + (sin(fLatA_Rad) * sin(fLatB_Rad))); - - // Step 2. Multiply the angle by the radius of the sphere to get arc length. - return fAOB_Rad * RADIUS_OF_WORLD_IN_METERS; -} -#endif /* ROADSTER_DEAD_CODE */ - -// ======================================================== -// Redraw -// ======================================================== - -void map_set_redraw_needed(gboolean bNeeded) -{ - g_Map.m_bRedrawNeeded = bNeeded; -} - -gboolean map_get_redraw_needed() -{ - return g_Map.m_bRedrawNeeded; + pMap->m_pPixmap = gdk_pixmap_new( + pMap->m_pTargetWidget->window, + pMap->m_MapDimensions.m_uWidth, pMap->m_MapDimensions.m_uHeight, + -1); + + g_mutex_unlock(pMap->m_pPixmapMutex); + g_mutex_unlock(pMap->m_pDataMutex); } // ======================================================== // Draw Functions // ======================================================== -void map_get_render_metrics(rendermetrics_t* pMetrics) +void map_get_render_metrics(map_t* pMap, rendermetrics_t* pMetrics) { g_assert(pMetrics != NULL); // // Set up renderMetrics array // - pMetrics->m_nZoomLevel = map_get_zoomlevel(); - pMetrics->m_nWindowWidth = g_Map.m_MapDimensions.m_uWidth; - pMetrics->m_nWindowHeight = g_Map.m_MapDimensions.m_uHeight; + pMetrics->m_nZoomLevel = map_get_zoomlevel(pMap); + pMetrics->m_nWindowWidth = pMap->m_MapDimensions.m_uWidth; + pMetrics->m_nWindowHeight = pMap->m_MapDimensions.m_uHeight; // Calculate how many world degrees we'll be drawing - pMetrics->m_fScreenLatitude = map_pixels_to_degrees(g_Map.m_MapDimensions.m_uHeight, pMetrics->m_nZoomLevel); - pMetrics->m_fScreenLongitude = map_pixels_to_degrees(g_Map.m_MapDimensions.m_uWidth, pMetrics->m_nZoomLevel); + pMetrics->m_fScreenLatitude = map_pixels_to_degrees(pMap, pMap->m_MapDimensions.m_uHeight, pMetrics->m_nZoomLevel); + pMetrics->m_fScreenLongitude = map_pixels_to_degrees(pMap, pMap->m_MapDimensions.m_uWidth, pMetrics->m_nZoomLevel); // The world bounding box (expressed in lat/lon) of the data we will be drawing - pMetrics->m_rWorldBoundingBox.m_A.m_fLongitude = g_Map.m_MapCenter.m_fLongitude - pMetrics->m_fScreenLongitude/2; - pMetrics->m_rWorldBoundingBox.m_A.m_fLatitude = g_Map.m_MapCenter.m_fLatitude - pMetrics->m_fScreenLatitude/2; - pMetrics->m_rWorldBoundingBox.m_B.m_fLongitude = g_Map.m_MapCenter.m_fLongitude + pMetrics->m_fScreenLongitude/2; - pMetrics->m_rWorldBoundingBox.m_B.m_fLatitude = g_Map.m_MapCenter.m_fLatitude + pMetrics->m_fScreenLatitude/2; + pMetrics->m_rWorldBoundingBox.m_A.m_fLongitude = pMap->m_MapCenter.m_fLongitude - pMetrics->m_fScreenLongitude/2; + pMetrics->m_rWorldBoundingBox.m_A.m_fLatitude = pMap->m_MapCenter.m_fLatitude - pMetrics->m_fScreenLatitude/2; + pMetrics->m_rWorldBoundingBox.m_B.m_fLongitude = pMap->m_MapCenter.m_fLongitude + pMetrics->m_fScreenLongitude/2; + pMetrics->m_rWorldBoundingBox.m_B.m_fLatitude = pMap->m_MapCenter.m_fLatitude + pMetrics->m_fScreenLatitude/2; } -static void map_draw_background(cairo_t *pCairo) +static void map_draw_background(map_t* pMap, cairo_t *pCairo) { cairo_save(pCairo); cairo_set_rgb_color(pCairo, 247/255.0, 235/255.0, 230/255.0); - cairo_rectangle(pCairo, 0, 0, g_Map.m_MapDimensions.m_uWidth, g_Map.m_MapDimensions.m_uHeight); + cairo_rectangle(pCairo, 0, 0, pMap->m_MapDimensions.m_uWidth, pMap->m_MapDimensions.m_uHeight); cairo_fill(pCairo); cairo_restore(pCairo); } // EXPERIMENTAL TEXT RENDERING -static void map_draw_line_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, gdouble fLineWidth, const gchar* pszLabel) +static void map_draw_line_label(map_t* pMap, cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, gdouble fLineWidth, const gchar* pszLabel) { if(pPointString->m_pPointsArray->len < 2) return; @@ -560,7 +435,7 @@ static void map_draw_line_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, gfloat fFontSize = pLabelStyle->m_afFontSizeAtZoomLevel[pRenderMetrics->m_nZoomLevel-1]; if(fFontSize == 0) return; - if(!scenemanager_can_draw_label(pszLabel)) { + if(!scenemanager_can_draw_label(pMap->m_pSceneManager, pszLabel)) { //g_print("dup label: %s\n", pszLabel); return; } @@ -795,10 +670,10 @@ static void map_draw_line_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, } cairo_restore(pCairo); - scenemanager_label_drawn(pszLabel); + scenemanager_label_drawn(pMap->m_pSceneManager, pszLabel); } -void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, const gchar* pszLabel) +void map_draw_polygon_label(map_t* pMap, cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rendermetrics_t* pRenderMetrics, pointstring_t* pPointString, const gchar* pszLabel) { if(pPointString->m_pPointsArray->len < 3) return; @@ -808,7 +683,7 @@ void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rend gdouble fAlpha = pLabelStyle->m_clrColor.m_fAlpha; if(fAlpha == 0.0) return; - if(!scenemanager_can_draw_label(pszLabel)) { + if(!scenemanager_can_draw_label(pMap->m_pSceneManager, pszLabel)) { //g_print("dup label: %s\n", pszLabel); return; } @@ -816,7 +691,6 @@ void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rend gdouble fTotalX = 0.0; gdouble fTotalY = 0.0; - gdouble fMaxX = -G_MAXDOUBLE; // init to the worst possible value so first point will override gdouble fMaxY = -G_MAXDOUBLE; gdouble fMinX = G_MAXDOUBLE; @@ -858,7 +732,7 @@ void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rend CAIRO_FONT_SLANT_NORMAL, pLabelStyle->m_abBoldAtZoomLevel[pRenderMetrics->m_nZoomLevel-1] ? CAIRO_FONT_WEIGHT_BOLD : CAIRO_FONT_WEIGHT_NORMAL); cairo_scale_font(pCairo, fFontSize); - + // Get total width of string cairo_text_extents_t extents; cairo_text_extents(pCairo, pszLabel, &extents); @@ -891,23 +765,23 @@ void map_draw_polygon_label(cairo_t *pCairo, textlabelstyle_t* pLabelStyle, rend } cairo_fill(pCairo); cairo_restore(pCairo); - - scenemanager_label_drawn(pszLabel); + + scenemanager_label_drawn(pMap->m_pSceneManager, pszLabel); } -void map_draw(cairo_t *pCairo) +void map_draw(map_t* pMap, cairo_t *pCairo) { rendermetrics_t renderMetrics = {0}; - map_get_render_metrics(&renderMetrics); + map_get_render_metrics(pMap, &renderMetrics); rendermetrics_t* pRenderMetrics = &renderMetrics; - scenemanager_clear(); + scenemanager_clear(pMap->m_pSceneManager); // // Load geometry // TIMER_BEGIN(loadtimer, "--- BEGIN ALL DB LOAD"); - geometryset_load_geometry(&(pRenderMetrics->m_rWorldBoundingBox)); + map_data_load(pMap, &(pRenderMetrics->m_rWorldBoundingBox)); locationset_load_locations(&(pRenderMetrics->m_rWorldBoundingBox)); TIMER_END(loadtimer, "--- END ALL DB LOAD"); @@ -918,22 +792,24 @@ void map_draw(cairo_t *pCairo) // TIMER_BEGIN(maptimer, "BEGIN RENDER MAP"); cairo_save(pCairo); - map_draw_background(pCairo); + map_draw_background(pMap, pCairo); cairo_set_fill_rule(pCairo, CAIRO_FILL_RULE_WINDING); cairo_scale_font(pCairo, 18.00); // Render Layers - gint iLayerDraw; - for(iLayerDraw=0 ; iLayerDraw<NUM_ELEMS(layerdraworder) ; iLayerDraw++) { + gint i; + for(i=0 ; i<NUM_ELEMS(layerdraworder) ; i++) { //g_print("drawing %d\n", layerdraworder[iLayerDraw].nLayer); - layerdraworder[iLayerDraw].pFunc( - pCairo, - pRenderMetrics, - /* geometry */ g_aLayers[layerdraworder[iLayerDraw].nLayer].m_pGeometrySet, - /* style */ &g_aLayers[layerdraworder[iLayerDraw].nLayer].m_Style.m_aSubLayers[layerdraworder[iLayerDraw].nSubLayer], - &g_aLayers[layerdraworder[iLayerDraw].nLayer].m_TextLabelStyle - ); + gint nLayer = layerdraworder[i].nLayer; + gint nSubLayer = layerdraworder[i].nSubLayer; + + layerdraworder[i].pFunc(pMap, pCairo, + pRenderMetrics, + /* geometry */ pMap->m_apLayerData[nLayer]->m_pPointStringsArray, + /* style */ &g_aLayers[nLayer].m_Style.m_aSubLayers[nSubLayer], + &g_aLayers[nLayer].m_TextLabelStyle + ); } TIMER_END(maptimer, "END RENDER MAP"); @@ -942,23 +818,23 @@ void map_draw(cairo_t *pCairo) gint iLocationSet; for(iLocationSet=0 ; iLocationSet<pLocationSets->len ; iLocationSet++) { locationset_t* pLocationSet = g_ptr_array_index(pLocationSets, iLocationSet); - map_draw_layer_points(pCairo, pRenderMetrics, pLocationSet->m_pLocationsArray); + map_draw_layer_points(pMap, pCairo, pRenderMetrics, pLocationSet->m_pLocationsArray); } TIMER_END(loctimer, "END RENDER LOCATIONS"); - map_draw_crosshair(pCairo, pRenderMetrics); + map_draw_crosshair(pMap, pCairo, pRenderMetrics); cairo_restore(pCairo); // We don't need another redraw until something changes - map_set_redraw_needed(FALSE); +// map_set_redraw_needed(FALSE); } #define CROSSHAIR_LINE_RELIEF (6) #define CROSSHAIR_LINE_LENGTH (12) #define CROSSHAIR_CIRCLE_RADIUS (12) -static void map_draw_crosshair(cairo_t* pCairo, rendermetrics_t* pRenderMetrics) +static void map_draw_crosshair(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics) { cairo_save(pCairo); cairo_set_line_width(pCairo, 1.0); @@ -984,9 +860,9 @@ static void map_draw_crosshair(cairo_t* pCairo, rendermetrics_t* pRenderMetrics) cairo_restore(pCairo); } -void map_draw_layer_points(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray) +void map_draw_layer_points(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray) { - gfloat fRadius = map_degrees_to_pixels(0.0007, map_get_zoomlevel()); + gfloat fRadius = map_degrees_to_pixels(pMap, 0.0007, map_get_zoomlevel(pMap)); gboolean bAddition = FALSE; cairo_save(pCairo); @@ -1026,7 +902,7 @@ void map_draw_layer_points(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPt cairo_restore(pCairo); } -void map_draw_layer_polygons(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) +void map_draw_layer_polygons(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) { mappoint_t* pPoint; pointstring_t* pPointString; @@ -1046,8 +922,8 @@ void map_draw_layer_polygons(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, g // cairo_set_dash(pCairo, g_aDashStyles[pSubLayerStyle->m_nDashStyle].m_pfList, g_aDashStyles[pSubLayerStyle->m_nDashStyle].m_nCount, 0.0); gint iString; - for(iString=0 ; iString<pGeometry->m_pPointStringsArray->len ; iString++) { - pPointString = g_ptr_array_index(pGeometry->m_pPointStringsArray, iString); + for(iString=0 ; iString<pPointStringsArray->len ; iString++) { + pPointString = g_ptr_array_index(pPointStringsArray, iString); if(pPointString->m_pPointsArray->len >= 3) { pPoint = g_ptr_array_index(pPointString->m_pPointsArray, 0); @@ -1097,7 +973,7 @@ void map_draw_layer_polygons(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, g cairo_fill(pCairo); } -void map_draw_layer_lines(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) +void map_draw_layer_lines(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) { mappoint_t* pPoint; pointstring_t* pPointString; @@ -1115,7 +991,7 @@ void map_draw_layer_lines(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geom gdouble fTolerance; if(fLineWidth >= 6.0) { - fTolerance = 0.5; + fTolerance = 0.6; } else { if(nCapStyle == CAIRO_LINE_CAP_ROUND) { @@ -1142,8 +1018,8 @@ void map_draw_layer_lines(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geom cairo_set_alpha(pCairo, pSubLayerStyle->m_clrColor.m_fAlpha); cairo_set_line_width(pCairo, fLineWidth); - for(iString=0 ; iString<pGeometry->m_pPointStringsArray->len ; iString++) { - pPointString = g_ptr_array_index(pGeometry->m_pPointStringsArray, iString); + for(iString=0 ; iString<pPointStringsArray->len ; iString++) { + pPointString = g_ptr_array_index(pPointStringsArray, iString); if(pPointString->m_pPointsArray->len >= 2) { pPoint = g_ptr_array_index(pPointString->m_pPointsArray, 0); @@ -1171,35 +1047,35 @@ void map_draw_layer_lines(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geom cairo_restore(pCairo); } -void map_draw_layer_line_labels(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) +void map_draw_layer_line_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) { gint i; gdouble fLineWidth = pSubLayerStyle->m_afLineWidths[pRenderMetrics->m_nZoomLevel-1]; - for(i=0 ; i<pGeometry->m_pPointStringsArray->len ; i++) { - pointstring_t* pPointString = g_ptr_array_index(pGeometry->m_pPointStringsArray, i); + for(i=0 ; i<pPointStringsArray->len ; i++) { + pointstring_t* pPointString = g_ptr_array_index(pPointStringsArray, i); if(pPointString->m_pszName[0] != '\0') { - map_draw_line_label(pCairo, pLabelStyle, pRenderMetrics, pPointString, fLineWidth, pPointString->m_pszName); + map_draw_line_label(pMap, pCairo, pLabelStyle, pRenderMetrics, pPointString, fLineWidth, pPointString->m_pszName); } } } -void map_draw_layer_polygon_labels(cairo_t* pCairo, rendermetrics_t* pRenderMetrics, geometryset_t* pGeometry, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) +void map_draw_layer_polygon_labels(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pPointStringsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle) { gint i; - for(i=0 ; i<pGeometry->m_pPointStringsArray->len ; i++) { - pointstring_t* pPointString = g_ptr_array_index(pGeometry->m_pPointStringsArray, i); + for(i=0 ; i<pPointStringsArray->len ; i++) { + pointstring_t* pPointString = g_ptr_array_index(pPointStringsArray, i); if(pPointString->m_pszName[0] != '\0') { - map_draw_polygon_label(pCairo, pLabelStyle, pRenderMetrics, pPointString, pPointString->m_pszName); + map_draw_polygon_label(pMap, pCairo, pLabelStyle, pRenderMetrics, pPointString, pPointString->m_pszName); } } } -void map_draw_gps_trail(cairo_t* pCairo, pointstring_t* pPointString) +void map_draw_gps_trail(map_t* pMap, cairo_t* pCairo, pointstring_t* pPointString) { rendermetrics_t renderMetrics = {0}; - map_get_render_metrics(&renderMetrics); + map_get_render_metrics(pMap, &renderMetrics); rendermetrics_t* pRenderMetrics = &renderMetrics; if(pPointString->m_pPointsArray->len > 2) { @@ -1225,32 +1101,177 @@ void map_draw_gps_trail(cairo_t* pCairo, pointstring_t* pPointString) } } -// ======================================================== -// Road Direction / Suffix conversions -// ======================================================== - -const gchar* map_road_suffix_itoa(gint nSuffixID, ESuffixLength eSuffixLength) +static gboolean map_data_load(map_t* pMap, maprect_t* pRect) { - if(nSuffixID >= ROAD_SUFFIX_FIRST && nSuffixID <= ROAD_SUFFIX_LAST) { - if(eSuffixLength == SUFFIX_LENGTH_SHORT) { - return g_RoadNameSuffix[nSuffixID].m_pszShort; - } - else { - return g_RoadNameSuffix[nSuffixID].m_pszLong; + g_return_val_if_fail(pRect != NULL, FALSE); + + db_resultset_t* pResultSet = NULL; + db_row_t aRow; + + gint nZoomLevel = map_get_zoomlevel(pMap); + + map_data_clear(pMap); + + TIMER_BEGIN(mytimer, "BEGIN Geometry LOAD"); + + // HACKY: make a list of layer IDs "2,3,5,6" + gchar azLayerNumberList[200] = {0}; + gint nActiveLayerCount = 0; + gint i; + for(i=LAYER_FIRST ; i <= LAYER_LAST ;i++) { + if(g_aLayers[i].m_Style.m_aSubLayers[0].m_afLineWidths[nZoomLevel-1] != 0.0 || + g_aLayers[i].m_Style.m_aSubLayers[1].m_afLineWidths[nZoomLevel-1] != 0.0) + { + gchar azLayerNumber[10]; + + if(nActiveLayerCount > 0) g_snprintf(azLayerNumber, 10, ",%d", i); + else g_snprintf(azLayerNumber, 10, "%d", i); + + g_strlcat(azLayerNumberList, azLayerNumber, 200); + nActiveLayerCount++; } } - if(nSuffixID != ROAD_SUFFIX_NONE) return "???"; - return ""; + if(nActiveLayerCount == 0) { + g_print("no visible layers!\n"); + return TRUE; + } + + // generate SQL + gchar* pszSQL = g_strdup_printf( + "SELECT Road.ID, Road.TypeID, AsText(Road.Coordinates), RoadName.Name, RoadName.SuffixID" + " FROM Road " + " LEFT JOIN Road_RoadName ON (Road.ID=Road_RoadName.RoadID)" + " LEFT JOIN RoadName ON (Road_RoadName.RoadNameID=RoadName.ID)" + " WHERE" + " TypeID IN (%s) AND" + " MBRIntersects(GeomFromText('Polygon((%f %f,%f %f,%f %f,%f %f,%f %f))'), Coordinates)", + azLayerNumberList, + pRect->m_A.m_fLatitude, pRect->m_A.m_fLongitude, // upper left + pRect->m_A.m_fLatitude, pRect->m_B.m_fLongitude, // upper right + pRect->m_B.m_fLatitude, pRect->m_B.m_fLongitude, // bottom right + pRect->m_B.m_fLatitude, pRect->m_A.m_fLongitude, // bottom left + pRect->m_A.m_fLatitude, pRect->m_A.m_fLongitude // upper left again + ); + //g_print("sql: %s\n", pszSQL); + + db_query(pszSQL, &pResultSet); + g_free(pszSQL); + + TIMER_SHOW(mytimer, "after query"); + + guint32 uRowCount = 0; + if(pResultSet) { + TIMER_SHOW(mytimer, "after clear layers"); + while((aRow = db_fetch_row(pResultSet))) { + uRowCount++; + + // aRow[0] is ID + // aRow[1] is TypeID + // aRow[2] is Coordinates in mysql's text format + // aRow[3] is road name + // aRow[4] is road name suffix id +// g_print("data: %s, %s, %s, %s, %s\n", aRow[0], aRow[1], aRow[2], aRow[3], aRow[4]); + + // Get layer type that this belongs on + gint nTypeID = atoi(aRow[1]); + if(nTypeID < LAYER_FIRST || nTypeID > LAYER_LAST) { + g_warning("geometry record '%s' has bad type '%s'\n", aRow[0], aRow[1]); + continue; + } + + // Extract points + pointstring_t* pNewPointString = NULL; + if(!pointstring_alloc(&pNewPointString)) { + g_warning("out of memory loading pointstrings\n"); + continue; + } + db_parse_pointstring(aRow[2], pNewPointString, point_alloc); + + // Build name by adding suffix, if one is present + gchar azFullName[100] = ""; + + // does it have a name? + if(aRow[3] != NULL && aRow[4] != NULL) { + gint nSuffixID = atoi(aRow[4]); + const gchar* pszSuffix = road_suffix_itoa(nSuffixID, ROAD_SUFFIX_LENGTH_SHORT); + g_snprintf(azFullName, 100, "%s%s%s", + aRow[3], (pszSuffix[0] != '\0') ? " " : "", pszSuffix); + } + pNewPointString->m_pszName = g_strdup(azFullName); + + // Add this item to layer's list of pointstrings + g_ptr_array_add( + pMap->m_apLayerData[nTypeID]->m_pPointStringsArray, pNewPointString); + } // end while loop on rows + g_print("[%d rows]\n", uRowCount); + TIMER_SHOW(mytimer, "after rows retrieved"); + + db_free_result(pResultSet); + TIMER_SHOW(mytimer, "after free results"); + TIMER_END(mytimer, "END Geometry LOAD"); + + return TRUE; + } + else { + g_print(" no rows\n"); + return FALSE; + } } -gboolean map_road_suffix_atoi(const gchar* pszSuffix, gint* pReturnSuffixID) +static void map_data_clear(map_t* pMap) { - gint i; - for(i=0 ; i<NUM_ELEMS(g_RoadNameSuffixLookup) ; i++) { - if(g_ascii_strcasecmp(pszSuffix, g_RoadNameSuffixLookup[i].m_pszName) == 0) { - *pReturnSuffixID = g_RoadNameSuffixLookup[i].m_nID; - return TRUE; + gint i,j; + for(i=0 ; i<NUM_ELEMS(pMap->m_apLayerData) ; i++) { + maplayer_data_t* pLayerData = pMap->m_apLayerData[i]; + + // Free each pointstring + for(j = (pLayerData->m_pPointStringsArray->len - 1) ; j>=0 ; j--) { + pointstring_t* pPointString = g_ptr_array_remove_index_fast(pLayerData->m_pPointStringsArray, j); + pointstring_free(pPointString); } } - return FALSE; } + + +#if ROADSTER_DEAD_CODE +static double map_get_distance_in_meters(mappoint_t* pA, mappoint_t* pB) +{ + g_assert_not_reached(); // unused/tested + + // This functions calculates the length of the arc of the "greatcircle" that goes through + // the two points A and B and whos center is the center of the sphere, O. + + // When we multiply this angle (in radians) by the radius, we get the length of the arc. + + // NOTE: This algorithm wrongly assumes that Earth is a perfect sphere. + // It is actually slightly egg shaped. But it's good enough. + + // All trig functions expect arguments in radians. + double fLonA_Rad = DEG2RAD(pA->m_fLongitude); + double fLonB_Rad = DEG2RAD(pB->m_fLongitude); + double fLatA_Rad = DEG2RAD(pA->m_fLatitude); + double fLatB_Rad = DEG2RAD(pB->m_fLatitude); + + // Step 1. Calculate AOB (in radians). + // An explanation of this equation is at http://mathforum.org/library/drmath/view/51722.html + double fAOB_Rad = acos((cos(fLatA_Rad) * cos(fLatB_Rad) * cos(fLonB_Rad - fLonA_Rad)) + (sin(fLatA_Rad) * sin(fLatB_Rad))); + + // Step 2. Multiply the angle by the radius of the sphere to get arc length. + return fAOB_Rad * RADIUS_OF_WORLD_IN_METERS; +} + +// ======================================================== +// Redraw +// ======================================================== + +void map_set_redraw_needed(gboolean bNeeded) +{ + pMap->m_bRedrawNeeded = bNeeded; +} + +gboolean map_get_redraw_needed() +{ + return pMap->m_bRedrawNeeded; +} +#endif /* ROADSTER_DEAD_CODE */ + @@ -26,11 +26,55 @@ #include <cairo.h> +typedef enum { + kSublayerBottom, + kSublayerTop, +} ESubLayer; + +#define MIN_LINE_LENGTH_FOR_LABEL (40) +#define LABEL_PIXELS_ABOVE_LINE (2) +#define LABEL_PIXEL_RELIEF_INSIDE_LINE (2) // when drawing a label inside a line, only do so if we would have at least this much blank space above+below the text + +// For road names: Bitstream Vera Sans Mono ? + +#define INCHES_PER_METER (39.37007) + +#define MIN_ZOOMLEVEL (1) +#define MAX_ZOOMLEVEL (10) +#define NUM_ZOOMLEVELS (10) + +#define WORLD_CIRCUMFERENCE_IN_METERS (40076000) +#define WORLD_METERS_PER_DEGREE (WORLD_CIRCUMFERENCE_IN_METERS / 360.0) +#define WORLD_METERS_TO_DEGREES(x) ((x) / WORLD_METERS_PER_DEGREE) +#define WORLD_DEGREES_TO_METERS(x) ((x) * WORLD_METERS_PER_DEGREE) +#define KILOMETERS_PER_METER (1000) +#define WORLD_KILOMETERS_TO_DEGREES(x) ((x * KILOMETERS_PER_METER) / WORLD_METERS_PER_DEGREE) + +#define WORLD_CIRCUMFERENCE_IN_FEET (131482939.8324) +#define WORLD_FEET_PER_DEGREE (WORLD_CIRCUMFERENCE_IN_FEET / 360.0) +#define WORLD_FEET_TO_DEGREES(X) ((X) / WORLD_FEET_PER_DEGREE) +#define FEET_PER_MILE (5280) +#define WORLD_MILES_TO_DEGREES(x) ((x * FEET_PER_MILE) / WORLD_FEET_PER_DEGREE) + +// Earth is slightly egg shaped so there are infinite radius measurements: + +// at poles: ? +// average: 6,371,010 +// at equator: 6,378,136 meters + +#define RADIUS_OF_WORLD_IN_METERS (6371010) + +#define DEG2RAD(x) ((x) * (M_PI / 180.0)) +#define RAD2DEG(x) ((x) * (180.0 / M_PI)) + struct GtkWidget; #define MIN_ZOOM_LEVEL 1 #define MAX_ZOOM_LEVEL 10 +#include "layers.h" +#include "scenemanager.h" + // World space typedef struct mappoint { gdouble m_fLatitude; @@ -65,7 +109,6 @@ typedef struct zoomlevel { extern zoomlevel_t g_sZoomLevels[]; - typedef enum { UNIT_FIRST=0, UNIT_FEET=0, @@ -79,54 +122,6 @@ typedef enum { extern gchar* g_aDistanceUnitNames[]; -enum ERoadNameSuffix { // these can't change once stored in DB - ROAD_SUFFIX_FIRST = 0, - ROAD_SUFFIX_NONE = 0, - - ROAD_SUFFIX_ROAD = 1, - ROAD_SUFFIX_STREET, - ROAD_SUFFIX_DRIVE, - ROAD_SUFFIX_BOULEVARD, // blvd - ROAD_SUFFIX_AVENUE, - ROAD_SUFFIX_CIRCLE, - ROAD_SUFFIX_SQUARE, - ROAD_SUFFIX_PATH, - ROAD_SUFFIX_WAY, - ROAD_SUFFIX_PLAZA, - ROAD_SUFFIX_TRAIL, - ROAD_SUFFIX_LANE, - ROAD_SUFFIX_CROSSING, - ROAD_SUFFIX_PLACE, - ROAD_SUFFIX_COURT, - ROAD_SUFFIX_TURNPIKE, - ROAD_SUFFIX_TERRACE, - ROAD_SUFFIX_ROW, - ROAD_SUFFIX_PARKWAY, - - ROAD_SUFFIX_BRIDGE, - ROAD_SUFFIX_HIGHWAY, - ROAD_SUFFIX_RUN, - ROAD_SUFFIX_PASS, - - ROAD_SUFFIX_FREEWAY, - ROAD_SUFFIX_ALLEY, - ROAD_SUFFIX_CRESCENT, - ROAD_SUFFIX_TUNNEL, - ROAD_SUFFIX_WALK, - ROAD_SUFFIX_BRANCE, - ROAD_SUFFIX_COVE, - ROAD_SUFFIX_BYPASS, - ROAD_SUFFIX_LOOP, - ROAD_SUFFIX_SPUR, - ROAD_SUFFIX_RAMP, - ROAD_SUFFIX_PIKE, - ROAD_SUFFIX_GRADE, - ROAD_SUFFIX_ROUTE, - ROAD_SUFFIX_ARC, - - ROAD_SUFFIX_LAST = ROAD_SUFFIX_ARC -}; - typedef struct { gint m_nZoomLevel; gdouble m_fScreenLatitude; @@ -136,38 +131,58 @@ typedef struct { gint m_nWindowHeight; } rendermetrics_t; -// ESuffixLength -typedef enum { - SUFFIX_LENGTH_SHORT, - SUFFIX_LENGTH_LONG -} ESuffixLength; +typedef struct { + GPtrArray* m_pPointStringsArray; // this should probably change to an array of 'roads' +} maplayer_data_t; + +typedef struct { + // Mutex and the data it controls (always lock before reading/writing) + GMutex* m_pDataMutex; + mappoint_t m_MapCenter; + dimensions_t m_MapDimensions; + guint16 m_uZoomLevel; + maplayer_data_t* m_apLayerData[ NUM_LAYERS + 1 ]; + GtkWidget* m_pTargetWidget; + scenemanager_t* m_pSceneManager; + + // Mutex and the data it controls (always lock before reading/writing) + GMutex* m_pPixmapMutex; + GdkPixmap* m_pPixmap; +} map_t; + -void map_draw(cairo_t *cr); +void map_init(void); +gboolean map_new(map_t** ppMap, GtkWidget* pTargetWidget); -const gchar* map_road_suffix_itoa(gint nSuffixID, ESuffixLength eSuffixLength); -gboolean map_road_suffix_atoi(const gchar* pszSuffix, gint* pReturnSuffixID); // Gets and Sets -guint16 map_get_zoomlevel(void); -guint32 map_get_zoomlevel_scale(void); -void map_set_zoomlevel(guint16 uZoomLevel); +guint16 map_get_zoomlevel(map_t* pMap); +guint32 map_get_zoomlevel_scale(map_t* pMap); +void map_set_zoomlevel(map_t* pMap, guint16 uZoomLevel); //void map_get_render_metrics(rendermetrics_t* pMetrics); -void map_set_redraw_needed(gboolean bNeeded); -gboolean map_get_redraw_needed(void); +void map_set_redraw_needed(map_t* pMap, gboolean bNeeded); +gboolean map_get_redraw_needed(map_t* pMap); -guint32 map_get_scale(void); +guint32 map_get_scale(map_t* pMap); -void map_set_centerpoint(const mappoint_t* pPoint); -void map_get_centerpoint(mappoint_t* pReturnPoint); -void map_set_dimensions(const dimensions_t* pDimensions); +void map_set_centerpoint(map_t* pMap, const mappoint_t* pPoint); +void map_get_centerpoint(map_t* pMap, mappoint_t* pReturnPoint); +void map_set_dimensions(map_t* pMap, const dimensions_t* pDimensions); // Conversions -void map_windowpoint_to_mappoint(screenpoint_t* pScreenPoint, mappoint_t* pMapPoint); -gdouble map_distance_in_units_to_degrees(gdouble fDistance, gint nDistanceUnit); +void map_windowpoint_to_mappoint(map_t* pMap, screenpoint_t* pScreenPoint, mappoint_t* pMapPoint); +gdouble map_distance_in_units_to_degrees(map_t* pMap, gdouble fDistance, gint nDistanceUnit); // remove this! -void map_center_on_windowpoint(guint16 uX, guint16 uY); +void map_center_on_windowpoint(map_t* pMap, guint16 uX, guint16 uY); + + +GdkPixmap* map_get_pixmap(map_t* pMap); +void map_release_pixmap(map_t* pMap); +void map_draw_thread_begin(map_t* pMap, GtkWidget* pTargetWidget); + +void map_draw(map_t* pMap, cairo_t *cr); #endif diff --git a/src/road.c b/src/road.c new file mode 100644 index 0000000..4eb16c7 --- /dev/null +++ b/src/road.c @@ -0,0 +1,221 @@ +/*************************************************************************** + * road.c + * + * Copyright 2005 Ian McIntosh + * ian_mcintosh@linuxadvocate.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <gnome.h> +#include "road.h" +#include "util.h" + +struct { + gchar* m_pszLong; + gchar* m_pszShort; +} g_RoadNameSuffix[] = { + {"",""}, + {"Road", "Rd"}, + {"Street", "St"}, + {"Drive", "Dr"}, + {"Boulevard", "Bvd"}, + {"Avenue", "Ave"}, + {"Circle", "Crl"}, + {"Square", "Sq"}, + {"Path", "Pth"}, + {"Way", "Wy"}, + {"Plaza", "Plz"}, + {"Trail", "Trl"}, + {"Lane", "Ln"}, + {"Crossing", "Xing"}, + {"Place", "Pl"}, + {"Court", "Ct"}, + {"Turnpike", "Tpke"}, + {"Terrace", "Ter"}, + {"Row", "Row"}, + {"Parkway", "Pky"}, + + {"Bridge", "Brg"}, + {"Highway", "Hwy"}, + {"Run", "Run"}, + {"Pass", "Pass"}, + + {"Freeway", "Fwy"}, + {"Alley", "Aly"}, + {"Crescent", "Cres"}, + {"Tunnel", "Tunl"}, + {"Walk", "Walk"}, + {"Terrace", "Trce"}, + {"Branch", "Br"}, + {"Cove", "Cv"}, + {"Bypass", "Byp"}, + {"Loop", "Loop"}, + {"Spur", "Spur"}, + {"Ramp", "Ramp"}, + {"Pike", "Pike"}, + {"Grade", "Grd"}, + {"Route", "Rte"}, + {"Arc", "Arc"}, +}; + +struct { + gchar* m_pszName; + gint m_nID; +} g_RoadNameSuffixLookup[] = { + {"Rd", ROAD_SUFFIX_ROAD}, + {"Road", ROAD_SUFFIX_ROAD}, + + {"St", ROAD_SUFFIX_STREET}, + {"Street", ROAD_SUFFIX_STREET}, + + {"Dr", ROAD_SUFFIX_DRIVE}, + {"Drive", ROAD_SUFFIX_DRIVE}, + + {"Blv", ROAD_SUFFIX_BOULEVARD}, + {"Blvd", ROAD_SUFFIX_BOULEVARD}, + {"Boulevard", ROAD_SUFFIX_BOULEVARD}, + + {"Av", ROAD_SUFFIX_AVENUE}, + {"Ave", ROAD_SUFFIX_AVENUE}, + {"Avenue", ROAD_SUFFIX_AVENUE}, + + {"Cir", ROAD_SUFFIX_CIRCLE}, + {"Crl", ROAD_SUFFIX_CIRCLE}, + {"Circle", ROAD_SUFFIX_CIRCLE}, + + {"Sq", ROAD_SUFFIX_SQUARE}, + {"Square", ROAD_SUFFIX_SQUARE}, + + {"Pl", ROAD_SUFFIX_PLACE}, + {"Place", ROAD_SUFFIX_PLACE}, + + {"Xing", ROAD_SUFFIX_CROSSING}, + {"Crossing", ROAD_SUFFIX_CROSSING}, + + {"Ct", ROAD_SUFFIX_COURT}, + {"Court", ROAD_SUFFIX_COURT}, + + {"Tpke", ROAD_SUFFIX_TURNPIKE}, + {"Turnpike", ROAD_SUFFIX_TURNPIKE}, + + {"Ter", ROAD_SUFFIX_TERRACE}, + {"Terrace", ROAD_SUFFIX_TERRACE}, + + {"Row", ROAD_SUFFIX_ROW}, + + {"Pth", ROAD_SUFFIX_PATH}, + {"Path", ROAD_SUFFIX_PATH}, + + {"Wy", ROAD_SUFFIX_WAY}, + {"Way", ROAD_SUFFIX_WAY}, + + {"Plz", ROAD_SUFFIX_PLAZA}, + {"Plaza", ROAD_SUFFIX_PLAZA}, + + {"Trl", ROAD_SUFFIX_TRAIL}, + {"Trail", ROAD_SUFFIX_TRAIL}, + + {"Ln", ROAD_SUFFIX_LANE}, + {"Lane", ROAD_SUFFIX_LANE}, + + {"Pky", ROAD_SUFFIX_PARKWAY}, + {"Parkway", ROAD_SUFFIX_PARKWAY}, + + {"Brg", ROAD_SUFFIX_BRIDGE}, + {"Bridge", ROAD_SUFFIX_BRIDGE}, + + {"Hwy", ROAD_SUFFIX_HIGHWAY}, + {"Highway", ROAD_SUFFIX_HIGHWAY}, + + {"Run", ROAD_SUFFIX_RUN}, + + {"Pass", ROAD_SUFFIX_PASS}, + + {"Freeway", ROAD_SUFFIX_FREEWAY}, + {"Fwy", ROAD_SUFFIX_FREEWAY}, + + {"Alley", ROAD_SUFFIX_ALLEY}, + {"Aly", ROAD_SUFFIX_ALLEY}, + + {"Crescent", ROAD_SUFFIX_CRESCENT}, + {"Cres", ROAD_SUFFIX_CRESCENT}, + + {"Tunnel", ROAD_SUFFIX_TUNNEL}, + {"Tunl", ROAD_SUFFIX_TUNNEL}, + + {"Walk", ROAD_SUFFIX_WALK}, + {"Walk", ROAD_SUFFIX_WALK}, + + {"Branch", ROAD_SUFFIX_BRANCE}, + {"Br", ROAD_SUFFIX_BRANCE}, + + {"Cove", ROAD_SUFFIX_COVE}, + {"Cv", ROAD_SUFFIX_COVE}, + + {"Bypass", ROAD_SUFFIX_BYPASS}, + {"Byp", ROAD_SUFFIX_BYPASS}, + + {"Loop", ROAD_SUFFIX_LOOP}, + + {"Spur", ROAD_SUFFIX_SPUR}, + + {"Ramp", ROAD_SUFFIX_RAMP}, + + {"Pike", ROAD_SUFFIX_PIKE}, + + {"Grade", ROAD_SUFFIX_GRADE}, + {"Grd", ROAD_SUFFIX_GRADE}, + + {"Route", ROAD_SUFFIX_ROUTE}, + {"Rte", ROAD_SUFFIX_ROUTE}, + + {"Arc", ROAD_SUFFIX_ARC}, + +}; + + +// ======================================================== +// Road Direction / Suffix conversions +// ======================================================== + +const gchar* road_suffix_itoa(gint nSuffixID, ESuffixLength eSuffixLength) +{ + if(nSuffixID >= ROAD_SUFFIX_FIRST && nSuffixID <= ROAD_SUFFIX_LAST) { + if(eSuffixLength == ROAD_SUFFIX_LENGTH_SHORT) { + return g_RoadNameSuffix[nSuffixID].m_pszShort; + } + else { + return g_RoadNameSuffix[nSuffixID].m_pszLong; + } + } + if(nSuffixID != ROAD_SUFFIX_NONE) return "???"; + return ""; +} + +gboolean road_suffix_atoi(const gchar* pszSuffix, gint* pReturnSuffixID) +{ + gint i; + for(i=0 ; i<NUM_ELEMS(g_RoadNameSuffixLookup) ; i++) { + if(g_ascii_strcasecmp(pszSuffix, g_RoadNameSuffixLookup[i].m_pszName) == 0) { + *pReturnSuffixID = g_RoadNameSuffixLookup[i].m_nID; + return TRUE; + } + } + return FALSE; +} + diff --git a/src/road.h b/src/road.h new file mode 100644 index 0000000..4b1d6e0 --- /dev/null +++ b/src/road.h @@ -0,0 +1,84 @@ +/*************************************************************************** + * road.h + * + * Copyright 2005 Ian McIntosh + * ian_mcintosh@linuxadvocate.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _ROAD_H_ +#define _ROAD_H_ + +// ESuffixLength +typedef enum { + ROAD_SUFFIX_LENGTH_SHORT, + ROAD_SUFFIX_LENGTH_LONG +} ESuffixLength; + +enum ERoadNameSuffix { // these can't change once stored in DB + ROAD_SUFFIX_FIRST = 0, + ROAD_SUFFIX_NONE = 0, + + ROAD_SUFFIX_ROAD = 1, + ROAD_SUFFIX_STREET, + ROAD_SUFFIX_DRIVE, + ROAD_SUFFIX_BOULEVARD, // blvd + ROAD_SUFFIX_AVENUE, + ROAD_SUFFIX_CIRCLE, + ROAD_SUFFIX_SQUARE, + ROAD_SUFFIX_PATH, + ROAD_SUFFIX_WAY, + ROAD_SUFFIX_PLAZA, + ROAD_SUFFIX_TRAIL, + ROAD_SUFFIX_LANE, + ROAD_SUFFIX_CROSSING, + ROAD_SUFFIX_PLACE, + ROAD_SUFFIX_COURT, + ROAD_SUFFIX_TURNPIKE, + ROAD_SUFFIX_TERRACE, + ROAD_SUFFIX_ROW, + ROAD_SUFFIX_PARKWAY, + + ROAD_SUFFIX_BRIDGE, + ROAD_SUFFIX_HIGHWAY, + ROAD_SUFFIX_RUN, + ROAD_SUFFIX_PASS, + + ROAD_SUFFIX_FREEWAY, + ROAD_SUFFIX_ALLEY, + ROAD_SUFFIX_CRESCENT, + ROAD_SUFFIX_TUNNEL, + ROAD_SUFFIX_WALK, + ROAD_SUFFIX_BRANCE, + ROAD_SUFFIX_COVE, + ROAD_SUFFIX_BYPASS, + ROAD_SUFFIX_LOOP, + ROAD_SUFFIX_SPUR, + ROAD_SUFFIX_RAMP, + ROAD_SUFFIX_PIKE, + ROAD_SUFFIX_GRADE, + ROAD_SUFFIX_ROUTE, + ROAD_SUFFIX_ARC, + + ROAD_SUFFIX_LAST = ROAD_SUFFIX_ARC +}; + +const gchar* road_suffix_itoa(gint nSuffixID, ESuffixLength eSuffixLength); +gboolean road_suffix_atoi(const gchar* pszSuffix, gint* pReturnSuffixID); + +#endif diff --git a/src/scenemanager.c b/src/scenemanager.c index d700277..549644b 100644 --- a/src/scenemanager.c +++ b/src/scenemanager.c @@ -22,7 +22,6 @@ */ #include <gtk/gtk.h> -#include "geometryset.h" #include "scenemanager.h" /* @@ -36,57 +35,50 @@ Goals: // gchar* m_pszLabel; // } roadlabel_t; -struct { - GPtrArray* m_p; - GHashTable* m_pLabelHash; -} g_SceneManager; - void scenemanager_init(void) { - g_SceneManager.m_pLabelHash = g_hash_table_new(g_str_hash, g_str_equal); } -gboolean scenemanager_can_draw_label(const gchar* pszLabel) +void scenemanager_new(scenemanager_t** ppReturn) +{ + scenemanager_t* pNew = g_new0(scenemanager_t, 1); + pNew->m_pLabelHash = g_hash_table_new(g_str_hash, g_str_equal); + *ppReturn = pNew; +} + +gboolean scenemanager_can_draw_label(scenemanager_t* pSceneManager, const gchar* pszLabel) { + g_assert(pSceneManager != NULL); + gpointer pKey; gpointer pValue; // can draw if it doesn't exist in table - gboolean bOK = (g_hash_table_lookup_extended(g_SceneManager.m_pLabelHash, - pszLabel, - &pKey, &pValue) == FALSE); + gboolean bOK = (g_hash_table_lookup_extended(pSceneManager->m_pLabelHash, + pszLabel, &pKey, &pValue) == FALSE); // g_print("permission for %s: %s\n", pszLabel, bOK ? "YES" : "NO"); return bOK; } -void scenemanager_label_drawn(const gchar* pszLabel) +void scenemanager_label_drawn(scenemanager_t* pSceneManager, const gchar* pszLabel) { + g_assert(pSceneManager != NULL); // g_print("drawn! %s\n", pszLabel); - g_hash_table_insert(g_SceneManager.m_pLabelHash, pszLabel, NULL); + g_hash_table_insert(pSceneManager->m_pLabelHash, pszLabel, NULL); } -void scenemanager_clear(void) +void scenemanager_clear(scenemanager_t* pSceneManager) { - g_hash_table_destroy(g_SceneManager.m_pLabelHash); + g_assert(pSceneManager != NULL); - scenemanager_init(); + g_hash_table_destroy(pSceneManager->m_pLabelHash); + pSceneManager->m_pLabelHash = g_hash_table_new(g_str_hash, g_str_equal); } #if ROADSTER_DEAD_CODE -static void scenemanager_add_label_line(geometryset_t* pGeometry, gchar* pszLabel) -{ - -} - -static void scenemanager_add_label_polygon(geometryset_t* pGeometry, gchar* pszLabel) -{ - -} - -static void scenemanager_draw(void) -{ - -} +static void scenemanager_add_label_line(geometryset_t* pGeometry, gchar* pszLabel) {} +static void scenemanager_add_label_polygon(geometryset_t* pGeometry, gchar* pszLabel) {} +static void scenemanager_draw(void) {} #endif /* ROADSTER_DEAD_CODE */ diff --git a/src/scenemanager.h b/src/scenemanager.h index ac4c6ca..ebbe929 100644 --- a/src/scenemanager.h +++ b/src/scenemanager.h @@ -21,8 +21,22 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef _SCENEMANAGER_H_ +#define _SCENEMANAGER_H_ + +//#include <gnome.h> + +typedef struct scenemanager { + GPtrArray* m_p; + GHashTable* m_pLabelHash; +} scenemanager_t; + void scenemanager_init(void); -gboolean scenemanager_can_draw_label(const gchar* pszLabel); -void scenemanager_label_drawn(const gchar* pszLabel); -void scenemanager_clear(void); +void scenemanager_new(scenemanager_t** ppReturn); + +gboolean scenemanager_can_draw_label(scenemanager_t* pSceneManager, const gchar* pszLabel); +void scenemanager_label_drawn(scenemanager_t* pSceneManager, const gchar* pszLabel); +void scenemanager_clear(scenemanager_t* pSceneManager); + +#endif diff --git a/src/search.c b/src/search.c index 56a4780..c943baf 100644 --- a/src/search.c +++ b/src/search.c @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #include <gtk/gtk.h> #include "search.h" @@ -34,20 +34,20 @@ void search_clean_string(gchar* p) gchar* pWriter = p; // skip white - while(*pReader == ' ') { + while(g_ascii_isspace(*pReader)) { pReader++; } // remove double spaces while(*pReader != '\0') { - if(*pReader == ' ') { - if(*(pReader+1) == ' ' || *(pReader+1) == '\0') { + if(g_ascii_isspace(*pReader)) { + if(g_ascii_isspace(*(pReader+1)) || *(pReader+1) == '\0') { // don't copy this character (space) if the next one is a space also // or if it's the last character } else { // yes, copy this space - *pWriter = *pReader; + *pWriter = ' '; // this also turns newlines etc. into spaces pWriter++; } } diff --git a/src/search_location.c b/src/search_location.c index baf1852..c37342e 100644 --- a/src/search_location.c +++ b/src/search_location.c @@ -47,6 +47,8 @@ void search_location_filter_result(gint nLocationID); void search_location_execute(const gchar* pszSentence, gint nLocationSetID, gfloat fDistance, gint nDistanceUnit) { + return; +/* g_print("pszSentence = %s, nLocationSetID = %d, fDistance = %f, nDistanceUnit=%d\n", pszSentence, nLocationSetID, fDistance, nDistanceUnit); TIMER_BEGIN(search, "\n\n****************************\nSEARCH BEGIN"); @@ -62,8 +64,10 @@ void search_location_execute(const gchar* pszSentence, gint nLocationSetID, gflo g_free(locationsearch.m_pszCleanedSentence); TIMER_END(search, "SEARCH END"); +*/ } +/* void search_location_on_cleaned_sentence(locationsearch_t* pLocationSearch) { // Create an array of the words @@ -172,3 +176,4 @@ void search_location_filter_result(gint nLocationID) searchwindow_add_result(0, p, &pt); g_free(p); } +*/ diff --git a/src/search_road.c b/src/search_road.c index 59339d5..84950a3 100644 --- a/src/search_road.c +++ b/src/search_road.c @@ -27,25 +27,26 @@ #include "db.h" #include "util.h" -//#include "geometryset.h" #include "pointstring.h" #include "point.h" #include "searchwindow.h" #include "search.h" #include "search_road.h" +#include "road.h" typedef struct { gint m_nNumber; // house number eg. 51 gchar* m_pszRoadName; // road name eg. "Washington" gint m_nCityID; // gint m_nStateID; - gint m_pszZIPCode; + gchar* m_pszZIPCode; gint m_nSuffixID; // a number representing eg. Ave } roadsearch_t; -#define ROADSEARCH_NUMBER_NONE (-1) -#define SEARCH_RESULT_COUNT_LIMIT (200) // how many rows to get from DB -#define MAX_QUERY (4000) +#define ROADSEARCH_NUMBER_NONE (-1) +#define SEARCH_RESULT_COUNT_LIMIT (200) // how many rows to get from DB +#define MAX_QUERY (4000) +#define ROAD_MIN_LENGTH_FOR_WILDCARD_SEARCH (3) // if glib < 2.6 #if ((GLIB_MAJOR_VERSION < 2) || ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION < 6))) @@ -223,7 +224,7 @@ void search_road_on_words(gchar** aWords, gint nWordCount) if(nRemainingWordCount >= 2) { gint nSuffixID; - if(map_road_suffix_atoi(aWords[iLast], &nSuffixID)) { + if(road_suffix_atoi(aWords[iLast], &nSuffixID)) { // matched roadsearch.m_nSuffixID = nSuffixID; iLast--; @@ -309,6 +310,14 @@ void search_road_on_roadsearch_struct(const roadsearch_t* pRoadSearch) gchar* pszSafeRoadName = db_make_escaped_string(pRoadSearch->m_pszRoadName); g_print("pRoadSearch->m_pszRoadName = %s, pszSafeRoadName = %s\n", pRoadSearch->m_pszRoadName, pszSafeRoadName); + gchar* pszRoadNameCondition; + if(strlen(pRoadSearch->m_pszRoadName) < ROAD_MIN_LENGTH_FOR_WILDCARD_SEARCH) { + pszRoadNameCondition = g_strdup_printf("RoadName.Name='%s'", pszSafeRoadName); + } + else { + pszRoadNameCondition = g_strdup_printf("RoadName.Name LIKE '%s%%'", pszSafeRoadName); + } + g_snprintf(azQuery, MAX_QUERY, "SELECT Road.ID, RoadName.Name, RoadName.SuffixID, AsText(Road.Coordinates), Road.AddressLeftStart, Road.AddressLeftEnd, Road.AddressRightStart, Road.AddressRightEnd, CityLeft.Name, CityRight.Name" ", StateLeft.Code, StateRight.Code, Road.ZIPCodeLeft, Road.ZIPCodeRight" @@ -321,18 +330,18 @@ void search_road_on_roadsearch_struct(const roadsearch_t* pRoadSearch) // right side " LEFT JOIN City AS CityRight ON (Road.CityRightID=CityRight.ID)" " LEFT JOIN State AS StateRight ON (CityRight.StateID=StateRight.ID)" - " WHERE RoadName.Name LIKE '%s%%'" + " WHERE %s" // " WHERE RoadName.Name='%s'" " AND Road.ID IS NOT NULL" // don't include rows where the Road didn't match // begin clauses "%s" "%s" - "%s" - "%s" -// " ORDER BY RoadName.Name" + "%s" + "%s" " LIMIT %d;", pszAddressClause, - pszSafeRoadName, + + pszRoadNameCondition, // clauses pszSuffixClause, @@ -344,6 +353,7 @@ void search_road_on_roadsearch_struct(const roadsearch_t* pRoadSearch) // free strings db_free_escaped_string(pszSafeRoadName); g_free(pszAddressClause); + g_free(pszRoadNameCondition); g_free(pszSuffixClause); g_free(pszZIPClause); g_free(pszCityClause); @@ -552,35 +562,35 @@ void search_road_filter_result( // show no numbers if they're both 0 g_snprintf(azBuffer, BUFFER_SIZE, "%s %s\n%s", pszRoadName, - map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), + road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZRight); } else if(nAddressRightStart < nAddressRightEnd) { - g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressRightStart, nAddressRightEnd, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZRight); + g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressRightStart, nAddressRightEnd, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZRight); } else { // reverse start/end for the dear user :) - g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressRightEnd, nAddressRightStart, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZRight); + g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressRightEnd, nAddressRightStart, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZRight); } searchwindow_add_result(nRoadID, azBuffer, &ptAddress); // do left side, same as right side (see above) if(nAddressLeftStart == 0 && nAddressLeftEnd == 0) { - g_snprintf(azBuffer, BUFFER_SIZE, "%s %s\n%s", pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZLeft); + g_snprintf(azBuffer, BUFFER_SIZE, "%s %s\n%s", pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZLeft); } else if(nAddressLeftStart < nAddressLeftEnd) { - g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressLeftStart, nAddressLeftEnd, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZLeft); + g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressLeftStart, nAddressLeftEnd, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZLeft); } else { // swap address to keep smaller number to the left - g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressLeftEnd, nAddressLeftStart, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZLeft); + g_snprintf(azBuffer, BUFFER_SIZE, "%d-%d %s %s\n%s", nAddressLeftEnd, nAddressLeftStart, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZLeft); } searchwindow_add_result(nRoadID, azBuffer, &ptAddress); } else { // else the search had a road number // NOTE: we have to filter out results like "97-157" when searching for "124" because it's // on the wrong side of the road. -//g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s", nRoadNumber, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG)); +//g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s", nRoadNumber, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG)); // check left side of street // NOTE: if search was for an even, at least one (and hopefully both) of the range should be even @@ -599,7 +609,7 @@ void search_road_filter_result( gfloat fPercent = (gfloat)(nRoadNumber - nAddressLeftStart) / (gfloat)nRange; pointstring_walk_percentage(pPointString, fPercent, ROADSIDE_LEFT, &ptAddress); } - g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZLeft); + g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZLeft); searchwindow_add_result(nRoadID, azBuffer, &ptAddress); } else if(nRoadNumber >= nAddressLeftEnd && nRoadNumber <= nAddressLeftStart) { @@ -615,7 +625,7 @@ void search_road_filter_result( // flip percent (23 becomes 77, etc.) pointstring_walk_percentage(pPointString, (100.0 - fPercent), ROADSIDE_RIGHT, &ptAddress); } - g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZLeft); + g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZLeft); searchwindow_add_result(nRoadID, azBuffer, &ptAddress); } } @@ -636,7 +646,7 @@ void search_road_filter_result( gfloat fPercent = (gfloat)(nRoadNumber - nAddressRightStart) / (gfloat)nRange; pointstring_walk_percentage(pPointString, fPercent, ROADSIDE_RIGHT, &ptAddress); } - g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZRight); + g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZRight); searchwindow_add_result(nRoadID, azBuffer, &ptAddress); } else if(nRoadNumber >= nAddressRightEnd && nRoadNumber <= nAddressRightStart) { @@ -652,7 +662,7 @@ void search_road_filter_result( // flip percent (23 becomes 77, etc.) pointstring_walk_percentage(pPointString, (100.0 - fPercent), ROADSIDE_LEFT, &ptAddress); } - g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, map_road_suffix_itoa(nRoadSuffixID, SUFFIX_LENGTH_LONG), pszCSZRight); + g_snprintf(azBuffer, BUFFER_SIZE, "%d %s %s\n%s", nRoadNumber, pszRoadName, road_suffix_itoa(nRoadSuffixID, ROAD_SUFFIX_LENGTH_LONG), pszCSZRight); searchwindow_add_result(nRoadID, azBuffer, &ptAddress); } } diff --git a/src/searchwindow.c b/src/searchwindow.c index bfcb778..5661093 100644 --- a/src/searchwindow.c +++ b/src/searchwindow.c @@ -264,9 +264,7 @@ void searchwindow_go_to_selected_result(void) RESULTLIST_LONGITUDE, &pt.m_fLongitude, -1); - g_print("%f,%f\n", pt.m_fLatitude, pt.m_fLongitude); - - map_set_centerpoint(&pt); + mainwindow_set_centerpoint(&pt); mainwindow_draw_map(); mainwindow_statusbar_update_position(); // g_print("yay: %s\n", pszText); @@ -30,7 +30,7 @@ void util_random_color(void* pColor); -#if 0 +#if 1 #define TIMER_BEGIN(name, str) GTimer* name = g_timer_new(); g_print("\n%s (%f)\n", str, g_timer_elapsed(name, NULL)) #define TIMER_SHOW(name, str) g_print(" %s (%f)\n", str, g_timer_elapsed(name, NULL)) #define TIMER_END(name, str) g_print("%s (%f)\n", str, g_timer_elapsed(name, NULL)); g_timer_destroy(name); name = NULL |