Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix:#1218 #1219

Open
wants to merge 29 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
68afffb
Initial commit
OLFDB May 23, 2022
5a0288b
Merge branch 'navit-gps:trunk' into navitori
OLFDB May 23, 2022
e3cb9c2
Merge pull request #18 from navit-gps/trunk
OLFDB Jan 4, 2023
fd91e40
Fix:#1185
OLFDB Jan 5, 2023
be87cd3
Fix:#1185
OLFDB Jan 5, 2023
a2ffdea
Update after further tests
OLFDB Jan 7, 2023
31c48d4
Update navit.c
OLFDB Jan 7, 2023
90ff624
Update navit.c
OLFDB Jan 7, 2023
ae572cc
Revert "Fix:#1185"
OLFDB Jan 8, 2023
57cba4e
Revert "Fix:#1185"
OLFDB Jan 8, 2023
381e544
Merge trunk.
OLFDB Jan 11, 2023
64c5eab
merge trunk
OLFDB Jan 11, 2023
be53f3d
Merge branch 'navit-gps-trunk' into navitori
OLFDB Jan 11, 2023
34fcdb9
Taken from wiki and added UTM coordinate description
OLFDB Jan 14, 2023
ca0fd3c
Convinience Macro to get projection names in text
OLFDB Jan 14, 2023
7620dc4
Added SIZE enum member to calculate size of enum
OLFDB Jan 14, 2023
5d0bfe0
Changes to fix handling of UTM coordinates.
OLFDB Jan 14, 2023
223b8b3
Changed SIZE to projection_enumsize
OLFDB Jan 14, 2023
fb0afeb
Removed unneccessary macro PROJASSTRING
OLFDB Jan 21, 2023
90d36d7
Removed unneccessary enum value projection_enumsize
OLFDB Jan 21, 2023
7c2492a
Use dbg instead of printf again
OLFDB Jan 21, 2023
c187fda
Linked new file coordinates.rst
OLFDB Jan 21, 2023
d9c0f97
astyle
OLFDB Jan 21, 2023
4f64b74
Update after testing with all coordinate formats. Google Maps included.
OLFDB Jan 21, 2023
c3dba1b
Changed to rst format and added Google Maps coordinates description
OLFDB Jan 31, 2023
1167d94
Merge branch 'trunk' into bookmarkissue
OLFDB Dec 25, 2023
55f0c86
Revert "Merge branch 'trunk' into bookmarkissue"
OLFDB Dec 26, 2023
8a3fa0d
Fixes for testcases
OLFDB Dec 26, 2023
cf5587b
Fix for testcases
OLFDB Dec 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions docs/configuration/coordinates.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
## Coordinates in Navit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just happen now to see that you used markdown instead of reStructuredText which results in no headline found here and not format here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just updated coordinates.rst to be in rst format (at least I choose export reStructuredText in Typora to create it). Added some lines for Google Maps coordinates as well.


Various parts of Navit will read geographical coordinates provided as text:

