sauce4zwift icon indicating copy to clipboard operation
sauce4zwift copied to clipboard

X and Y in state - how to convert to latitude / longitude

Open stuartlynne opened this issue 2 years ago • 13 comments

I'm assuming from the comments in various files that x and y in the state record (from web server event stream) are a coordinate position.

Can you provide some details on how to convert that to latitude/longitude?

Thanks!

stuartlynne avatar Sep 26 '22 17:09 stuartlynne

This is currently unknown to me. I'm not doing any correlation between x/y and mapping information presently. At some point I would like to know the answer though, especially if I can find a good source of maps and topo info.

mayfield avatar Sep 26 '22 20:09 mayfield

This shows how to map latitude/longitude to X/Y for the first 7 worlds.

https://github.com/Ogadai/zwift-mobile-api/blob/master/src/mapLatLong.js

stuartlynne avatar Oct 01 '22 20:10 stuartlynne

I'm assuming from the comments in various files that x and y in the state record (from web server event stream) are a coordinate position.

Can you provide some details on how to convert that to latitude/longitude?

Thanks!

@stuartlynne what are you wanting to do with the lat/longs? I am not a dev, but spent 15 years working with geocoded address data and complementary map layers in a previous life. I may (or may not) be able to assist.

Jason-The-Shepherd avatar Oct 14 '22 00:10 Jason-The-Shepherd

I am working on a separate application that captures additional ANT+ and BLE sensor data (e.g. Moxy MO2, VO2Master, etc) to generate an alternate FIT file with the combined data for a workout.

Sauce lets me add speed, distance and hopefully latitude / longitude.

More specifically, all the data that Zwift puts in their FIT file, but with additional data from all available sensors.

And at this point lat/long is the only thing I'm missing. And it appears to be tantalizingly close with the X/Y position data.

On Thu, Oct 13, 2022 at 5:52 PM Jason-The-Shepherd @.***> wrote:

I'm assuming from the comments in various files that x and y in the state record (from web server event stream) are a coordinate position.

Can you provide some details on how to convert that to latitude/longitude?

Thanks!

@stuartlynne https://github.com/stuartlynne what are you wanting to do with the lat/longs? I am not a dev, but spent 15 years working with geocoded address data and complementary map layers in a previous life. I may (or may not) be able to assist.

— Reply to this email directly, view it on GitHub https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1278336196, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACIUWMUXI4EBJ6I3TVAO53WDCVD5ANCNFSM6AAAAAAQV746ZU . You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

stuartlynne avatar Oct 14 '22 07:10 stuartlynne

@stuartlynne the maths for this is not within my experience, but I understand what you are trying to achieve. I found the following links which describe the equation, some examples of code that may or may not be useful and lastly, an Australian Government tool for validating conversions where the coordinate is within Australian territory. https://sciencing.com/convert-xy-coordinates-longitude-latitude-8449009.html

https://gis.stackexchange.com/questions/221882/formula-to-convert-x-y-to-long-lat-coordinates-of-given-point

https://geodesyapps.ga.gov.au/grid-to-geographic

Hope this helps

Jason-The-Shepherd avatar Oct 16 '22 23:10 Jason-The-Shepherd

Thanks, I'll check it out.

Part of the issue will be getting the x/y origin and scale for each of the dozen Zwift worlds.

On Sun, Oct 16, 2022 at 4:34 PM Jason-The-Shepherd @.***> wrote:

@stuartlynne https://github.com/stuartlynne the maths for this is not within my experience, but I understand what you are trying to achieve. I found the following links which describe the equation, some examples of code that may or may not be useful and lastly, an Australian Government tool for validating conversions where the coordinate is within Australian territory.

https://sciencing.com/convert-xy-coordinates-longitude-latitude-8449009.html

https://gis.stackexchange.com/questions/221882/formula-to-convert-x-y-to-long-lat-coordinates-of-given-point

https://geodesyapps.ga.gov.au/grid-to-geographic

Hope this helps

— Reply to this email directly, view it on GitHub https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1280094561, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACIUWL2GXLPEFH5PSKFPVLWDSGIPANCNFSM6AAAAAAQV746ZU . You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

stuartlynne avatar Oct 17 '22 08:10 stuartlynne

As @stuartlynne notes, the old zwift mobile api project has the conversion for the many world. I discovered that after I calculated the same conversion. You can calculate the conversion by riding a course, recording the x/y and then getting the lat/lon from the fit file. You can use numerical methods or manually get really close.

It seems to be a linear scale with offset. long = a + bX and lat = m + nY Start with a guess to get the numbers similar to the fit file. Map both points sets of points (x/y, lat/lon), using any mapping tool. Then keep start adjusting the scale and offset till the course overlaps.

vincentdavis avatar Nov 12 '22 12:11 vincentdavis

I did some of that manually. Didn't think of doing an entire ride :-)

We can capture S4Z data as timestamp, x, y, to a csv (or fit) file, then do a python script to extract and match timestamps to get two pairs (x,y) (lat, long) each point.

