Related
I need to produce the star map with constellations etc in the Mollweide projection (elliptical projection giving 360 view angle, used in plotting night sky). I found a recipe at https://kimnewzealand.github.io/2019/02/21/celestial-maps/ with the use of sf package and converting the default EPSG:4326 data of the sky objects into Mollweide projection.
At some stage the data is converted to the Mollweide projection using the command:
constellation_lines_sf_trans<- st_transform(constellation_lines_sf_trans, crs = "+proj=moll")
The resulting image, reproduced along the lines as described in the link, looks like:
It is fine, however, the coordinate system is equatorial, that is basically with the same rotation axis as all coordinate systems on the Earth, like WGS84 (North Pole upwards). For example, the Milky Way is shown on this plot, going at some angle 60 degrees. We need the so called galactic coordinates: this is the coordinate plane coinciding with the plane of our Galaxy. So, Milky way here would be just a horizontal line of the ellipse axis. For example, the solution found elsewhere, seems to use the same technique, but the code is not given there:
Here Milky Way is a horizontal line, and the North Pole is in the upper left corner (denoted as np; for example, here one can see the distorted recognizable constellations of Ursa Major/Minor around the North Pole). I would take this image, but there is a blind spot (showing the blind zone of an observatory which cannot reach this region in the sky), so I would like to reproduce this image: constellations + Mollweide projection + "galactic" orientation of the reference frame.
We are able to convert between variety of coordinate systems in R packages. It seems that most GIS tools use various flavors of Earth-related coordinate systems and projections, based to the rotation of the Earth (North Pole up), for majority of applications, needed for GIS. The question is whether it is possible to load and convert to a predefined galactic coordinate system (or, for example, to the ecliptic system), or to perform this conversion on the fly in the scripts with manual conversion of star data
EDIT: Actually, after further research, it appears that it all comes down to having your projection do a rotation. This also happens in the code on the interactive example I mention farther below. To make it center of the Galactic center, you need to rotate by [93.5949, 28.9362, -58.5988], which specify the [lambda, phi, gamma] rotation angles in degrees about each spherical axis. (when you rotate, there's no need to convert your ra or dec coordinates to galactic coordinates anymore.)
I don't know enough about mapping in R to be able to say if it's possible to specify a rotation on a projection, but here's an amazing example that shows this process with d3.js (and for those truly interested, shows where the angles come from). In case it's not possible, perhaps the route below would still be viable.
I was investigating the same thing, and I might've found something. I think that you first need to convert your equatorial ra (right ascension) and dec (declination) coordinates to galactic coordinates. And then apply a (Mollweide) projection. I'm not sure if that is completely correct since my case was slightly different, but at least this worked for me:
The dataset has rows of ra &dec in equatorial coordinates (given in degrees in my case)
Using the euler function of the astrolibR package, I calculate the Galactic longitude gl and latitude gb (ps: you can also use the glactc function):
data$gl <- euler(data$ra, data$dec, select=1)$ao
data$gb <- euler(data$ra, data$dec, select=1)$bo
Next, using these new coordinates I apply the Aitoff projection that is also part of the astrolibR package to get back x and y coordinates:
data$x <- -aitoff(data$gl, data$gb)$x
data$y <- aitoff(data$gl, data$gb)$y
which I can then plot
ggplot(data, aes(x, y)) + geom_point(shape=16, size = 0.1, alpha = 0.2) + coord_fixed()
(the image below is based on my own dataset of observations, the "darker line" follows the ecliptic line, and the two blobs in the lower right are the Large & Small Magellanic Clouds)
I found it useful to compare against this interactive map and setting the coordinates to "galactic", centering on 0,0 and then trying different kinds of projections.
Perhaps you can try applying the Mollweide projection with the gl and gb coordinates instead?
I would like to create a GPS drawing program in Argon and A-Frame which draws lines based upon people's movements.
Lines can be drawn in A-Frame with, for example, the meshline component which uses Cartesian points:
<a-entity meshline="lineWidth: 20; path: -2 -1 0, 0 -2 0</a-entity>
If I were to do this with a GPS device, I would take the GPS coordinates and map them directly to something like Google maps. Does Argon have any similar functionality such that I can use the GPS coordinates directly as the path like so:
<a-entity meshline="lineWidth: 20; path: 37.32299 -122.04185 0, 37.32298 -122.03224</a-entity>
Since one can specify an LLA point for a reference frame I suppose one way to do this would be to conceive of the center LLA point as "0, 0, 0" and then use a function to map the LLA domain to a Cartesian range.
It would be preferable, however, to use the geo-coordinates directly. Is this possible in Argon?
To understand the answer, you need to first understand the various frames of reference used by Argon.
First, Argon makes use of cesiumjs.org's geospatial math libraries and Entity's so that all "locations" in Argon must either be expressed geospatially OR be relative to a geospatial entity. These are rooted at the center of the earth, in what Cesium calls FIXED coordinates, but are also know as ECEF or ECF coordinates. In that system, coordinates are in meters, with up/down going through the poles, east/west going through the meridian (I believe). Any point on the surface of the earth is represented with pretty large numbers.
This coordinate system is nice because we can represent anything on or near the earth precisely using it. Cesium also supports INERTIAL coordinates, which are used to represent near-earth orbital objects, and can convert between the two frames.
But, it is inconvenient when doing AR for a few reasons:
the numbers used to represent the position of the viewer and objects near them are quite large, even if they are very close, which can lead to mathematical accuracy issues, especially in the 3D graphics system.
The coordinates we "think about" when we think about the world around us have the ground as "flat" and "up" as pointing ... well, up. So, in 3D graphics, an object above another object typically has the same X and Z values, but has a Y that's bigger. In ECEF coordinates, all the numbers change because what we perceive as "up" is really a vector from the center of the earth though us, and is only "up" if we're on the north (or south, depending on your +/-) pole. Most 3D graphics libraries you might want to use (e.g., physics libraries, for example), assume a world in which the ground is one plane (typically the XZ plane) and Y is up (some aeronautics and other engineering applications use Z as up and have XY as the ground, but the issue is the same).
Argon deals with this, as do many geospatial AR systems, by creating a local coordinate system for the graphics and application to use. There are really three options for this:
Pick some arbitrary (but fixed) local place as the origin. Some systems, which are built to work in one place, have this hard-coded. Others let the application set it. We don't do this because it would encourage applications to take the easy path and only work in one place (we've seen this in the past).
Set the local place to the camera. This has the advantage that the math is the most "accurate" because all points are expressed relative to the camera. But, this causes two issues. First, the camera tends to move continuously (even if only due to sensor noise) in AR apps. Second, many libraries (again, like physics libraries) assume that the origin of the system is stable and on the earth, with the camera/user moving through it. These issues can be worked around, but they are tedious for application developers to deal with.
Set the origin of the local coordinates to an arbitrary location near the user, and if the user moves far from it, recenter automatically. The advantage of this is the program doesn't necessarily have to do much to deal with it, and it meshes nicely with 3D graphics libraries. The disadvantage is the local coordinates are arbitrary, and might be different each time a program is run. However, the application developer may have to pay attention to when the origin is recentered.
Argon uses open 3. When the app starts, we create a new local coordinate frame at the user's location, on the plane tangent to the earth. If the user moves far from that location we update the origin and emit an event to the application (currently, we recenter if you are 5km away from the origin). In many simple apps, with only a few frames or reference expressed in geospatial coordinates (and the rest of the application data expressed relative to known geospatial locations), the conversion from geospatial to local can just be done each frame, allowing the app developer to ignore the reentering problem. The programmer is free to use either ENU (east-north-up) or EUS (east-up-south) as their coordinate system; we tend to use EUS because it's similar to what most 3D graphics systems use (Y is up, Z points south, and X is east).
One of the reasons we chose this approach is that we've found in the past that if we had predictable local coordinates, application developers would store data using those coordinates even though that's not a good idea (you data is now tied to some relatively arbitrary application-specific coordinate system, and will now only work in that location).
So, now to your question. Your issue is that you want to use geospatial (cesium's coordinates, that argon uses) coordinates in AFrame. The short answer is you can't use them directly, since AFrame is built assuming a local 3D graphics coordinate system. The argon-aframe package binds aframe to argon by allowing you to specify referenceframe components that position an a-entity at an argon/cesium geospatial location, and take care of all the internal conversions for you.
The assumption when I wrote that code was that authors would then create their content using the local, 3D graphics coordinates, and attach those hunks of graphics to a-entity's that were located in the world with referenceframe's.
In order to have individual coordinates in AFrame correspond to geospatial places, you will need to manage that yourself, perhaps by creating a component to do it for you, or (if the data is known at the start) by converting it up front.
Here's what I'd do.
Assuming you have a list of geospatial coordinates (expressed as LLA), I'd convert each to a local coordinates (by first converting from LLA to Cesium's FIXED ECEF coordinates and creating a Cesium Entity, and then calling Argon's context.getEntityPose() on that entity (which will return it's local coordinates). I would pick one geospatial location in the set (perhaps the first one?) and then subtract it's local coordinates from each of them, so that they are all expressed in local coordinates relative to that known geospatial location.
Then, I'd create an AFrame entity attached to the referenceframe of that unique geospatial entity, and create your graphics content inside of it, using the local coordinates that are expressed relative to it. For example, let's say the geospatial location is LongLat = "-84.398881 33.778463" and you stored those points (local coordinates, relative to LongLat) in userPath, you could do something like this:
<ar-scene>
<ar-geopose id="GT" lla=" -84.398881 33.778463" userotation="false">
<a-entity meshline="lineWidth: 20; path: userPath; color: #E20049"></a-entity>
</ar-geopose>
</ar-scene>
I have a map of a mountainous landscape, http://skimap.org/data/989/60/1218033025.jpg. It contains a number of known points, the lat-longs of which can be easily found out using Google maps. I wish to be able to pin any latitude longitude coordinate on the map, of course within the bounds of the landscape.
For this, I tried an approach that seems to be largely failing. I assumed the map to be equivalent to an aerial photograph of the Swiss landscape, without any info about the altitude or other coordinates of the camera. So, I assumed the plane perpendicular to the camera lens normal to be Ax+By+Cz-d=0.
I attempt to find the plane constants, using the known points. I fix my origin at a point, with z=0 at the sea level. I take two known points in the landscape, and using the equation for a line in 3D, I find the length of the projection of this line segment joining the two known points, on the plane. I multiply it by another constant K to account for the resizing of this length on a static 2d representation of this 3D image. The length between the two points on a 2d static representation of this image on this screen can be easily found in pixels, and the actual length of the line joining the two points, can be easily found, since I can calculate the distance between the two points with their lat-longs, and their heights above sea level.
So, I end up with an equation directly relating the distance between the two points on the screen 2d representation, lets call it Ls, and the actual length in the landscape, L. I have many other known points, so plugging them into the equation should give me values of the 4 constants. For this, I needed 8 known points (known parameters being their name, lat-long, and heights above sea level), one being my orogin, and the second being a fixed reference point. The rest 6 points generate a system of 6 linear equations in A^2, B^2, C^2, AB, BC and CA. Solving the system using a online tool, I get the result that the system has a unique solution with all 6 constants being 0.
So, it seems that the assumption that the map is equivalent to an aerial photograph taken from an aircraft, is faulty. Can someone please give me some pointers or any other ideas to get this to work? Do open street maps have a Mercator projection?
I would say that this impossible to do in an automatic way. The skimap should be considered as an image rather than a map, a map is an projection of the real world into one plane, since this doesn't fit skimaps very well they are drawn instead.
The best way is probably to manually define a lot of points in the skimap with known or estimated coordinates and use them to estimate the points betwween. To get an acceptable result you probably have to assign coordinates to each pixel in the skimap.
You could do something like the following: http://magazin.unic.com/en/2012/02/16/making-of-interactive-mobile-piste-map-by-laax/
I am solving the exact same issue. It is pretty hard and lots of maths. Taking me a few weeks to solve it. Interpolation is the key as well with lots of manual mapping. I would say that for a ski mountain it will take at least 1000/1500 points to be able to get the very basic. So, not a trivial task unless you can automate the collection of these points (what I am doing!) ;)
It's been a while since my math in university, and now I've come to need it like I never thought i would.
So, this is what I want to achieve:
Having a set of 3D points (geographical points, latitude and longitude, altitude doesn't matter), I want to display them on a screen, considering the direction I want to take into account.
This is going to be used along with a camera and a compass , so when I point the camera to the North, I want to display on my computer the points that the camera should "see". It's a kind of Augmented Reality.
Basically what (i think) i need is a way of transforming the 3D points viewed from above (like viewing the points on google maps) into a set of 3d Points viewed from a side.
The conversion of Latitude and longitude to 3-D cartesian (x,y,z) coordinates can be accomplished with the following (Java) code snippet. Hopefully it's easily converted to your language of choice. lat and lng are initially the latitude and longitude in degrees:
lat*=Math.PI/180.0;
lng*=Math.PI/180.0;
z=Math.sin(-lat);
x=Math.cos(lat)*Math.sin(-lng);
y=Math.cos(lat)*Math.cos(-lng);
The vector (x,y,z) will always lie on a sphere of radius 1 (i.e. the Earth's radius has been scaled to 1).
From there, a 3D perspective projection is required to convert the (x,y,z) into (X,Y) screen coordinates, given a camera position and angle. See, for example, http://en.wikipedia.org/wiki/3D_projection
It really depends on the degree of precision you require. If you're working on a high-precision, close-in view of points anywhere on the globe you will need to take the ellipsoidal shape of the earth into account. This is usually done using an algorithm similar to the one descibed here, on page 38 under 'Conversion between Geographical and Cartesian Coordinates':
http://www.icsm.gov.au/gda/gdatm/gdav2.3.pdf
If you don't need high precision the techniques mentioned above work just fine.
could anyone explain me exactly what these params mean ?
I've tried and the results where very weird so i guess i am missunderstanding some of the params for the perspective projection
* {a}_{x,y,z} - the point in 3D space that is to be projected.
* {c}_{x,y,z} - the location of the camera.
* {\theta}_{x,y,z} - The rotation of the camera. When {c}_{x,y,z}=<0,0,0>, and {\theta}_{x,y,z}=<0,0,0>, the 3D vector <1,2,0> is projected to the 2D vector <1,2>.
* {e}_{x,y,z} - the viewer's position relative to the display surface. [1]
Well, you'll want some 3D vector arithmetic to move your origin, and probably some quaternion-based rotation functions to rotate the vectors to match your direction. There are any number of good tutorials on using quaternions to rotate 3D vectors (since they're used a lot for rendering and such), and the 3D vector stuff is pretty simple if you can remember how vectors are represented.
well, just a pice ov advice, you can plot this points into a 3d space (you can do easily this using openGL).
You have to transforrm the lat/long into another system for example polar or cartesian.
So starting from lat/longyou put the origin of your space into the center of the heart, than you have to transform your data in cartesian coord:
z= R * sin(long)
x= R * cos(long) * sin(lat)
y= R * cos(long) * cos(lat)
R is the radius of the world, you can put it at 1 if you need only to cath the direction between yoour point of view anthe points you need "to see"
than put the Virtual camera in a point of the space you've created, and link data from your real camera (simply a vector) to the data of the virtual one.
The next stemp to gain what you want to do is to try to plot timages for your camera overlapped with your "virtual space", definitevly you should have a real camera that is a control to move the virtual one in a virtual space.
I have a game world with lots of irregular objects with varying coordinate systems controlling how objects on their surface work. However the camera and these objects can leave and move out into open empty space, where a normal Cartesian coordinate system is used. How do I manage mapping between the two?
One idea I had would be to wrap these objects in a bounds such as a sphere or box, within which said coordinate system would be used, however this becomes problematic if those bounding objects overlap, at which point I'm unsure whether the idea is fundamentally flawed or a solution can be found, since these objects are moving and could overlap at some point
I think you should place all your objects in the cartesian 'empty space' coordinate system by composition of your irregular objects coordinates system with the position matrix.
It adds a level, but will make everything easier.
Regarding the use of bounds I had an idea where the object would use the coordinate system of the smallest bounds it occupied, and then transform according to the heirarchy of systems from top to bottom.
Thus lets say stick figures on a cylinder adjacent to a large object would follow the cylinder rather than flitting between the two objects and their coordinate systems.
Irregardless of the local coordinate system around each of irregular objects, all points will still map to the global world coordinates at one point or another because eventually when you want to render your objects they'll have to get mapped into world space and then camera space. You can use the same object space to world space transform matrices to do the mapping.
You can use Lame's coefficients to transform the dimensions of different coordinate systems.
You can transform any kind of coordinate systems, your own as well. The only condition is to have orthogonal dimensions (every dimension has to be independent from other dimensions).
Here is some document I found: link text.
Hope it helps.