aurora-opensource / xviz

A protocol for real-time transfer and visualization of autonomy data
http://xviz.io
Apache License 2.0
1.01k stars 228 forks source link

Rotating a GEOGRAPHIC polygon primitive #409

Open gerardsimons opened 5 years ago

gerardsimons commented 5 years ago

Hi there,

I am looking for the most easy way of rotating some of my polygons. I have live data coming in from which I can derive a bounding box (polygon primitive) and some other piece of data that tells me it's heading. What would be the best way to transform it. I am aware of a transform matrix for the meta, but this does not seem to convenient, as different primitives would have different transformations.

I am dabbling now in my own rotation scripts where I convert each coordinate to Cartesian coordinates using geodes, rotate and convert back, find relevant parts here:

const LatLon = require('geodesy').LatLonEllipsoidal;

// pt is some point in lon, lat XVIZ format, part of a series of points that make a bounding box, origin is the center of these points

// This uses LatLon.datum.WGS84 as a datum by default
var ptLatLong = new LatLon(pt[1], pt[0]);

var p = ptLatLong.toCartesian();

var xd = (p.x - origin.x);
var yd = (p.y - origin.y);
var rotatedX = xd * Math.cos(angle) - yd * Math.sin(angle);
var rotatedY = yd * Math.cos(angle) + xd * Math.sin(angle);

p = new Vec3d(rotatedX + origin.x, rotatedY + origin.y, p.z);

// Perhaps I need to use a different datum?
var back = p.toLatLonE(ll.datum);

This causes shearing (see screenshot). Any advice on what would be the best approach would be very much appreciated. in general having to use this external library is probably not the way to go?

Screenshot 2019-03-14 at 10 28 50
Algirdyz commented 5 years ago

Made it work fine with this:

getGeoCoordinatesForMesh(lon, lat, angle, vertices){
        var rotated = new Array();
        for(var i in vertices) {
            var v = vertices[i];
            var bearing = Math.atan2(v[0], v[1]) + toRadians(angle); 
            var distance = Math.sqrt(v[0] * v[0] + v[1] * v[1]);
            var lat1 = toRadians(lat);    
            var lon1 = toRadians(lon);    
            var centralAngle = distance / earthRadius;
            var lat2 = Math.asin( Math.sin(lat1)*Math.cos(centralAngle) + Math.cos(lat1)*Math.sin(centralAngle)*Math.cos(bearing));    
            var lon2 = lon1+ Math.atan2(Math.sin(bearing)*Math.sin(centralAngle)*Math.cos(lat1),Math.cos(centralAngle)-Math.sin(lat1)*Math.sin(lat2));

            rotated.push([toDegrees(lon2), toDegrees(lat2), v[2]]);            
        }
        return rotated;
    }

Basically instead using a rotation matrix I get an angle and distance for each vertex from origin and use some math to get the coordinates for it when adding a desired angle.

vertices passed into this should have origin as 0,0,0 angle is in degrees lon/lat are for the desired origin after transformation

twojtasz commented 5 years ago

@gerardsimons I'm trying to understand this more precisely.

We have support for defining a custom transform at runtime using the DYNAMIC coordinate and the transform_callback. I'm actually not 100% we have this tested ;( But is this the part you are saying seems inconvenient?

https://github.com/uber/xviz/blob/master/docs/protocol-schema/session-protocol.md#stream_metadata

It looks like you have a work around from the above which is great. But I'll keep this open so I can dig into this and get an example of the DYNAMIC transform to validate and see if that would fit this case.

Algirdyz commented 5 years ago

@twojtasz How does DYNAMIC coordinate work? I could not find much documentation or examples on how to use it.