sauce4zwift
sauce4zwift copied to clipboard
X and Y in state - how to convert to latitude / longitude
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!
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.
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
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.
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 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
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)
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.
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)
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
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)
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 |
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
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)
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
E.g.
<!-- JAPAN -->
<latDegDist>110614.710938</latDegDist>
<lonDegDist>109287.523438</lonDegDist>
<latOffset>-10.749806</latOffset>
<lonOffset>165.836441</lonOffset>
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.
MVP as of dffa332744ee2faaec5b06d932c678bb3923a808