Does anyone know of a good way to deal with a point cloud heightfield in python? I've done some googling but I'm not sure if any of the results really describe what I need. I have over 20 million points in the form of (lat, lon, altitude) (or if you'd rather, (x, y, altitude)) and want to be able to interpolate to an arbitrary position. But my experience is that a simple quadratic interpolation is terrible for altitude data. E.g. picture the following height points, and wanting to interpolate at point X:
4 3 2
4 3 2 2 0 0
3 2 0 0 2
2 22 0 2 2
2 X 2 3
0 0 0 2 3
0 2 3 4
2 3
Clearly X is down in the bottom of some sort of deep channel running ENE from the bottom left (or WSW from the top right). But quadratic interpolation will state that X is at around height 2 - aka not in a canyon at all, but on its rim. Quadratic interpolation cares only about distance, not angle. But in terrain, angle matters a lot. If you have a distant point, and several closer points in the same direction, the distant point is virtually meaningless, but if you have a distant point in a direction with no other points in the way, that point can be very meaningful.
A good triangulation could capture the geometry, obviously - it's easy enough to interpolate a point on a triangular facet. But a Delaunay triangulation wouldn't cut it - it would just reinforce the screwup, because it doesn't like long thin shapes like canyons, and would instead prefer to tesselate the points across the edges of the canyon in the above example.
I can think up algorithms to capture the terrain well (such as "projecting" from each point with a line toward X representing a weighted slope contribution, and weakening the weighting by each point the line passes, relative to how close it passes... then doing a least-squares fit for all slopes and points). Another option that comes to mind is using quadratic interpolation in all directions from X to get slopes in each direction, then iteratively adjusting X up or down to converge to a solution where it's not jutting unusually up or down as a whole. But any new algorithm would probably be significant work to implement, and I hate reinventing the wheel (probably suboptimally). Surely there must be some sort of fast library that would be good for this sort of thing? Hopefully pythonic? :)
Related
I'm sure that this has been answer already but I'm still confused with the post I already found on stackoverflow, that's why I decided to post my question.
I'm not super familiar with geometry transformation (except translation but this one is easy), and I need to transform a set of 3D points based on a selection of 3 points as describe in the picture
Here's my plan so far :
Create a triangle based on 3 points (let's call it tri) -> This is OK
Calculate the centroid of the triangle formed by my 3 points -> This is this is OK
translate all the points to the origin (0,0,0) -> This is OK as well
Rotate every points so that tri's points Z coordinates are equal to 0 -> This is were I'm lost and unsure how to process (without any errors...)
I know it's not an hard issues, but if anyone knows how to process with numpy for example, I'm open :-)
Thank you for your help :-)
In step 4 what you want is to rotate the triangle so that its normal is vertical.
You need to calculate the triangle's normal first. You can do so by using the cross product between two vectors (a and b) along two sides of the triangle: N = a x b.
Then you can calculate an axis of rotation A using the cross product between the triangle's normal and the Z axis: A = N x Z.
Then you can rotate the points using axis A.
As pointed out elsewhere, the solution is not unique.
I am writing mincraft-like game with voxel terrain.
For mountains, I specify a location, a height and size. There is a function to return True if the block at the current (x, y, z) coordinate is part of a mountain. If a block is far away from the centre of a mountain, True is only returned if if the z coord is below a maximum height for the distance from the mountain, ie the further from a mountain a block is, the lower the maximum height. So at the centre of a mountain, the maximum height is high, and True will be returned even if the z is high (I am using a z-up system). However, further away from the mountain, the maximum height will be lower.
However, my current function (below) returns them linearly, and real mountains do not have straight sides:
def isMountain(self, x, y, z, mountainPos, mountainSize, mountainHeight):
if math.hypot(mountainPos[0] - x, mountainPos[1] - y) < mountainSize:
if z < (mountainHeight - math.hypot(mountainPos[0] - x, mountainPos[1] - y)):
return True
else:
return False
The line 3 checks if z is less than the maximum height for the position, if yes, returning True, otherwise, False.
These are the maximum heights for distances:
Distance: Max Height
0 - 10
1 - 9
2 - 8
...
9 - 1
10 - 0
How could I re-write this function to make it return more mountain-like values: not linear, rather cubic or smooth fall-off (like blender proportianal edit mode), so it would give values more like this:
0 - 10
1 - 9
2 - 9
3 - 8
4 - 7
5 - 5
6 - 3
7 - 1
You can either break your head to find out some mathematical formula for this, or you could simulate the natural erosion process.
This is usually done using a grid (matrix, cells, ...) and iterating.
Basically you would start with more or less random high terrain, then erode it until mountains form, well actually mountains are what remains.
That said, this is usually more costly than using a simple function, but on modern computers this would work well.
Also see: https://www.gamasutra.com/blogs/MattKlingensmith/20130811/198049/How_we_Generate_Terrain_in_DwarfCorp.php
If you were interested in going another route you could use a modified version of perlin noise to use amplitude and frequency then use smoothing transition to get what you want. You could set points to have a general height range and then let the noise algo do its thing to create variability between the points. I have done something similar for creating an inf gen world with different biomes that have different kinds of mountain heights and shapes.
Maybe you could use an inverse tan function like this
https://www.desmos.com/calculator/sn7tbepuxh
Where h is the max height, s is the steepness and x is the distance from the centre of the peak. The -1 at the end allows negative values to be ignored so that the base of the mountain won't extend forever.
I've used this for a mountain generator for a small game and it seems to work fine, just as long as you tweak your steepness and height values to the mountain isn't too spiky.
I'm trying to go from alt/azi to RA/Dec for a point on the sky at a fixed location, trying out pyEphem. I've tried a couple of different ways, and I get sort of the right answer, within a couple of degrees, but I'm expecting better, and I can't figure out where the problems lie.
I've been using Canopus as a test case (I'm not after stars specifically, so I can't use the in-built catalogue). So in my case, I know that at
stn = ephem.Observer()
# yalgoo station, wa
stn.long = '116.6806'
stn.lat = '-28.3403'
stn.elevation = 328.0
stn.pressure = 0 # no refraction correction.
stn.epoch = ephem.J2000
stn.date = '2014/12/15 14:32:09' #UTC
Stellarium, checked with other web sites tell me Canopus should be at
azi, alt '138:53:5.1', '56:09:52.6' or in equatorial RA 6h 23m 57.09s/ Dec. -52deg 41' 44.6"
but trying:
cano = ephem.FixedBody()
cano._ra = '6:23:57.1'
cano._dec = '-52:41:44.0'
cano._epoch = ephem.J2000
cano.compute( stn)
print( cano.az, cano.alt)
>>>(53:22:44.0, 142:08:03.0)
about 3 degrees out. I've also tried the reverse,
ra, dec = stn.radec_of('138:53:5.1', '56:09:52.6')
>>>(6:13:18.52, -49:46:09.5)
where I'm expecting 6:23 not 6:13. Turning on refraction correction makes a small difference, but not enough, and I've always understood aberration and nutation were much smaller effects than this offset as well?
As a follow up, I've tried manual calculations, based on 'Practical Astronomy with your calculator'; so for dec:
LAT = math.radians(-28.340335)
LON = math.radians(116.680621667)
ALT = math.radians(56.16461)
AZ = math.radians(138.88475)
sinDEC = (math.sin( LAT)*math.sin( ALT)
+ math.cos( LAT)*math.cos( ALT)*math.cos( AZ) )
DEC = math.asin( sinDEC)
DEC_deg = math.degrees(DEC)
print( 'dec = ', DEC_deg )
>>>('dec = ', -49.776032754148986)
again, quite different from '56:09:52.6', but reasonably close to pyEphem - so now I'm thoroughly confused! So now I'm suspecting the problem is my understanding, rather than pyEphem - could someone enlighten me about the correct way to go do RADEC/ALTAZI conversions, and why things are not lining up?!
First some notes
Atmospheric scattering and relative speed between observer and object
have the maximal error (near horizon) up to 0.6 degree which is nowhere near your error.
how can altitude be over 90 degrees?
you got swapped data for azimut and altitude
I put your observer data into mine program and result was similar to yours
but I visually search for that star instead of putting the coordinates. Result was also about 3-4 degrees off in RA axis
RA=6.4h Dec=-52.6deg
azi=142.4deg alt=53.9deg
mine engine is in C++, using Kepler's equation
Now what can be wrong:
mine stellar catalog can be wrongly converted
rotated wrongly with some margin but strongly doubt that it is 3 degrees. Also perspective transforms can add some error while rendering at 750AU distance from observer. I never tested for Southern sky (not visible from mine place).
we are using different Earth reference frame then the data you comparing to
I found out that some sites like NASA Horizon use different reference frame which does not correspond with mine observations. Look here
calculate the time when the sun is X degrees below/above the Horizon
at the start of the answer is link to 2 sites with different reference frames when you compare the result they are off. The second link is corresponding with mine observations the rest is dealing (included source code) with Kepler's equation based Solar system simulation. The other sublinks are also worth looking into.
I could have a bug in mine simulation/data
I have referenced data to this engine which could partially hide any computation errors from mine observer position so handle all above text with taken that it mind.
you could use wrong time/Julian date to stellar time conversions
if your time is off then the angles will not match...
How to resolve this?
pick up your Telescope, set up equatoreal coordinate system/mount to it and measure Ra/Dec Azi/Alt for known (distant) object in reality and compare with computed positions. Only this way you can decide which value is good or wrong (for reference frame you are using). Do this on star not planet !!! Do this on high altitude angles not near Horizon !!!
How to transform between azimutal and equatoreal coordinates
I compute transform matrix Eath representing earth's coordinate system (upper right) in heliocentric coordinate system as global coordinate system (left) then I compute another matrix NEH representing observer on Earth's surface (North,East,High/Altitude ... lower right).
After this it is just a matter of matrix and vector multiplications and conversion between Cartesian and spherical coordinate systems look here:
Representing Points on a Circular Radar Math approach
for more insight to azimutal coordinates. if you use just that simple equation like in your example then you do not account for many things... The Earth position is computed by Kepler's equation, rotation is given by daily rotation, nutation and precession included.
I use 64 bit floating point values which can create round errors but not that high ...
I use geometric North Pole as observer reference (this could add some serious error near poles).
The biggest thing that can affect this is the speed of light but that account for near earth 'moving' objects like planets not stars (except Sun) because their computed position is visible after some time ... For example Sun-Earth distance is about 8 light minutes so we see the Sun where it was 8 minutes ago. If the effemerides data is geometrical only (not account for this) then this can lead to high errors if not computed properly.
Newer effemerides models use gravity integration instead of Kepler so their data must be geometrical and the final output is then corrected by the time shift ...
I need to write a script in python which given coordinates of 2 points in 3d space finds a collinear point in distane 1 unit from one the given points. This third point must lay between those two given.
I think I will manage with scripting but I am not really sure how to calculate it from mathematical point of view. I found some stuff on google, but they do not answer my question.
Thanks for any advice.
Given 2 points, (x1,y1,z1) and (x2,y2,z2), you can take the difference between the two, so you end up with (x2-x1,y2-y1,z2-z1). Take the norm of this (i.e. take the distance between the original 2 points), and divide (x2-x1,y2-y1,z2-z1) by that value. You now have a vector with the same slope as the line between the first 2 points, but it has magnitude one, since you normalized it (by dividing by its magnitude). Then add/subtract that vector to one of the original points to get your final answer.
So I have a 4d force field as in x y and z with a Force attached to each point.
I'm a a bit at a lost on how to interpolate this, I came across this though.
http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.ndimage.interpolation.map_coordinates.html
It looks like I can make an array of x y z F and then interpolate it but I'm really not too sure.
Anyone know any good libraries for python on how to do this?
Example input is:
x y z Force
0 0 0 35
0 0 1 32
0 0 2 23
...
2 5 9 54
The way you described it (x,y,z), this is a 3D field, not 4D.
The purpose of interpolation is to specify a field (in this case Force) at any point (x,y,z)
even if you don't have a Force, at precisely that point (x,y,z). Instead, you have the forces at a number of nearby points and you interpolate them to get a meaningful Force at point (x,y,z). In 3D you would need a bilinear interpolation algorithm at the least, and coding it up (and keeping indices in order) is non-trivial.
In Python, you can use Scipy's interpolation routines.
So, if i understand you corret, you have the force given at some points and at others not and want to come up with an interpolation?
At NMR the use of linear interpolation is till up to date. As an alternative, you can give splines a try, but thats more costly. But it mostly depends on the kind of your force - how fast is it going changing? Build your interpolation rouinte out of that.