The script run until the map(x,y) does not match the (lat,long) point, and then display the deviation.

On Sat, Nov 12, 2022 at 4:55 AM Vincent @.***> wrote:

As @stuartlynne https://github.com/stuartlynne notes, the old zwift mobile api project has the conversion for the many world. I discovered that after I calculated the same conversion. You can calculate the conversion by riding a course, recording the x/y and then getting the lat/lon from the fit file. You can use numerical methods or manually get really close.

It seems to be a linear scale with offset. long = a + bX and lat = m + nY Start with a guess to get the numbers similar to the fit file. Map both points sets of points (x/y, lat/lon), using any mapping tool. Then keep start adjusting the scale and offset till the course overlaps.

— Reply to this email directly, view it on GitHub https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312473139, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACIUWJVGD5W3BYFFLQT4BLWH6HU5ANCNFSM6AAAAAAQV746ZU . You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

stuartlynne avatar Nov 13 '22 02:11 stuartlynne

The pit file on your computer is time stamped with your computer time. And this could be so he’ll seconds different then split time. It even creates a situation where you can’t compare to peoples files or event because the computer times are not correct.

On Sat, Nov 12, 2022 at 7:36 PM Stuart Lynne @.***> wrote:

I did some of that manually. Didn't think of doing an entire ride :-)

We can capture S4Z data as timestamp, x, y, to a csv (or fit) file, then do a python script to extract and match timestamps to get two pairs (x,y) (lat, long) each point.

The script run until the map(x,y) does not match the (lat,long) point, and then display the deviation.

On Sat, Nov 12, 2022 at 4:55 AM Vincent @.***> wrote:

As @stuartlynne https://github.com/stuartlynne notes, the old zwift mobile api project has the conversion for the many world. I discovered that after I calculated the same conversion. You can calculate the conversion by riding a course, recording the x/y and then getting the lat/lon from the fit file. You can use numerical methods or manually get really close.

It seems to be a linear scale with offset. long = a + bX and lat = m + nY Start with a guess to get the numbers similar to the fit file. Map both points sets of points (x/y, lat/lon), using any mapping tool. Then keep start adjusting the scale and offset till the course overlaps.

— Reply to this email directly, view it on GitHub < https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312473139>, or unsubscribe < https://github.com/notifications/unsubscribe-auth/AACIUWJVGD5W3BYFFLQT4BLWH6HU5ANCNFSM6AAAAAAQV746ZU

. You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

— Reply to this email directly, view it on GitHub https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312623275, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABYY5ALNTEN4H4BBOUTQJDWIBHZJANCNFSM6AAAAAAQV746ZU . You are receiving this because you commented.Message ID: @.***>

-- Sent from mobile app. Vincent Davis 720-301-3003

vincentdavis avatar Nov 13 '22 02:11 vincentdavis

The S4Z capture will be on the same computer, and it is (I think) giving us timestamps from the Zwift app. Should match.

We may also be able to use altitude as a second way to match.

On Sat, Nov 12, 2022 at 6:42 PM Vincent @.***> wrote:

The pit file on your computer is time stamped with your computer time. And this could be so he’ll seconds different then split time. It even creates a situation where you can’t compare to peoples files or event because the computer times are not correct.

On Sat, Nov 12, 2022 at 7:36 PM Stuart Lynne @.***> wrote:

I did some of that manually. Didn't think of doing an entire ride :-)

We can capture S4Z data as timestamp, x, y, to a csv (or fit) file, then do a python script to extract and match timestamps to get two pairs (x,y) (lat, long) each point.

The script run until the map(x,y) does not match the (lat,long) point, and then display the deviation.

On Sat, Nov 12, 2022 at 4:55 AM Vincent @.***> wrote:

As @stuartlynne https://github.com/stuartlynne notes, the old zwift mobile api project has the conversion for the many world. I discovered that after I calculated the same conversion. You can calculate the conversion by riding a course, recording the x/y and then getting the lat/lon from the fit file. You can use numerical methods or manually get really close.

It seems to be a linear scale with offset. long = a + bX and lat = m + nY Start with a guess to get the numbers similar to the fit file. Map both points sets of points (x/y, lat/lon), using any mapping tool. Then keep start adjusting the scale and offset till the course overlaps.

— Reply to this email directly, view it on GitHub < https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312473139 , or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AACIUWJVGD5W3BYFFLQT4BLWH6HU5ANCNFSM6AAAAAAQV746ZU

. You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

— Reply to this email directly, view it on GitHub < https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312623275>, or unsubscribe < https://github.com/notifications/unsubscribe-auth/AABYY5ALNTEN4H4BBOUTQJDWIBHZJANCNFSM6AAAAAAQV746ZU

. You are receiving this because you commented.Message ID: @.***>

-- Sent from mobile app. Vincent Davis 720-301-3003

— Reply to this email directly, view it on GitHub https://github.com/SauceLLC/sauce4zwift/issues/8#issuecomment-1312624108, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACIUWIYRXZLPTDSJHCR5WTWIBIP3ANCNFSM6AAAAAAQV746ZU . You are receiving this because you were mentioned.Message ID: @.***>

