diff options
author | Ian McIntosh <ian_mcintosh@linuxadvocate.org> | 2005-10-05 19:00:53 +0000 |
---|---|---|
committer | Ian McIntosh <ian_mcintosh@linuxadvocate.org> | 2005-10-05 19:00:53 +0000 |
commit | 50c966d35f9cb58c69eb3927f9cf669e47d2b77e (patch) | |
tree | daae4096b0a6c9b4c7cf42847728cabe6d673eea | |
parent | 5f76cb6b989a4c93bfc2b8cbb9b41a3c66dcf13b (diff) |
Added missing files.
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | data/layers.xml | 7 | ||||
-rw-r--r-- | data/roadster.glade | 4 | ||||
-rw-r--r-- | src/map_draw_cairo.c | 10 | ||||
-rw-r--r-- | src/map_hittest.c | 420 | ||||
-rw-r--r-- | src/map_hittest.h | 68 | ||||
-rw-r--r-- | src/map_style.c | 2 |
7 files changed, 507 insertions, 9 deletions
@@ -1,5 +1,10 @@ 2005-10-05 Ian McIntosh <ian_mcintosh@linuxadvocate.org> + * src/map_hittest.c: + * src/map_hittest.h: Added missing files. + +2005-10-05 Ian McIntosh <ian_mcintosh@linuxadvocate.org> + * src/import_tiger.c: * src/search_road.c: * src/db.c: Add level of detail concept. diff --git a/data/layers.xml b/data/layers.xml index 7263602..fd4fc0d 100644 --- a/data/layers.xml +++ b/data/layers.xml @@ -207,12 +207,12 @@ </layer> <layer data-source="rivers" draw-type="lines"> - <property zoom-level="6" name="line-width" value="1" /> + <property zoom-level="1-6" name="line-width" value="1" /> <property zoom-level="7" name="line-width" value="2" /> <property zoom-level="8" name="line-width" value="2" /> <property zoom-level="9" name="line-width" value="2" /> <property zoom-level="10" name="line-width" value="2" /> - <property zoom-level="6-10" name="color" value="#B5C6D6FF" /> + <property zoom-level="1-10" name="color" value="#B5C6D6FF" /> </layer> <layer data-source="lakes" draw-type="polygons"> @@ -229,7 +229,7 @@ </layer> <layer data-source="misc-areas" draw-type="polygons"> - <property zoom-level="6-10" name="color" value="#C0C0C0ff" /> + <property zoom-level="1-10" name="color" value="#C0C0C0ff" /> </layer> <!-- <layer data-source="urban-areas" draw-type="polygons"> --> @@ -237,6 +237,7 @@ <!-- </layer> --> <layer draw-type="fill"> +<!-- <property zoom-level="1-10" name="fill-image" value="ground-pattern" /> --> <property zoom-level="1-10" name="color" value="#F3EDDEFF" /> </layer> diff --git a/data/roadster.glade b/data/roadster.glade index 3d3d644..ce5c4f6 100644 --- a/data/roadster.glade +++ b/data/roadster.glade @@ -1095,8 +1095,8 @@ Banks</property> </widget> <widget class="GtkWindow" id="mainwindow"> - <property name="width_request">700</property> - <property name="height_request">500</property> + <property name="width_request">600</property> + <property name="height_request">300</property> <property name="visible">True</property> <property name="title" translatable="yes">Roadster Preview Release</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> diff --git a/src/map_draw_cairo.c b/src/map_draw_cairo.c index 6d65ce9..b234fbf 100644 --- a/src/map_draw_cairo.c +++ b/src/map_draw_cairo.c @@ -172,9 +172,13 @@ void map_draw_cairo(map_t* pMap, GPtrArray* pTiles, rendermetrics_t* pRenderMetr } else if(pLayer->nDrawType == MAP_LAYER_RENDERTYPE_POLYGON_LABELS) { if(nDrawFlags & DRAWFLAG_LABELS) { -// map_draw_cairo_layer_polygon_labels(pMap, pCairo, pRenderMetrics, -// pMap->apLayerData[pLayer->nDataSource]->pRoadsArray, -// pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]); + gint iTile; + for(iTile=0 ; iTile < pTiles->len ; iTile++) { + maptile_t* pTile = g_ptr_array_index(pTiles, iTile); + map_draw_cairo_layer_polygon_labels(pMap, pCairo, pRenderMetrics, + pTile->apMapObjectArrays[pLayer->nDataSource], // data + pLayer->paStylesAtZoomLevels[nStyleZoomLevel-1]); + } } } } diff --git a/src/map_hittest.c b/src/map_hittest.c new file mode 100644 index 0000000..6b7ac6d --- /dev/null +++ b/src/map_hittest.c @@ -0,0 +1,420 @@ +/*************************************************************************** + * map_hittest.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 <gtk/gtk.h> +#include <math.h> +#include "map.h" +#include "map_hittest.h" +#include "map_math.h" +#include "road.h" +#include "location.h" +#include "locationset.h" + + +static gboolean map_hittest_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine); +static ESide map_hittest_side_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pClosestPointOnLine, mappoint_t* pHitPoint); +static gboolean map_hittest_locations(map_t* pMap, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct); +static gboolean map_hittest_locationsets(map_t* pMap, rendermetrics_t* pRenderMetrics, mappoint_t* pHitPoint, maphit_t** ppReturnStruct); + +// ======================================================== +// Hit Testing +// ======================================================== + +gboolean map_hittest(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct) +{ +#if 0 // GGGGGGGGGGGGGGGG + rendermetrics_t rendermetrics; + map_get_render_metrics(pMap, &rendermetrics); + + if(map_hittest_locationselections(pMap, &rendermetrics, pMap->pLocationSelectionArray, pMapPoint, ppReturnStruct)) { + return TRUE; + } + + if(map_hittest_locationsets(pMap, &rendermetrics, pMapPoint, ppReturnStruct)) { + return TRUE; + } + + // Test things in the REVERSE order they are drawn (otherwise we'll match things that have been painted-over) + gint i; + for(i=G_N_ELEMENTS(layerdraworder)-1 ; i>=0 ; i--) { + if(layerdraworder[i].eSubLayerRenderType != SUBLAYER_RENDERTYPE_LINES) continue; + + gint nLayer = layerdraworder[i].nLayer; + + // use width from whichever layer it's wider in + gdouble fLineWidth = max(g_aLayers[nLayer]->Style.aSubLayers[0].afLineWidths[pMap->uZoomLevel-1], + g_aLayers[nLayer]->Style.aSubLayers[1].afLineWidths[pMap->uZoomLevel-1]); + +#define EXTRA_CLICKABLE_ROAD_IN_PIXELS (3) + + // make thin roads a little easier to hit + // fLineWidth = max(fLineWidth, MIN_ROAD_HIT_TARGET_WIDTH); + + // XXX: hack, map_pixels should really take a floating point instead. + gdouble fMaxDistance = map_pixels_to_degrees(pMap, 1, pMap->uZoomLevel) * ((fLineWidth/2) + EXTRA_CLICKABLE_ROAD_IN_PIXELS); // half width on each side + + if(map_hittest_layer_roads(pMap->apLayerData[nLayer]->pRoadsArray, fMaxDistance, pMapPoint, ppReturnStruct)) { + return TRUE; + } + // otherwise try next layer... + } +#endif + return FALSE; +} + +void map_hittest_maphit_free(map_t* pMap, maphit_t* pHitStruct) +{ + if(pHitStruct == NULL) return; + + // free type-specific stuff + if(pHitStruct->eHitType == MAP_HITTYPE_URL) { + g_free(pHitStruct->URLHit.pszURL); + } + + // free common stuff + g_free(pHitStruct->pszText); + g_free(pHitStruct); +} + +static gboolean map_hittest_layer_roads(GPtrArray* pRoadsArray, gdouble fMaxDistance, mappoint_t* pHitPoint, maphit_t** ppReturnStruct) +{ + g_assert(ppReturnStruct != NULL); + g_assert(*ppReturnStruct == NULL); // pointer to null pointer + + /* this is helpful for testing with the g_print()s in map_hit_test_line() */ +/* mappoint_t p1 = {2,2}; */ +/* mappoint_t p2 = {-10,10}; */ +/* mappoint_t p3 = {0,10}; */ +/* map_hit_test_line(&p1, &p2, &p3, 20); */ +/* return FALSE; */ + + // Loop through line strings, order doesn't matter here since they're all on the same level. + gint iString; + for(iString=0 ; iString<pRoadsArray->len ; iString++) { + road_t* pRoad = g_ptr_array_index(pRoadsArray, iString); + if(pRoad->pMapPointsArray->len < 2) continue; + + // start on 1 so we can do -1 trick below + gint iPoint; + for(iPoint=1 ; iPoint<pRoad->pMapPointsArray->len ; iPoint++) { + mappoint_t* pPoint1 = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint-1); + mappoint_t* pPoint2 = &g_array_index(pRoad->pMapPointsArray, mappoint_t, iPoint); + + mappoint_t pointClosest; + gdouble fPercentAlongLine; + + // hit test this line + if(map_hittest_line(pPoint1, pPoint2, pHitPoint, fMaxDistance, &pointClosest, &fPercentAlongLine)) { + //g_print("fPercentAlongLine = %f\n",fPercentAlongLine); + + // fill out a new maphit_t struct with details + maphit_t* pHitStruct = g_new0(maphit_t, 1); + pHitStruct->eHitType = MAP_HITTYPE_ROAD; + + if(pRoad->pszName[0] == '\0') { + pHitStruct->pszText = g_strdup("<i>unnamed</i>"); + } + else { + ESide eSide = map_hittest_side_test_line(pPoint1, pPoint2, &pointClosest, pHitPoint); + + gint nAddressStart; + gint nAddressEnd; + if(eSide == SIDE_LEFT) { + nAddressStart = pRoad->nAddressLeftStart; + nAddressEnd = pRoad->nAddressLeftEnd; + } + else { + nAddressStart = pRoad->nAddressRightStart; + nAddressEnd = pRoad->nAddressRightEnd; + } + + if(nAddressStart == 0 || nAddressEnd == 0) { + pHitStruct->pszText = g_strdup_printf("%s", pRoad->pszName); + } + else { + gint nMinAddres = MIN(nAddressStart, nAddressEnd); + gint nMaxAddres = MAX(nAddressStart, nAddressEnd); + + pHitStruct->pszText = g_strdup_printf("%s <b>#%d-%d</b>", pRoad->pszName, nMinAddres, nMaxAddres); + } + } + *ppReturnStruct = pHitStruct; + return TRUE; + } + } + } + return FALSE; +} + +static ESide map_hittest_side_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pClosestPointOnLine, mappoint_t* pHitPoint) +{ + // make a translated-to-origin *perpendicular* vector of the line (points to the "left" of the line when walking from point 1 to 2) + mappoint_t v; + v.fLatitude = (pPoint2->fLongitude - pPoint1->fLongitude); // NOTE: swapping lat and lon to make perpendicular + v.fLongitude = -(pPoint2->fLatitude - pPoint1->fLatitude); + + // make a translated-to-origin vector of the line from closest point to hitpoint + mappoint_t u; + u.fLatitude = pHitPoint->fLatitude - pClosestPointOnLine->fLatitude; + u.fLongitude = pHitPoint->fLongitude - pClosestPointOnLine->fLongitude; + + // figure out the signs of the elements of the vectors + gboolean bULatPositive = (u.fLatitude >= 0); + gboolean bULonPositive = (u.fLongitude >= 0); + gboolean bVLatPositive = (v.fLatitude >= 0); + gboolean bVLonPositive = (v.fLongitude >= 0); + + //g_print("%s,%s %s,%s\n", bVLonPositive?"Y":"N", bVLatPositive?"Y":"N", bULonPositive?"Y":"N", bULatPositive?"Y":"N"); + + // if the signs agree, it's to the left, otherwise to the right + if(bULatPositive == bVLatPositive && bULonPositive == bVLonPositive) { + return SIDE_LEFT; + } + else { + // let's check our algorithm: if the signs aren't both the same, they should be both opposite + // ...unless the vector from hitpoint to line center is 0, which doesn't have sign + + //g_print("%f,%f %f,%f\n", u.fLatitude, u.fLongitude, v.fLatitude, v.fLongitude); + g_assert(bULatPositive != bVLatPositive || u.fLatitude == 0.0); + g_assert(bULonPositive != bVLonPositive || u.fLongitude == 0.0); + return SIDE_RIGHT; + } +} + +// hit test all locations +static gboolean map_hittest_locationsets(map_t* pMap, rendermetrics_t* pRenderMetrics, mappoint_t* pHitPoint, maphit_t** ppReturnStruct) +{ + gdouble fMaxDistance = map_pixels_to_degrees(pMap, 1, pMap->uZoomLevel) * 3; // XXX: don't hardcode distance :) + + const GPtrArray* pLocationSetsArray = locationset_get_array(); + gint i; + for(i=0 ; i<pLocationSetsArray->len ; i++) { + locationset_t* pLocationSet = g_ptr_array_index(pLocationSetsArray, i); + + // the user is NOT trying to click on invisible things :) + if(!locationset_is_visible(pLocationSet)) continue; + + // 2. Get array of Locations from the hash table using LocationSetID + GPtrArray* pLocationsArray; + pLocationsArray = g_hash_table_lookup(pMap->pLocationArrayHashTable, &(pLocationSet->nID)); + if(pLocationsArray != NULL) { + if(map_hittest_locations(pMap, pRenderMetrics, pLocationsArray, pHitPoint, ppReturnStruct)) { + return TRUE; + } + } + else { + // none loaded + } + } + return FALSE; +} + +// hit-test an array of locations +static gboolean map_hittest_locations(map_t* pMap, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct) +{ + gint i; + for(i=(pLocationsArray->len-1) ; i>=0 ; i--) { // NOTE: test in *reverse* order so we hit the ones drawn on top first + location_t* pLocation = g_ptr_array_index(pLocationsArray, i); + + // bounding box test + if(pLocation->Coordinates.fLatitude < pRenderMetrics->rWorldBoundingBox.A.fLatitude + || pLocation->Coordinates.fLongitude < pRenderMetrics->rWorldBoundingBox.A.fLongitude + || pLocation->Coordinates.fLatitude > pRenderMetrics->rWorldBoundingBox.B.fLatitude + || pLocation->Coordinates.fLongitude > pRenderMetrics->rWorldBoundingBox.B.fLongitude) + { + continue; // not visible + } + + gdouble fX1 = SCALE_X(pRenderMetrics, pLocation->Coordinates.fLongitude); + gdouble fY1 = SCALE_Y(pRenderMetrics, pLocation->Coordinates.fLatitude); + gdouble fX2 = SCALE_X(pRenderMetrics, pHitPoint->fLongitude); + gdouble fY2 = SCALE_Y(pRenderMetrics, pHitPoint->fLatitude); + + gdouble fDeltaX = fX2 - fX1; + gdouble fDeltaY = fY2 - fY1; + + fDeltaX = abs(fDeltaX); + fDeltaY = abs(fDeltaY); + + if(fDeltaX <= 3 && fDeltaY <= 3) { + // fill out a new maphit_t struct with details + maphit_t* pHitStruct = g_new0(maphit_t, 1); + pHitStruct->eHitType = MAP_HITTYPE_LOCATION; + pHitStruct->LocationHit.nLocationID = pLocation->nID; + + pHitStruct->LocationHit.Coordinates.fLatitude = pLocation->Coordinates.fLatitude; + pHitStruct->LocationHit.Coordinates.fLongitude = pLocation->Coordinates.fLongitude; + + if(pLocation->pszName[0] == '\0') { + pHitStruct->pszText = g_strdup_printf("<i>unnamed POI %d</i>", pLocation->nID); + } + else { + pHitStruct->pszText = g_strdup(pLocation->pszName); + } + *ppReturnStruct = pHitStruct; + return TRUE; + } + } + return FALSE; +} + +static gboolean map_hittest_locationselections(map_t* pMap, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationSelectionArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct) +{ + screenpoint_t screenpoint; + screenpoint.nX = (gint)SCALE_X(pRenderMetrics, pHitPoint->fLongitude); + screenpoint.nY = (gint)SCALE_Y(pRenderMetrics, pHitPoint->fLatitude); + + gint i; + for(i=(pLocationSelectionArray->len-1) ; i>=0 ; i--) { + locationselection_t* pLocationSelection = g_ptr_array_index(pLocationSelectionArray, i); + + if(pLocationSelection->bVisible == FALSE) continue; + + if(map_math_screenpoint_in_screenrect(&screenpoint, &(pLocationSelection->InfoBoxRect))) { + // fill out a new maphit_t struct with details + maphit_t* pHitStruct = g_new0(maphit_t, 1); + + if(map_math_screenpoint_in_screenrect(&screenpoint, &(pLocationSelection->InfoBoxCloseRect))) { + pHitStruct->eHitType = MAP_HITTYPE_LOCATIONSELECTION_CLOSE; + pHitStruct->pszText = g_strdup("close"); + pHitStruct->LocationSelectionHit.nLocationID = pLocationSelection->nLocationID; + } + else if(map_math_screenpoint_in_screenrect(&screenpoint, &(pLocationSelection->EditRect))) { + pHitStruct->eHitType = MAP_HITTYPE_LOCATIONSELECTION_EDIT; + pHitStruct->pszText = g_strdup("edit"); + pHitStruct->LocationSelectionHit.nLocationID = pLocationSelection->nLocationID; + } + else { + gboolean bURLMatch = FALSE; + + gint iURL; + for(iURL=0 ; iURL<pLocationSelection->nNumURLs ; iURL++) { + if(map_math_screenpoint_in_screenrect(&screenpoint, &(pLocationSelection->aURLs[iURL].Rect))) { + pHitStruct->eHitType = MAP_HITTYPE_URL; + pHitStruct->pszText = g_strdup("click to open location"); + pHitStruct->URLHit.pszURL = g_strdup(pLocationSelection->aURLs[iURL].pszURL); + + bURLMatch = TRUE; + break; + } + } + + // no url match, just return a generic "hit the locationselection box" + if(!bURLMatch) { + pHitStruct->eHitType = MAP_HITTYPE_LOCATIONSELECTION; + pHitStruct->pszText = g_strdup(""); + pHitStruct->LocationSelectionHit.nLocationID = pLocationSelection->nLocationID; + } + } + *ppReturnStruct = pHitStruct; + return TRUE; + } + } + return FALSE; +} + +// Does the given point come close enough to the line segment to be considered a hit? +static gboolean map_hittest_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine) +{ + if(pHitPoint->fLatitude < (pPoint1->fLatitude - fMaxDistance) && pHitPoint->fLatitude < (pPoint2->fLatitude - fMaxDistance)) return FALSE; + if(pHitPoint->fLongitude < (pPoint1->fLongitude - fMaxDistance) && pHitPoint->fLongitude < (pPoint2->fLongitude - fMaxDistance)) return FALSE; + + // Some bad ASCII art demonstrating the situation: + // + // / (u) + // / | + // / | + // (0,0) =====(a)========== (v) + + // v is the translated-to-origin vector of line (road) + // u is the translated-to-origin vector of the hitpoint + // a is the closest point on v to the end of u (the hit point) + + // + // 1. Convert p1->p2 vector into a vector (v) that is assumed to come out of the origin (0,0) + // + mappoint_t v; + v.fLatitude = pPoint2->fLatitude - pPoint1->fLatitude; // 10->90 becomes 0->80 (just store 80) + v.fLongitude = pPoint2->fLongitude - pPoint1->fLongitude; + + gdouble fLengthV = sqrt((v.fLatitude*v.fLatitude) + (v.fLongitude*v.fLongitude)); + if(fLengthV == 0.0) return FALSE; // bad data: a line segment with no length? + + // + // 2. Make a unit vector out of v (meaning same direction but length=1) by dividing v by v's length + // + mappoint_t unitv; + unitv.fLatitude = v.fLatitude / fLengthV; + unitv.fLongitude = v.fLongitude / fLengthV; // unitv is now a unit (=1.0) length v + + // + // 3. Translate the hitpoint in the same way we translated v + // + mappoint_t u; + u.fLatitude = pHitPoint->fLatitude - pPoint1->fLatitude; + u.fLongitude = pHitPoint->fLongitude - pPoint1->fLongitude; + + // + // 4. Use the dot product of (unitv) and (u) to find (a), the point along (v) that is closest to (u). see diagram above. + // + gdouble fLengthAlongV = (unitv.fLatitude * u.fLatitude) + (unitv.fLongitude * u.fLongitude); + + // Does it fall along the length of the line *segment* v? (we know it falls along the infinite line v, but that does us no good.) + // (This produces false negatives on round/butt end caps, but that's better that a false positive when another line is actually there!) + if(fLengthAlongV > 0 && fLengthAlongV < fLengthV) { + mappoint_t a; + a.fLatitude = v.fLatitude * (fLengthAlongV / fLengthV); // multiply each component by the percentage + a.fLongitude = v.fLongitude * (fLengthAlongV / fLengthV); + // NOTE: (a) is *not* where it actually hit on the *map*. don't draw this point! we'd have to translate it back away from the origin. + + // + // 5. Calculate the distance from the end of (u) to (a). If it's less than the fMaxDistance, it's a hit. + // + gdouble fRise = u.fLatitude - a.fLatitude; + gdouble fRun = u.fLongitude - a.fLongitude; + gdouble fDistanceSquared = fRise*fRise + fRun*fRun; // compare squared distances. same results but without the sqrt. + + if(fDistanceSquared <= (fMaxDistance*fMaxDistance)) { + /* debug aids */ + /* g_print("pPoint1 (%f,%f)\n", pPoint1->fLatitude, pPoint1->fLongitude); */ + /* g_print("pPoint2 (%f,%f)\n", pPoint2->fLatitude, pPoint2->fLongitude); */ + /* g_print("pHitPoint (%f,%f)\n", pHitPoint->fLatitude, pHitPoint->fLongitude); */ + /* g_print("v (%f,%f)\n", v.fLatitude, v.fLongitude); */ + /* g_print("u (%f,%f)\n", u.fLatitude, u.fLongitude); */ + /* g_print("unitv (%f,%f)\n", unitv.fLatitude, unitv.fLongitude); */ + /* g_print("fDotProduct = %f\n", fDotProduct); */ + /* g_print("a (%f,%f)\n", a.fLatitude, a.fLongitude); */ + /* g_print("fDistance = %f\n", sqrt(fDistanceSquared)); */ + if(pReturnClosestPoint) { + pReturnClosestPoint->fLatitude = a.fLatitude + pPoint1->fLatitude; + pReturnClosestPoint->fLongitude = a.fLongitude + pPoint1->fLongitude; + } + + if(pfReturnPercentAlongLine) { + *pfReturnPercentAlongLine = (fLengthAlongV / fLengthV); + } + return TRUE; + } + } + return FALSE; +} diff --git a/src/map_hittest.h b/src/map_hittest.h new file mode 100644 index 0000000..e6dfda3 --- /dev/null +++ b/src/map_hittest.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * map_hittest.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 _MAP_HITTEST_H_ +#define _MAP_HITTEST_H_ + +#include "map.h" + +typedef enum { + MAP_HITTYPE_LOCATION, + MAP_HITTYPE_ROAD, + + // the following all use LocationSelectionHit in the union below + MAP_HITTYPE_LOCATIONSELECTION, // hit somewhere on a locationselection graphic (info balloon) + MAP_HITTYPE_LOCATIONSELECTION_CLOSE, // hit locationselection graphic close graphic (info balloon [X]) + MAP_HITTYPE_LOCATIONSELECTION_EDIT, // hit locationselection graphic edit graphic (info balloon "edit") + + MAP_HITTYPE_URL, +} EMapHitType; + +typedef struct { + EMapHitType eHitType; + gchar* pszText; + union { + struct { + gint nLocationID; + mappoint_t Coordinates; + } LocationHit; + + struct { + gint nRoadID; + mappoint_t ClosestPoint; + } RoadHit; + + struct { + gint nLocationID; + } LocationSelectionHit; + + struct { + gchar* pszURL; + } URLHit; + }; +} maphit_t; + +gboolean map_hittest(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct); +void map_hittest_maphit_free(map_t* pMap, maphit_t* pHitStruct); + +#endif diff --git a/src/map_style.c b/src/map_style.c index bcf4870..ac2457d 100644 --- a/src/map_style.c +++ b/src/map_style.c @@ -82,7 +82,7 @@ void map_style_load(map_t* pMap, const gchar* pszFileName) if(pMap->pLayersArray != NULL) { g_warning("reloading styles currently leaks memory so... don't do it very often :)\n"); - pMap->pLayersArray = NULL; + pMap->pLayersArray = NULL; // XXX: memory leak :) } pMap->pLayersArray = g_ptr_array_new(); |