- the [textfile](https://wiki.navit-project.org/index.php/Textfile) map format
- the "center=" attribute in the configuration file
- some Navit commands (e.g. set_position), which can be invoked via the [internal GUI](https://wiki.navit-project.org/index.php/Internal_GUI) or the [Dbus](https://wiki.navit-project.org/index.php/Dbus) bindings
- the files for bookmarks and last map position (bookmarks.txt and center.txt)

This page documents the coordinate systems and formats that Navit will accept.

## Supported coordinate systems and formats

### Longitude / Latitude in decimal degrees

Longitude / latitude in degrees can be specified as signed decimal fractions:

```
-33.3553 6.334
```

That would be about 33° West, 6° North. Note that in this format longitude comes first. The coordinates are assumed to be based on WGS84 (the coordinate system used by the GPS system, and by practically all common navigation systems).

### Latitude / Longitude in degrees and minutes

Latitude / Longitude can also be specified in degress and minutes with compass directions (N/S, E/W):

```
4808 N 1134 E
```

Latitude and longitude are multiplied by 100, so the position above corresponds to 48°8' N, 11°34' (Munich).

For greater precision you can write the minutes as decimal fractions:

```
4808.2356 N 1134.5252 E
```

That is 48°8.2356' N 11°34.5252' E, the center of the Marienplatz in Munich.

Notes:

- This format is rather unusual (because it uses arcminutes, but not arcseconds). It is probably easier to just use decimal fractions of degrees.
- The spaces are relevant for parsing. Use exactly one space between the number and the letter N/S/E/W.

### Cartesian coordinates

Internally, Navit uses a cartesian coordinate system induced by a Mercator projection. Coordinates are written as hexadecimal integers:

```
0x13a3d7 0x5d6d6d
```

or specifying a projection:

```
mg: 0x13a3d7 0x5d6d6d
```

That is again 48°8.2356' N 11°34.5252' E. The part up to and including the colon is optional, it names the projection to use. Possible values:

- mg - the projection used by Map&Guide (the default)
- garmin - "Garmin" projection (TODO: When would it be useful?)

This format is used internally by Navit, but is probably not very useful for other purposes.

### UTM coordinates

Navit can read coordinates in the [Universal Transverse Mercator coordinate system](http://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system) (UTM).

```
utm32U: 674499.306 5328063.675
```

```
utmref32UPU:74499.306 28063.675
```



## Development notes

The coordinates are parsed in function coord_parse() in coord.c. This code is used everywhere where Navit parses coordinates, except for the manual coordinate input in the Internal GUI (which uses its own format and parsing function).
254 changes: 128 additions & 126 deletions navit/coord.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
* @returns the coordinate
*/

int projection_enum_size[projection_enumsize];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

#define PROJASSTRING(x) (x==0?"projection_none":x==1?"projection_mg":x==2?"projection_garmin":x==3?"projection_screen":x==4?"projection_utm":"UNKNOWN")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this what projection_to_name is doing already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Removed the macro and used projection_to_name.

struct coord * coord_get(unsigned char **p) {
struct coord *ret=(struct coord *)(*p);
*p += sizeof(*ret);
Expand Down Expand Up @@ -132,11 +135,11 @@ void coord_rect_extend(struct coord_rect *r, struct coord *c) {
* Parses \c char \a *coord_input and writes back the coordinates to \c coord \a *result, using \c projection \a output_projection.
* \a *coord_input may specify its projection at the beginning.
* The format for \a *coord_input can be:
* \li [Proj:][-]0xXX.... [-]0xXX... - Mercator coordinates, hex integers (XX), Proj can be "mg" or "garmin", defaults to mg
* \li [Proj:][D][D]Dmm.mm.. N/S [D][D]DMM.mm... E/W - lat/long (WGS 84), integer degrees (DD) and minutes as decimal fraction (MM), Proj must be "geo" or absent
* \li [Proj:][-][D]D.d[d]... [-][D][D]D.d[d]... - long/lat (WGS 84, note order!), degrees as decimal fraction, Proj does not matter
* \li utm[zoneinfo]:[-][D]D.d[d]... [-][D][D]D.d[d] - UTM coordinates, as decimal fraction, with optional zone information (?)
* \li [-][D]D.d[d]...,[-][D][D]D.d[d]... - comma-separated (but without space inside the string) lat/long degrees as decimal fraction, Proj does not matter
* \li [Proj:][-]0xXX.... [-]0xXX... - Mercator coordinates, hex integers (XX), Proj can be "mg" or "garmin", defaults to mg
* \li [Proj:][D][D]Dmm.mm.. N/S [D][D]DMM.mm... E/W - lat/long (WGS 84), integer degrees (DD) and minutes as decimal fraction (MM), Proj must be "geo" or absent
* \li [Proj:][-][D]D.d[d]... [-][D][D]D.d[d]... - long/lat (WGS 84, note order!), degrees as decimal fraction, Proj does not matter
* \li utm[zoneinfo]:[-][D]D.d[d]... [-][D][D]D.d[d] - UTM coordinates, as decimal fraction, with optional zone information (?)
* \li [-][D]D.d[d]...,[-][D][D]D.d[d]... - comma-separated (but without space inside the string) lat/long degrees as decimal fraction, Proj does not matter
* Note that the spaces are relevant for parsing.
*
* @param *coord_input String to be parsed
Expand All @@ -145,126 +148,125 @@ void coord_rect_extend(struct coord_rect *r, struct coord *c) {
* @returns The lenght of the parsed string
*/

int coord_parse(const char *coord_input, enum projection output_projection, struct coord *result) {
char *proj=NULL,*s,*co;
const char *str=coord_input;
int args,ret = 0;
struct coord_geo g;
struct coord c,offset;
enum projection str_pro=projection_none;
int space_as_sep = 0;

dbg(lvl_debug,"enter('%s',%d,%p)", coord_input, output_projection, result);
s=strchr(str, ' ');
if (!s) {
space_as_sep = 1;
s=strchr(str, ',');
}
co=strchr(str,':');
if (co && co < s) {
proj=g_malloc(co-str+1);
g_strlcpy(proj, str, 1+co-str);
dbg(lvl_debug,"projection=%s", proj);
str=co+1;
s=strchr(str,space_as_sep?' ':',');
if (!strcmp(proj, "geo"))
str_pro = projection_none;
else {
str_pro = projection_from_name(proj,&offset);
if (str_pro == projection_none) {
dbg(lvl_error, "Unknown projection: %s", proj);
goto out;
}
}
}
if (! s) {
ret=0;
goto out;
}
while (*s == ' ') {
s++;
}
if (!space_as_sep && (!strncmp(s, "0x", 2) || !strncmp(s, "-0x", 3))) {
args=sscanf(str, "%i %i%n",&c.x, &c.y, &ret);
if (args < 2)
goto out;
dbg(lvl_debug,"str='%s' x=0x%x y=0x%x c=%d", str, c.x, c.y, ret);
dbg(lvl_debug,"rest='%s'", str+ret);

if (str_pro == projection_none)
str_pro=projection_mg;
if (str_pro != output_projection) {
transform_to_geo(str_pro, &c, &g);
transform_from_geo(output_projection, &g, &c);
}
*result=c;
} else if (!space_as_sep && (*s == 'N' || *s == 'n' || *s == 'S' || *s == 's')) {
double lng, lat;
char ns, ew;
dbg(lvl_debug,"str='%s'", str);
args=sscanf(str, "%lf %c %lf %c%n", &lat, &ns, &lng, &ew, &ret);
dbg(lvl_debug,"args=%d", args);
dbg(lvl_debug,"lat=%f %c lon=%f %c", lat, ns, lng, ew);
if (args < 4)
goto out;
dbg(lvl_debug,"projection=%d str_pro=%d projection_none=%d", output_projection, str_pro, projection_none);
if (str_pro == projection_none) {
g.lat=floor(lat/100);
lat-=g.lat*100;
g.lat+=lat/60;
g.lng=floor(lng/100);
lng-=g.lng*100;
g.lng+=lng/60;
if (ns == 's' || ns == 'S')
g.lat=-g.lat;
if (ew == 'w' || ew == 'W')
g.lng=-g.lng;
dbg(lvl_debug,"transform_from_geo(%f,%f)",g.lat,g.lng);
transform_from_geo(output_projection, &g, result);
dbg(lvl_debug,"result 0x%x,0x%x", result->x,result->y);
}
dbg(lvl_debug,"str='%s' x=%f ns=%c y=%f ew=%c c=%d", str, lng, ns, lat, ew, ret);
dbg(lvl_debug,"rest='%s'", str+ret);
} else if (!space_as_sep && (str_pro == projection_utm)) {
double x,y;
args=sscanf(str, "%lf %lf%n", &x, &y, &ret);
if (args < 2)
goto out;
c.x=x+offset.x;
c.y=y+offset.y;
if (str_pro != output_projection) {
transform_to_geo(str_pro, &c, &g);
transform_from_geo(output_projection, &g, &c);
}
*result=c;
} else if (space_as_sep) {
// When entering coords like google's format, we actually get strings like "52.5219,19.4127"
double lng, lat;
args=sscanf(str, "%lf,%lf%n", &lat, &lng, &ret);
if (args < 2)
goto out;
dbg(lvl_debug,"str='%s' x=%f y=%f c=%d", str, lng, lat, ret);
dbg(lvl_debug,"rest='%s'", str+ret);
g.lng=lng;
g.lat=lat;
transform_from_geo(output_projection, &g, result);
}
else {
double lng, lat;
args=sscanf(str, "%lf %lf%n", &lng, &lat, &ret);
if (args < 2)
goto out;
dbg(lvl_debug,"str='%s' x=%f y=%f c=%d", str, lng, lat, ret);
dbg(lvl_debug,"rest='%s'", str+ret);
g.lng=lng;
g.lat=lat;
transform_from_geo(output_projection, &g, result);
}
ret+=str-coord_input;
dbg(lvl_info, "ret=%d delta=%d ret_str='%s'", ret, GPOINTER_TO_INT(str-coord_input), coord_input+ret);
out:
g_free(proj);
return ret;
int coord_parse(const char *coord_input, enum projection output_projection, struct coord *result) {
char *proj = NULL, *s = NULL, *co;
const char *str = coord_input;
int args, ret = 0;
struct coord_geo g;
struct coord c, offset;
enum projection str_pro = projection_none;
int space_as_sep = 0;

dbg(lvl_debug, "enter('%s',%s,%p)\n", coord_input,
PROJASSTRING(output_projection), result);
co = strchr(str, ':');
if (co)
s = strstr(str, ": ");
if (s) {
space_as_sep = 1;
}
if (co) {
proj = g_malloc(co - str + 1);
g_strlcpy(proj, str, 1 + co - str);
dbg(lvl_debug, "projection=%s\n", proj);
str = co + 1;
if (space_as_sep)
str++;
s = (char*) str;
if (!strcmp(proj, "geo"))
str_pro = projection_none;
else {
str_pro = projection_from_name(proj, &offset);
if (str_pro == projection_none) {
dbg(lvl_debug, "Unknown projection: %s\n", proj);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why change from error to debug? error seems to be fitting here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to error again.

goto out;
}
}
} else {
s = (char*) str;
}
if ((!strncmp(s, "0x", 2) || !strncmp(s, "-0x", 3))) {
args = sscanf(str, "%i %i%n", &c.x, &c.y, &ret);
if (args < 2)
goto out;
dbg(lvl_debug, "str='%s' x=0x%x y=0x%x c=%d\n", str, c.x, c.y, ret);
dbg(lvl_debug, "rest='%s'\n", str + ret);

if (str_pro == projection_none)
str_pro = projection_mg;
if (str_pro != output_projection) {
transform_to_geo(str_pro, &c, &g);
transform_from_geo(output_projection, &g, &c);
}
*result = c;
} else if ((*s == 'N' || *s == 'n' || *s == 'S' || *s == 's')) {
double lng, lat;
char ns, ew;
dbg(lvl_debug, "str='%s'\n", str);
args = sscanf(str, "%lf %c %lf %c%n", &lat, &ns, &lng, &ew, &ret);
dbg(lvl_debug, "args=%d\n", args);
dbg(lvl_debug, "lat=%f %c lon=%f %c\n", lat, ns, lng, ew);
if (args < 4)
goto out;
dbg(lvl_debug, "projection=%s str_pro=%d projection_none=%d\n",
PROJASSTRING(output_projection), str_pro, projection_none);
if (str_pro == projection_none) {
g.lat = floor(lat / 100);
lat -= g.lat * 100;
g.lat += lat / 60;
g.lng = floor(lng / 100);
lng -= g.lng * 100;
g.lng += lng / 60;
if (ns == 's' || ns == 'S')
g.lat = -g.lat;
if (ew == 'w' || ew == 'W')
g.lng = -g.lng;
dbg(lvl_debug, "transform_from_geo(%f,%f)\n", g.lat, g.lng);
transform_from_geo(output_projection, &g, result);
dbg(lvl_debug, "result 0x%x,0x%x\n", result->x, result->y);
}
dbg(lvl_debug, "str='%s' x=%f ns=%c y=%f ew=%c c=%d\n", str, lng, ns,
lat, ew, ret);
dbg(lvl_debug, "rest='%s'\n", str + ret);
} else if (str_pro == projection_utm) {
double x, y;
args = sscanf(str, "%lf %lf%n", &x, &y, &ret);
if (args < 2)
goto out;
c.x = x + offset.x;
c.y = y + offset.y;
if (str_pro != output_projection) {
transform_to_geo(str_pro, &c, &g);
transform_from_geo(output_projection, &g, &c);
}
*result = c;
} else if (!space_as_sep) {
// When entering coords like google's format, we actually get strings like "52.5219,19.4127"
double lng, lat;
args = sscanf(str, "%lf,%lf%n", &lat, &lng, &ret);
if (args < 2)
goto out;
dbg(lvl_debug, "str='%s' x=%f y=%f c=%d\n", str, lng, lat, ret);
dbg(lvl_debug, "rest='%s'\n", str + ret);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why all the line returns? dbg should add those itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is original code. It is shown here as there were spaces inserted by eclipse formatter.

g.lng = lng;
g.lat = lat;
transform_from_geo(output_projection, &g, result);
} else {
double lng, lat;
args = sscanf(str, "%lf %lf%n", &lng, &lat, &ret);
if (args < 2)
goto out;
dbg(lvl_debug, "str='%s' x=%f y=%f c=%d\n", str, lng, lat, ret);
dbg(lvl_debug, "rest='%s'\n", str + ret);
g.lng = lng;
g.lat = lat;
transform_from_geo(output_projection, &g, result);
}
ret += str - coord_input;
dbg(lvl_debug, "ret=%d delta=%d ret_str='%s'\n", ret,
GPOINTER_TO_INT(str - coord_input), coord_input + ret);
out: g_free(proj);
return ret;
}

/**
Expand Down Expand Up @@ -300,7 +302,7 @@ void coord_print(enum projection pro, struct coord *c, FILE *out) {
} else {
y = c->y;
}
fprintf( out, "%s: %s0x%x %s0x%x\n",
fprintf( out, "%s:%s0x%x %s0x%x\n",
projection_to_name( pro ),
sign_x, x,
sign_y, y );
Expand Down
Loading