I have 4 Lat Lon positions. They represent a (rotated) rectangular region. But due to some calculation errors, sometimes they are not proper rectangular.
I want to convert those into (rotated) rectangular regions.
See Image for more clarification
In the above image I want the lat lon of the corners of the rectangle drawn given 4 lat lon as shown on the left side.
I tried searching but couldn't find any solution. Most of the solutions did not take care of rotated rectangle case.
How do I solve this problem ?
Note : Are there any libraries that does this, I am using JavaScript for implementation.
Note : I don't know if my question is more related to math.
Note : This is the particular solution that I used. It may not be perfect but it works.
Algorithm :
Calculate the distance between 1, 3 and 1, 2 lat lon from the image. This would give you 2 distances.
Find the coordinates along which the distance is greater. (In here lets consider the distance between 1 and 3 is greater.)
Find the bearing between those considered coordinates
Consider any coordinate as origin. (I choose coordinates of 3 as the origin for my case).
Rotate all points 1,2,3,4 along the origin with rotation angle as bearing. Here the rotation makes the considered points (here 1 and 3) to be parallel to the x axis.
Now you get 4 new coordinates. Find the minimum and maximum x and y from those 4 coordinates (consider them to be minX, minY, maxX, maxY).
The (minX, minY) gives you the top left coordinates of the rectangle and (maxX, maxY) gives you the bottom right coordinates of the rectangle. Using this information you can find the other two coordinates.
Now rotate these 4 new coordinates along the same origin but with rotation angle as -bearing. These are the vertices of the dotted rectangle in the image.
Note : This may not be perfect as I have not considered the earth radius and other complications associated with latitude, longitudes. But in my case the lat lon were pretty close to each other, and I wasn't interested in accuracy.
Hope some of us find it useful.
Related
TLDR; Given a set of triangle vertices and a normal vector (all in unit space), how do I calculate X, Y, Z Euler rotation angles of the triangle in world space?
I am attemping to display a 3D model in HTML - with actual HTML tags and CSS transforms. I've already loaded an OBJ file into a Javascript class instance.
The model is triangulated. My first aim is just to display the triangles as planes (HTML elements are rectangular) - I'll be 'cutting out' the triangle shapes with CSS clip-path later on.
I am really struggling to understand and get the triangles of the model rotated correctly.
I thought a rotation matrix could help me out, but my only experience with those is where I already have the rotation vector and I need to convert and send that to WebGL. This time there is no WebGL (or tutorials) to make things easier.
The following excerpt shows the face creation/'rendering' of faces. I'm using the face normal as the rotation but I know this is wrong.
for (const face of _obj.faces) {
const vertices = face.vertices.map(_index => _obj.vertices[_index]);
const center = [
(vertices[0][0] + vertices[1][0] + vertices[2][0]) / 3,
(vertices[0][1] + vertices[1][1] + vertices[2][1]) / 3,
(vertices[0][2] + vertices[1][2] + vertices[2][2]) / 3
];
// Each vertex has a normal but I am just picking the first vertex' normal
// to use as the 'face normal'.
const normals = face.normals.map(_index => _obj.normals[_index]);
const normal = normals[0];
// HTML element creation code goes here; reference is 'element'.
// Set face position (unit space)
element.style.setProperty('--posX', center[0]);
element.style.setProperty('--posY', center[1]);
element.style.setProperty('--posZ', center[2]);
// Set face rotation, converting to degrees also.
const rotation = [
normal[0] * toDeg,
normal[1] * toDeg,
normal[2] * toDeg,
];
element.style.setProperty('--rotX', rotation[0]);
element.style.setProperty('--rotY', rotation[1]);
element.style.setProperty('--rotZ', rotation[2]);
}
The CSS first translates the face on X,Y,Z, then rotates it on X,Y,Z in that order.
I think I need to 'decompose' my triangles' rotation into separate axis rotations - i.e rotate on X, then on Y, then on Z to get the correct rotation as per the model face.
I realise that the normal vector gives me an orientation but not a rotation around itself - I need to calculate that. I think I have to determine a vector along one triangle side and cross it with the normal, but this is something I am not clear on.
I have spent hours looking at similar questions on SO but I'm not smart enough to understand or make them work for me.
Is it possible to describe what steps to take without Latex equations? I'm good with pseudo code but my Math skills are severely lacking.
The full code is here: https://whoshotdk.co.uk/cssfps/ (view HTML source)
The mesh building function is at line 422.
The OBJ file is here: https://whoshotdk.co.uk/cssfps/data/model/test.obj
The Blender file is here: https://whoshotdk.co.uk/cssfps/data/model/test.blend
The mesh is just a single plane at an angle, displayed in my example (wrongly) in pink.
The world is setup so that -X is left, -Y is up, -Z is into the screen.
Thank You!
If you have a plane and want to rotate it to be in the same direction as some normal, you need to figure out the angles between that plane's normal vector and the normal vector you want. The Euler angles between two 3D vectors can be complicated, but in this case the initial plane normal should always be the same, so I'll assume the plane normal starts pointing towards positive X to make the maths simpler.
You also probably want to rotate before you translate, so that everything is easier since you'll be rotating around the origin of the coordinate system.
By taking the general 3D rotation matrix (all three 3D rotation matrices multiplied together, you can find it on the Wikipedia page) and applying it to the vector (1,0,0) you can then get the equations for the three angles a, b, and c needed to rotate that initial vector to the vector (x,y,z). This results in:
x = cos(a)*cos(b)
y = sin(a)*cos(b)
z = -sin(b)
Then rearranging these equations to find a, b and c, which will be the three angles you need (the three values of the rotation array, respectively):
a = atan(y/x)
b = asin(-z)
c = 0
So in your code this would look like:
const rotation = [
Math.atan2(normal[1], normal[0]) * toDeg,
Math.asin(-normal[2]) * toDeg,
0
];
It may be that you need to use a different rotation matrix (if the order of the rotations is not what you expected) or a different starting vector (although you can just use this method and then do an extra 90 degree rotation if each plane actually starts in the positive Y direction, for example).
I'd like get the points of a triangle around a point where the face would point in the direction of a specified normal. I'll be using THREE.js to add them to a BufferGeometry.
Very crude drawing:
Here's the code I have so far:
//The XYZ location of a point:
var x = model.points[i*3];
var y = model.points[i*3+1];
var z = model.points[i*3+2];
//The normal vector direction:
var nx = model.normals[i*3];
var ny = model.normals[i*3+1];
var nz = model.normals[i*3+2];
How can I pick 3 more points around this point that are all perpendicular to the normal and the same distance from the point / each other?
THANKS!
1) Take cross product of the normal with an arbitrary non-parallel vector. This will get you a vector perpendicular to the normal vector.
1.5) Normalize and scale the perpendicular vector to desired size. The length of this vector will be the distance from the triangle's centroid to each of its vertices.
2) Rotate the perpendicular vector by 2PI/3 and 4PI/3 around the normal vector.
3) Add the 3 vectors to the center point.
Note that there are infinitely many triangles that fit your criteria, even if we limit to only equilateral triangles. This is because there is an entire plane which is perpendicular to the given vector <nx, ny, nz> through the given point (x, y, z). Read here to see how to derive the equation for that plane. From there, you will need to pick a point on the plane. Then you can calculate the other two points by rotating around the given point at (x, y, z).
You need to find the plane parallel to the normal and containing the point (there is only one) and then pick any point in this plane with the specified distance and rotate it two times by 120 degree around the centeral point.
Currently I am trying to understand a Codpen where this guy has JSON data being fed into a Javascript app that plots coordinates using x and y.
Instead of using longitude and latitude to plot for example Hong Kong, he uses these coordinates.
{"x": 768,"y": 342,"name": "", "country":"Hong Kong"}
I want to be able to put in x and y a longitude and latitude value, but I can not figure out how to multiply or divide, a simple solution to go with his code. I am new to Javascript, but am trying to understand how to plot coordinates more efficiently on this specific project.
Is there a simple equation I could use to be able to plot more easily on this pen.
Thanks.
https://codepen.io/Flamov/pen/MozgXb
The example is basically using the Mercator Projection to convert radius, lat, long into euclidean x, y, z coordinates, as mentioned on lines 860+ of the JSFiddle you provided, and is using this S.O. answer as reference. Since radius is constant throughout the globe, you don't need to repeat that value for each point, it's just hard-coded into the example.
Mercator is a bit confusing because the scale stretches towards infinity as you approach the poles. As an easier alternative, you could use Vector3.setFromSphericalCoords(rad, lat, long) as outlined in the docs and it sets x, y, z for you. The main difference is that this approach doesn't cause distortion near the poles. It takes lat, long in radians:
lat ranges from [0, Pi] (north pole to south pole)
long ranges from [0, 2*Pi] (around the equator)
I've implemented some code to create some code to treat an image of a relatively small location like plane for converting between locations on the image I have stored and incoming Lat/Long information.
Using the formulas provided at https://msdn.microsoft.com/en-us/library/jj635757(v=vs.85).aspx I wrote these lines of code among others
var vector = math.matrix(
[[x1],
[y1],
[x2],
[y2]]);
var matrix = math.matrix(
[[lat1,long1,1,0]
,[-long1,lat1,0,1]
,[lat2,long2,1,0]
,[-long2,lat2,0,1]]);
var solution = math.multiply(math.inv(matrix),vector);
There is an implicit conversion from the vector returned to solution into conversiondata as I put it into and take it back out of my database.
a = parseFloat(conversiondata['A']);
b = parseFloat(conversiondata['B']);
c = parseFloat(conversiondata['C']);
d = parseFloat(conversiondata['D']);
var long = position.coords.longitude;
var lat = position.coords.latitude;
var x = a * lat + b * long + c;
var y = b * lat - a * long + d;
The values x1, x2, y1, y2 are supplied by getting user click data.
The values lat1, lat2, long1, long2 are supplied by the user in response to two clicks on the map image.
When putting x,y back onto the map its not quite in the right position, the position on the map seems to almost be on the opposite side of the line defined by (x1,y1) and (x2,y2). I'm trying to tell what the reason for the inaccuracy is. (I am however assuming for the time being that the apparent reflection is a coincidence)
If someone could help me narrow down what could be going wrong here are things I've considered (the map doesn't reach even a mile in any direction for reference).
The affine transformation simply doesn't work - But acccording to the link provided it includes scaling so that shouldn't be the cause of the problem
There is a problem with my setting of variables - I've been looking at my code too long to see it if it is.
I am losing too much accuracy moving the var data to MySQL as a float or to PHP as a string
I am not giving accurate enough information from click data / lat/long input. - I zoomed i significantly when clicking on the map and getting the lat/long from google maps though
SVG isn't accuracte enough - Though looking at the xml data it keeps the decimals.
The area that I'm working with is too big to simplify by assuming that the local map is a flat plane
Any help is appreciated, thanks for reading this far.
For further reference I put the lat/long data that JavaScript gave me into google maps and i'm comparing accuracy to that rather than my actual location.
Additional reference: I found "landmarks" on the east and west edges of my image and have calculated the longitude difference to be 0.02695 with the length of the image being at least twice the height.
Sample values of a full run-through of values.
Reference Points
Point 1 (x,y) = (619,564)
Point 1 (lat,long) = (X.099546,-Y.465179)
Point 2 (x,y) = (1181,190)
Point 2 (lat,long) = (X.10365341,-Y.457014)
Geolocation
Predicted coordinate (x,y) = (975,262)
Given coordinate(lat,long) = (X.102851,-Y.459996)
Real Blip (x,y) = (1022.7498707999475,351.02335709985346)
Real blip (approximate lat,long) = (X.101964, -Y.459340)
(Real blip lat long is approximate as it is in a body of water with no good landmarks)
For safety's sake I've taken the digits before the decimal out of the lat/long coordinates but I can confirm that all the X's are equal and all the Y's are equal
Additionally I played with the lat long values in Chrome's developer tools, it seems like the axes are a bit rotated approximately 30 degrees from what it should be
After sufficient poking around I figured out that I had ordered lat and long incorrectly. On my map that has not been rotated from N at the top the following code brings me within just a few feet, more than explainable than the lack of precision resulting from relying on user input and the pixel grid.
var matrix = math.matrix(
[[long1,lat1,1,0]
,[-lat1,long1,0,1]
,[long2,lat2,1,0]
,[-lat2,long2,0,1]]);
And
var x = a * long + b * lat + c;
var y = b * long - a * lat + d;
For anyone else that is interested in pursuing this as a potential solution to simplify the math of their app
The drift that occurred was less than 40 feet over a map with a diagonal of 8000 feet and a difference in reference points of around 3000 feet. This means the drift is little over 1% of the distance of the reference points, this includes the effect of human error.
This error should decrease as you work on smaller maps and increase as you work on bigger maps.
I tested it again on a map with a ~90 degree rotation and the code held up
I've seen many variations of this question asked but am having trouble relating their answers to my specific need.
I have several sets of 3 lat/lng coordinate pairs. The coordinates in any set are within a few km of eachother.
For each set I would like to convert the coordinates to x/y values so that I can plot them.
I would like to assign 1 of the coordinates to 0,0 and then compute the relative x/y values of the other two coordinates.
This site does what I want but unfortunately doesn't share the algorithm:
http://www.whoi.edu/marine/ndsf/cgi-bin/NDSFutility.cgi?form=0&from=LatLon&to=XY
First some definitions just to be clear
let a be latitude <-pi/2,+pi/2>
let b be longitude <0,+2*pi>
let re,rp be equator and pole radiuses of Earth
a0,b0, a1,b1, a2,b2 are your points in spherical coordinates
and x0,y0, x1,y1, x2,y2 are your wanted cartesian coordinates
convert coordinates to relative to (a0,b0)
Leta assume East is aligned to your X-axis and North pole is aligned to Y-axis
x0=0.0;
y0=0.0;
r1=re*cos(a1)+rp*sin(a1) // actual radius for point 1
r2=re*cos(a2)+rp*sin(a2) // actual radius for point 2
x1=x0+((b1-b0)*r1);
x2=x0+((b2-b0)*r2);
y1=y0+((a1-a0)*re); // here instead of re should be length of ellipse curve from 0 to a1-a0
y2=y0+((a2-a0)*re); // here instead of re should be length of ellipse curve from 0 to a2-a0
if re!=rp then the y1,y2 coordinates will be less accurate
to correct that just replace ((a1-a0)*re) with the propper formula
for ellipse arc->length computation (this one is for circle)
I am too lazy to compute that integral
anyway even this is good enough (earth eccentricity is not that bad)
you also can normalize the angles after substraction
while (a<-pi) a+=2.0*pi;`
while (a>+pi) a-=2.0*pi;`
just to be safe ...
Actually, that's not entirely true. The site does share the algorithm, just not in the way one would expect to.
See http://www.whoi.edu/marine/ndsf/utility/NDSFutility.js .
Hope that helps.