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.
Related
I'm trying calculate overlap area created by semicircle which created by folium.after that i want to assign x,y,z value to the each semi semicircle by reduce same value overlap ex:- to reduce two x value semicircles
here is the image for better understand
How do I calculate the overlap area using python?
1. Pure Math:
First, check if they intersect:
Since the overlaps are not uniform (orthogonal, perpendicular or symmetrical) you are going to need to use the help of something called FUNCTIONS (like f(x)) and since your sectors (they are not a semi-circle) look to be the same size and have a internal area, you can use INEQUALITIES to check if they are intersecting.
Say for example you have a two sectors that are intercepting like this, with their respective functions:
f(x) = x^2 + y^2 <= 5 | {0 <= x <= 5} {0 <= y} (RED)
g(x) = ((x - 4)^2) + y^2 <= 5 | {0 <= x <= 5} {0 <= y} (BLUE)
Assuming the unanimous cartesian system (x, y), all the sectors are drawing to the same coordinates (in the same 'space'; if you understand me here...):
Just equate the 2 functions together:
Rule: If f(x) intersects g(x) and vice-versa:
f(x) = g(x) at some point
g(x) is in / passes through the shaded area of f(x)
f(x) is in / passes through the shaded area of g(x)
The radius of f(x) + the radius of g(x) ≥ the distance between the 2 sectors
Note: 2 & 3 might need calculus to check, if your functions are not inequalities but lines.
Since you are coding a program, you can do an early out, that if one of the top 4 conditions are not met, the sectors do not intersect.
Second, if the sectors do intersect:
Use intergral calculus to find the area of intersection:
∫f(x) - ∫g(x) = the magnitude (size) of the area (make sure the upper and lower limits are specified correctly)
2. Using a 3D graphics method:
Now, I know this is not a really good method for this, but you could implement collision detection, if you do not like heavy maths.
Obviously, at first reading this may sound completely absurd (because collision detection is something used in game programming far more often), but have read at this:
circle-circle collision
and see if you can possibly implement a sort of sector hit-box on your quadrants (create circle hit-boxes, restrict them to sectors, and see if they intersect.)
Honestly, though, the first method would be the most optimum, assuming if you have some form of 3D or 2D cartesian system, where your quadrants are mapped on.
Although a little math heavy, it's up to you to how you would like to implement it in python (I would highly recommend creating multiple functions and optimising where you can (like the 4 rules to check intersection above)).
If you do not know any of the math concepts, google them to find out more, cause knowing how they work would help you a lot...
Me and my team are participating in ESA Astro Pi challenge. Our program will ran on the ISS for 3 hours and we will our results back and analyze them.
We want to investigate the connection between the magnetic intensity measurements from Sense HAT magnetometer and predictions from the World Magnetic Model (WMM). We want to research the accuracy of the magnetometer on Sense HAT.
The program will get raw magnetometer data (X, Y and Z) in microteslas from Sense HAT and calculate values H and F as described in British geological survey's article (section 2.1). It will then save them to CSV file, along with timestamp and location calculated with ephem.
We will then compare values Z, H and F from ISS and WMM and create maps with our data and differences (like figures 6, 8 and 10). We will then research, how accurate are Sense HAT magnetometer data.
We want to compare our data with data from WMM to see how accurate is Sense HAT magnetometer, but we have a problem that orientation of magnetometer will always be different. Because of that, our data will always be (very) different from WMM so we won't be able to compare them correctly.
We talked with Astro Pi support team and they suggested to "normalise the angled measurements so it looks like they were taken by a device aligned North/South".
Unfortunately, we (and they) don't know how to do this, so they suggested to ask this question on Stack Exchange. I asked it on Math Stack Exchange, Physics Stack Exchange and Raspberry Pi Forums. Unforcenetly, they didn't received any answers, so I am asking this question again.
How can we do this? We have data for timestamp, ISS location (latitude, longitude, elevation), magnetic data (X, Y and Z) and also direction from the North.
We want to normalise our data so we will be able to correctly compare them with data from WMM.
Here is part of our program that calculates magnetometer values (which gets not normalised data):
compass = sense.get_compass_raw()
try:
# Get raw data (values are swapped because Sense HAT on ISS is in different position)
# x: northerly intensity
# y: easterly intensity
# z: vertical intensity
x = float(compass['z'])
y = float(compass['y'])
z = float(compass['x'])
except (ValueError, KeyError) as err:
# Write error to log (excluded from this snippet)
pass
try:
# h: horizontal intensity
# f: total intensity
# d: declination
# i: inclination
h = sqrt(x ** 2 + y ** 2)
f = sqrt(h ** 2 + z ** 2)
d = degrees(atan(y / x))
i = degrees(atan(z / h))
except (TypeError, ValueError, ZeroDivisionError) as err:
# Write error to log (excluded from this snippet)
pass
There is also some simple simulator available with our code: https://trinket.io/library/trinkets/cc87813ce7
Part of email from Astro Pi team about location and position of magnetometer:
Z is going down through the middle of the Sense Hat.
X runs between the USB ports and SD card slot.
Y runs across from the HDMI port to the 40 way pin header.
On the ISS the AstroPi orientation is that the Ethernet + USB ports face the deck and the SD card slot is towards the sky.
So, that's basically a rotation around the Y axis from flat. So you keep the Y axis the same and swap around Z and X.
It can help to look at the Google Street view of the interior of the ISS Columbus module to get a better idea how the AstroPi is positioned;
https://www.google.com/streetview/#international-space-station/columbus-research-laboratory
If you pan the camera down and to the right, you'll see a green light - that's the AstroPi. The direction of travel for the whole space station is towards the inflatable Earth ball you can see on the left.
So, broadly speaking, the SD card slot points towards azimuth as in away from the centre of the Earth (so the X axis).
The LED matrix is facing the direction of travel of the space station (the Z axis).
Because of the orbital path of the ISS the Z and Y axes will continually change direction relative to the poles as it moves around the Earth.
So, I am guessing you want to normalise the angled measurements so it looks like they were taken by a device aligned North/South?
I think you need to create local reference coordinate system similar to NEH (north,east,height/altitude/up) something like
Representing Points on a Circular Radar Math approach.
Its commonly used in aviation as a reference frame (heading is derived from it) so your reference frame is computed from your geo location and its axises pointing to North, East and Up.
Now the problem is what does it mean aligned North/South and normalizing.. ?
If reference device measure just projection than you would need to do something like this:
dot(measured_vector,reference_unit_direction)
where the direction would be the North direction but as unit vector.
If the reference device measure a full 3D too then you need to transform both reference and tested measured data into the same coordinate system. That is done by using
transform matrices
So simple matrix * vector multiplication will do ... Only then compute the values H,F,Z which I do not know what they are and too lazy to go through papers ... would expect E,H or B vectors instead.
However if you do not have the geo location at moment of measure then you have just the North direction in respect to the ISS in form of Euler angles so you can not construct 3D reference frame at all (unless you got 2 known vectors instead of just one like UP). In such case you need to go with the option 1 projection (using dot product and north direction vector). So you will handle just scalar values instead of 3D vectors afterwards.
[Edit1]
From the link of yours:
The geomagnetic field vector, B, is described by the orthogonal
components X (northerly intensity), Y (easterly intensity) and Z
(vertical intensity, positive downwards);
This is not my field of expertise so I might be wrong here but this is how I understand it:
B(Bx,By,Bz) - magnetic field vector
a(ax,ay,az) - acceleration
Now F is a magnitude of B so its invariant on rotation:
F = |B| = sqrt( Bx*Bx + By*By + Bz*Bz )
you need to compute the X,Y,Z values of B in the NED reference frame (North,East,Down) so you need the basis vectors first:
Down = a/|a| // gravity points down
North = B/|B| // north is close to B direction
East = cross(Down,North) // East is perpendicular to Down and North
North = cross(East,Down) // north is perpendicular to Down and East, this should convert North to the horizontal plane
You should render them to visually check if they point to correct directions if not negate them by reordering the cross operands (I might have the order wrong I am used to use Up vector instead). Now just convert B to NED :
X = dot(North,B)
Y = dot(East,B)
Z = dot(Down,B)
And now you can compute the H
H = sqrt( X*X +Y*Y )
The vector math needed for this you will find in the transform matrix link above.
beware this will work only if no accelerations are present (the sensor is not on a robotic arm during its operation, or ISS is not doing a burn...) Otherwise you need to obtain the NED frame differently (like from onboard systems)
If this not work correctly then you can compute NED from your ISS position but for that you would need to know the exact orientation and displacement of the sensor in respect to your simulation model that provide your location. I do not know what rotations ISS do so I would not touch that subject unless as a last resort.
I am afraid that I will not have time for coding for some time ... anyway coding without sample input data nor the coordinate system expalnations and all the input/output variables is insanity ... simple negation of axis will invalidate the whole thing and there is a lot of duplicities along the ways and to cover all of them you would end up with many many versions to try to...
Apps should be build up incrementally but I am afraid that without the access to simulation or real HW that is not possible. And there is a whole bunch of things that could go wrong ... making even simple programs a magnitude harder to code... I would first check the F as it does not require any "normalization" first to see if the results are off or not. If off it might suggest different units or god knows what ...
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? :)
I am new member here and I'm gonna drive straight into this as I've spent my whole Sunday trying to get my head around it.
I'm new to Python, having previously learned coding on C++ to a basic-intermediate level (it was a 10-week university module).
I'm trying a couple of iterative techniques to calculate Pi but both are coming up slightly inaccurate and I'm not sure why.
The first method I was taught at university - I'm sure some of you have seen it done before.
x=0.0
y=0.0
incircle = 0.0
outcircle = 0.0
pi = 0.0
i = 0
while (i<100000):
x = random.uniform(-1,1)
y = random.uniform(-1,1)
if (x*x+y*y<=1):
incircle=incircle+1
else:
outcircle=outcircle+1
i=i+1
pi = (incircle/outcircle)
print pi
It's essentially a generator for random (x,y) co-ordinates on a plane from -1 to +1 on both axes. Then if x^2+y^2 <= 1, we know the point rests inside a circle of radius 1 within the box formed by the co-ordinate axes.
Depending on the position of the point, a counter increases for incircle or outcircle.
The value for pi is then the ratio of values inside and outside the circle. The co-ordinates are randomly generated so it should be an even spread.
However, even at very high iteration values, my result for Pi is always around the 3.65 mark.
The second method is another iteration which calculates the circumference of a polygon with increasing number of sides until the polygon is almost a circle, then, Pi=Circumference/diameter. (I sort of cheated because the coding has a math.cos(Pi) term so it looks like I'm using Pi to find Pi, but this is only because you can't easily use degrees to represent angles on Python). But even for high iterations the final result seems to end around 3.20, which again is wrong. The code is here:
S = 0.0
C = 0.0
L = 1.0
n = 2.0
k = 3.0
while (n<2000):
S = 2.0**k
L = L/(2.0*math.cos((math.pi)/(4.0*n)))
C = S*L
n=n+2.0
k=k+1.0
pi = C/math.sqrt(2.0)
print pi
I remember, when doing my C++ course, being told that the problem is a common one and it isn't due to the maths but because of something within the coding, however I can't remember exactly. It may be to do with the random number generation, or the limitations of using floating point numbers, or... anything really. It could even just be my mathematics...
Can anyone think what the issue is?
TL;DR: Trying to calculate Pi, I can get close to it but never very accurately, no matter how many iterations I do.
(Oh and another point - in the second code there's a line saying S=2.0**k. If I set 'n' to anything higher than 2000, the value for S becomes too big to handle and the code crashes. How can I fix this?)
Thanks!
The algorithm for your first version should look more like this:
from __future__ import division, print_function
import sys
if sys.version_info.major < 3:
range = xrange
import random
incircle = 0
n = 100000
for n in range(n):
x = random.random()
y = random.random()
if (x*x + y*y <= 1):
incircle += 1
pi = (incircle / n) * 4
print(pi)
Prints:
3.14699146991
This is closer. Increase n to get even closer to pi.
The algorithm takes into account only one quarter of the unit circle, i.e. with a radius of 1.
The formula for the area of a quarter circle is:
area_c = (pi * r **2) / 4
That for the area of the square containing this circle:
area_s = r **2
where r is the radius of the circle.
Now the ratio is:
area_c / area_s
substitute the equations above, re-arange and you get:
pi = 4 * (area_c / area_s)
Going Monte Carlo, just replace both areas by a very high number that represents them. Typically, the analogy of darts thrown randomly is used here.
For the first one, your calculation should be
pi = incircle/1000000*4 # 3.145376..
This is the number of points that landed inside of the circle over the number of total points (approximately 0.785671 on my run).
With a radius of 1 (random.uniform(-1,1)), the total area is 4, so if you multiple 4 by the ratio of points that landed inside of the circle, you get the correct answer.
I was unable to go from the previous question because I was not a member of the website so I was unable to comment on it when I returned.
Here is my question:
To find the area of a region bounded by the graph y=x^2 and the x-axis on the interval [a,b] we can approximate the region by drawing a number of "thin" rectangles and taking the sum of their areas. Let us divide [a,b] into n smaller intervals of the same widght h=b-1/n. On each interval there is a rectangle with the height y=r where r is the middle of that small interval on the x-axis. The area of that rectangle is hy. Write a Python function that takes a,b, and n as parameters and returns the approximate area of the region under the parabola y=x^2 using the above method. If you could please explain as to why your program works that would be helpful.
Thanks to helpful members, I found the following program(please edit the program for i am unable/ don't know how to
def parabola(x):
y = x*x
return y
def approx_area(fn, a, b, n):
"""
Approximate the area under fn in the interval [a,b]
by adding the area of n rectangular slices.
"""
a = float(a)
b = float(b)
area = 0.0
for slice in range(n):
left = a + (b-a)*slice/n
right = a + (b-a)*(slice+1)/n
mid = (left + right)*0.5
height = fn(mid)
width = right - left
area += height * width
return area
print "Area is", approx_area(parabola, -1.0, 1.0, 500)
However, I would need to place this under one entire function. Any ideas on how I can do this?
Okay, by changing the function to y = x and trying some known input values, I conclude that it works fine:
0 .. 1 => 0.5
0 .. 2 => 2.0
1 .. 2 => 1.5
0 .. 9 => 40.5
If you want it all in one function, just get rid of parabola(), remove the first parameter from the approx_area() function (and call), then change:
height = fn(mid)
to:
height = mid * mid
as in:
def approx_area(a, b, n):
"""
Approximate the area under fn in the interval [a,b]
by adding the area of n rectangular slices.
"""
a = float(a)
b = float(b)
area = 0.0
for slice in range(n):
left = a + (b-a)*slice/n
right = a + (b-a)*(slice+1)/n
mid = (left + right)*0.5
height = mid * mid
width = right - left
area += height * width
return area
print "Area is", approx_area(-1, 1, 500)
Note that I wouldn't normally give this much explicit help for homework but, since you've done the bulk of the work yourself, it's only a small nudge to push you across the line.
I would warn you against handing in this code as-is since a simple web search will easily find it here and your grades may suffer for that.
Examine it, understand how it works thoroughly, then try to re-code it yourself without looking at this source. That will assist you far more in your career than just blind copying, trust me.
And just so you understand the theory behind this method, consider the slice of the function y = x:
7 .
6 /|
5 / |
| |
| |
| |
| |
| |
0 +-+
567
The midpoint y co-ordinate (and also the height) of the top is (5 + 7) / 2, or 6, and the width is 2 so the area is 12.
Now this is in fact the actual area but that's only because of the formula we're using. For a non-linear formula, there will be inaccuracies because of the nature of the "line" at the top. Specifically, in your case, a parabola is curved.
But these inaccuracies get less and less and you use thinner and thinner slices since any line tends towards a straight line (linear) as you shorten it. For the case above, if you divided that into two slices, the areas would be 5.5 x 1 and 6.5 x 1 for a total of 12. If you line weren't straight, the two-slice answer would be closer to reality than the one-slice answer.
For your parabola (but from x = 0 .. 1 to make my life easier, just double everything for x = -1 .. 1 since it's symmetrical around the y-axis), the worst case in a one-slice solution. In that case, the midpoint is at x = 0.5, y = 0.25 and, when you multiply that y by the width of 1, you get an area of 0.25.
With two slices (width = 0.5), the midpoints are at:
x y y x width
---- ------ ---------
0.25 0.0625 0.03125
0.75 0.5625 0.28125
---------
0.31250
So the area estimate there is 0.3125.
With four slices (width = 0.25), the midpoints are at:
x y y x width
----- -------- ----------
0.125 0.015625 0.00390625
0.375 0.140625 0.03515625
0.625 0.390625 0.09765625
0.875 0.765625 0.19140625
----------
0.32812500
So the area estimate there is 0.328125.
With eight slices (width = 0.125), the midpoints are at:
x y y x width
------ ---------- -----------
0.0625 0.00390625 0.000488281
0.1875 0.03515625 0.004394531
0.3125 0.09765625 0.012207031
0.4375 0.19140625 0.023925781
0.5625 0.31640625 0.039550781
0.6875 0.47265625 0.059082031
0.8125 0.66015625 0.082519531
0.9375 0.87890625 0.109863281
-----------
0.332031248
So the area estimate there is 0.332031248.
As you can see, this is becoming closer and closer to the actual area of 1/3 (I know this since I know calculus, see below).
Hopefully, that will assist you in understanding the code you have.
If you really want to know how this works, you need to look into calculus, specifically integration and differentiation. These methods can take a formula and give you another formula for calculating the slope of a line and the area under the line.
But, unless you're going to be using it a lot and need real (mathematical) accuracy, you can probably just use the approximation methods you're learning about.
There is also a good visualization of this at http://en.wikipedia.org/wiki/Integral#Formal_definitions
We look at the section of the parabola between a and b, and we divide it into a set of vertical rectangular slices such that the top-center of each rectangle is exactly on the parabola.
This leaves one corner of each rectangle "hanging over" the parabola, and the other too low, leaving unfilled space; so the area under the parabola is equal to the area of the rectangle, plus a bit, minus a bit. But how do we compare the bits? Is the area of the rectangle a bit too much, or not quite enough?
If we draw a line tangent to the parabola at the top-center of the rectangle, we can "cut off" the overlapping bit, flip it over, and add it to the other side; note that this does not change the total area of the rectangle (now a trapezoid).
We can now see that there is a little bit of space left on either side under the parabola, so the area of the trapezoid is slightly less than the area under the parabola. We can now think of the trapezoid-tops as forming a bunch of straight-line segments (a "linear piecewise approximation") along the bottom of the parabola; and the area under the segments is almost the same as (but always slightly less than) the actual area we are seeking.
So how do we minimize the "slightly less than" amount, to make our calculated area more accurate? One way is to use curved approximation-pieces instead of straight lines; this leads into splines (Bezier curves, NURBS, etc). Another way is to use a larger number of shorter line-pieces, to "increase the resolution". Calculus takes this idea to the limit (pun intended), using an infinite number of infinitely short pieces.