-- O_ -<,_____ ()/(_)______


@.***>____604-518-1749(m)__604-461-7532(h)

stuartlynne avatar Nov 14 '22 03:11 stuartlynne

I have verified that we can match data captured from S4Z to data extracted from the Zwift-generated FIT file.

The timestamps appear to be out by one. The timestamp from S4Z (from worldTime + worldTimeOffset) is one less than the timestamp from the FIT file.

As a quick test, I generated the distance between the first and current points from S4Z x,y and the FIT lat,long and compared those. That shows a close match, generally to about a 1-3% difference.

The S4Z x,y distance was computed with: math.dist(first_xy, this_xy)/100.

The FIT lat, long distance was computed with the: haversine(first_loc, this_loc, unit=haversine.Unit.METERS)

This would suggest that determining the latitude, and longitude of the point x,y=0,0, would get us most of the way to convert them.

Then we need to determine the source of the slight 1-3% difference.

FIT S4Z % Diff
1030.46044 1022.284833 0.793
1033.856213 1023.524147 0.999
1034.233899 1022.401268 1.144
1033.666661 1015.70748 1.737
1027.056138 1004.239435 2.222
1015.236837 991.3481574 2.353
1002.040622 978.3476357 2.364
988.840838 965.0268788 2.408
975.7636398 951.8437333 2.451
962.1864709 938.4526842 2.467
949.1126397 925.6362625 2.474
936.2988395 914.1602359 2.364
924.9125541 903.8226472 2.28
914.3380965 894.3394418 2.187

stuartlynne avatar Nov 17 '22 19:11 stuartlynne

I added code to compute estimated zero x,y points by subtracting x,y to the FIT lat, long.

Averaged over a few thousand points we get this as the suggested latitude/longitude for the zero X/Y point in Watopia.

11.65532509, 167.6785151

stuartlynne avatar Nov 17 '22 20:11 stuartlynne

The RoadCaptain app has the required constants to do the X/Y conversions. I have done a small python app to test and asked for permission to publish that. See RoadCaptain issue 110

Worlds = {
    1:  ( -128809769.40541935, 9.040388931996475E-06,  1824587167.6433601, 9.15017561017031E-06),   # Watopia
    2:  (  416681564.4970093,  9.0099976736186E-06,   -684350551.7311095,  1.1315458228533332E-05), # Richmond
    3:  (  572999216.4279556,  8.988093472576876E-06, -1165514.8567129374, 1.4409163767062611E-05), # London
    4:  (  451904755.49697876, 9.021199819576003E-06, -624888323.3413696,  1.1838382403428395E-05), # New York
    5:  (  525815359.3559265,  8.990380293086398E-06,  85498815.16199112,  1.3328535060711476E-05), # Innsbruck
    6:  (  494915327.2666931,  8.990380293086398E-06,  89998398.77214432,  1.2603824000201662E-05), # Bologna
    7:  (  600543305.7785034,  8.990380293086398E-06, -10081972.491562366, 1.529215665285275E-05),  # Yorkshire
    8:  ( -114866743.52011015, 9.040388931996475E-06,  1811999121.6374512, 9.15017561017031E-06),   # Crit City
    9:  ( -118908671.79471876, 9.040388931996475E-06,  1812385336.6892092, 9.15017561017031E-06),   # Makuri Islands
    10: ( -240220877.27394104, 9.031302494445749E-06,  1719827819.2077637, 9.663609744784066E-06),  # France
    11: (  543554648.5443115,  8.990380293086398E-06,  16931795.4672575,   1.366736370221548E-05),  # Paris
}

def xyToLatLong(worldId, x, y):
    world = Worlds[ZwiftXY.course2world[worldId]]
    latitude = (x + world[0]) * world[1] * 0.01
    longitude = (y + world[2]) * world[3] * 0.01
    return round(latitude, 7), round(longitude, 7)

stuartlynne avatar Nov 18 '22 02:11 stuartlynne

This shows how to map latitude/longitude to X/Y for the first 7 worlds.

https://github.com/Ogadai/zwift-mobile-api/blob/master/src/mapLatLong.js

You can find the constants for the other maps from the file Zwift\assets\Worlds\worlds.wad\Worlds\worldlist.xml

worldlist.zip

E.g.

        <!-- JAPAN -->
        <latDegDist>110614.710938</latDegDist>
        <lonDegDist>109287.523438</lonDegDist>
        <latOffset>-10.749806</latOffset>
        <lonOffset>165.836441</lonOffset>

oldnapalm avatar Jan 06 '23 00:01 oldnapalm

Thanks for the tip @oldnapalm I updated my build tool that extracts client artifacts to bring in the data from that worldlist.xml file and incorporated the required conversions. Next release will have a latlng tuple in the playerstate data.

mayfield avatar Jan 11 '23 07:01 mayfield

MVP as of dffa332744ee2faaec5b06d932c678bb3923a808

mayfield avatar Jan 19 '23 19:01 mayfield