Uniformly distribute x points inside a circle - math

I would like to uniformly distribute a predetermined set of points within a circle. By uniform distribution, I mean they should all be equally distanced from each other (hence a random approach won't work). I tried a hexagonal approach, but I had problems consistently reaching the outermost radius.
My current approach is a nested for loop where each outer iteration reduces the radius & number of points, and each inner loop evenly drops points on the new radius. Essentially, it's a bunch of nested circles. Unfortunately, it's far from even. Any tips on how to do this correctly?

The goals of having a uniform distribution within the area and a uniform distribution on the boundary conflict; any solution will be a compromise between the two. I augmented the sunflower seed arrangement with an additional parameter alpha that indicates how much one cares about the evenness of boundary.
alpha=0 gives the typical sunflower arrangement, with jagged boundary:
With alpha=2 the boundary is smoother:
(Increasing alpha further is problematic: Too many points end up on the boundary).
The algorithm places n points, of which the kth point is put at distance sqrt(k-1/2) from the boundary (index begins with k=1), and with polar angle 2*pi*k/phi^2 where phi is the golden ratio. Exception: the last alpha*sqrt(n) points are placed on the outer boundary of the circle, and the polar radius of other points is scaled to account for that. This computation of the polar radius is done in the function radius.
It is coded in MATLAB.
function sunflower(n, alpha) % example: n=500, alpha=2
clf
hold on
b = round(alpha*sqrt(n)); % number of boundary points
phi = (sqrt(5)+1)/2; % golden ratio
for k=1:n
r = radius(k,n,b);
theta = 2*pi*k/phi^2;
plot(r*cos(theta), r*sin(theta), 'r*');
end
end
function r = radius(k,n,b)
if k>n-b
r = 1; % put on the boundary
else
r = sqrt(k-1/2)/sqrt(n-(b+1)/2); % apply square root
end
end

Might as well tag on my Python translation.
from math import sqrt, sin, cos, pi
phi = (1 + sqrt(5)) / 2 # golden ratio
def sunflower(n, alpha=0, geodesic=False):
points = []
angle_stride = 360 * phi if geodesic else 2 * pi / phi ** 2
b = round(alpha * sqrt(n)) # number of boundary points
for k in range(1, n + 1):
r = radius(k, n, b)
theta = k * angle_stride
points.append((r * cos(theta), r * sin(theta)))
return points
def radius(k, n, b):
if k > n - b:
return 1.0
else:
return sqrt(k - 0.5) / sqrt(n - (b + 1) / 2)
# example
if __name__ == '__main__':
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
points = sunflower(500, alpha=2, geodesic=False)
xs = [point[0] for point in points]
ys = [point[1] for point in points]
ax.scatter(xs, ys)
ax.set_aspect('equal') # display as square plot with equal axes
plt.show()

Stumbled across this question and the answer above (so all cred to user3717023 & Matt).
Just adding my translation into R here, in case someone else needed that :)
library(tibble)
library(dplyr)
library(ggplot2)
sunflower <- function(n, alpha = 2, geometry = c('planar','geodesic')) {
b <- round(alpha*sqrt(n)) # number of boundary points
phi <- (sqrt(5)+1)/2 # golden ratio
r <- radius(1:n,n,b)
theta <- 1:n * ifelse(geometry[1] == 'geodesic', 360*phi, 2*pi/phi^2)
tibble(
x = r*cos(theta),
y = r*sin(theta)
)
}
radius <- function(k,n,b) {
ifelse(
k > n-b,
1,
sqrt(k-1/2)/sqrt(n-(b+1)/2)
)
}
# example:
sunflower(500, 2, 'planar') %>%
ggplot(aes(x,y)) +
geom_point()

Building on top of #OlivelsAWord , here is a Python implementation using numpy:
import numpy as np
import matplotlib.pyplot as plt
def sunflower(n: int, alpha: float) -> np.ndarray:
# Number of points respectively on the boundary and inside the cirlce.
n_exterior = np.round(alpha * np.sqrt(n)).astype(int)
n_interior = n - n_exterior
# Ensure there are still some points in the inside...
if n_interior < 1:
raise RuntimeError(f"Parameter 'alpha' is too large ({alpha}), all "
f"points would end-up on the boundary.")
# Generate the angles. The factor k_theta corresponds to 2*pi/phi^2.
k_theta = np.pi * (3 - np.sqrt(5))
angles = np.linspace(k_theta, k_theta * n, n)
# Generate the radii.
r_interior = np.sqrt(np.linspace(0, 1, n_interior))
r_exterior = np.ones((n_exterior,))
r = np.concatenate((r_interior, r_exterior))
# Return Cartesian coordinates from polar ones.
return r * np.stack((np.cos(angles), np.sin(angles)))
# NOTE: say the returned array is called s. The layout is such that s[0,:]
# contains X values and s[1,:] contains Y values. Change the above to
# return r.reshape(n, 1) * np.stack((np.cos(angles), np.sin(angles)), axis=1)
# if you want s[:,0] and s[:,1] to contain X and Y values instead.
if __name__ == '__main__':
fig, ax = plt.subplots()
# Let's plot three sunflowers with different values of alpha!
for alpha in (0, 1, 2):
s = sunflower(500, alpha)
# NOTE: the 'alpha=0.5' parameter is to control transparency, it does
# not have anything to do with the alpha used in 'sunflower' ;)
ax.scatter(s[0], s[1], alpha=0.5, label=f"alpha={alpha}")
# Display as square plot with equal axes and add a legend. Then show the result :)
ax.set_aspect('equal')
ax.legend()
plt.show()

Adding my Java implementation of previous answers with an example (Processing).
int n = 2000; // count of nodes
Float alpha = 2.; // constant that can be adjusted to vary the geometry of points at the boundary
ArrayList<PVector> vertices = new ArrayList<PVector>();
Float scaleFactor = 200.; // scale points beyond their 0.0-1.0 range for visualisation;
void setup() {
size(500, 500);
// Test
vertices = sunflower(n, alpha);
displayTest(vertices, scaleFactor);
}
ArrayList<PVector> sunflower(int n, Float alpha) {
Double phi = (1 + Math.sqrt(5)) / 2; // golden ratio
Double angle = 2 * PI / Math.pow(phi, 2); // value used to calculate theta for each point
ArrayList<PVector> points = new ArrayList<PVector>();
Long b = Math.round(alpha*Math.sqrt(n)); // number of boundary points
Float theta, r, x, y;
for (int i = 1; i < n + 1; i++) {
r = radius(i, n, b.floatValue());
theta = i * angle.floatValue();
x = r * cos(theta);
y = r * sin(theta);
PVector p = new PVector(x, y);
points.add(p);
}
return points;
}
Float radius(int k, int n, Float b) {
if (k > n - b) {
return 1.0;
} else {
Double r = Math.sqrt(k - 0.5) / Math.sqrt(n - (b+1) / 2);
return r.floatValue();
}
}
void displayTest(ArrayList<PVector> points, Float size) {
for (int i = 0; i < points.size(); i++) {
Float x = size * points.get(i).x;
Float y = size * points.get(i).y;
pushMatrix();
translate(width / 2, height / 2);
ellipse(x, y, 5, 5);
popMatrix();
}
}

Here's my Unity implementation.
Vector2[] Sunflower(int n, float alpha = 0, bool geodesic = false){
float phi = (1 + Mathf.Sqrt(5)) / 2;//golden ratio
float angle_stride = 360 * phi;
float radius(float k, float n, float b)
{
return k > n - b ? 1 : Mathf.Sqrt(k - 0.5f) / Mathf.Sqrt(n - (b + 1) / 2);
}
int b = (int)(alpha * Mathf.Sqrt(n)); //# number of boundary points
List<Vector2>points = new List<Vector2>();
for (int k = 0; k < n; k++)
{
float r = radius(k, n, b);
float theta = geodesic ? k * 360 * phi : k * angle_stride;
float x = !float.IsNaN(r * Mathf.Cos(theta)) ? r * Mathf.Cos(theta) : 0;
float y = !float.IsNaN(r * Mathf.Sin(theta)) ? r * Mathf.Sin(theta) : 0;
points.Add(new Vector2(x, y));
}
return points.ToArray();
}

Related

Plot a point in 3D space perpendicular to a line vector

I'm attempting to calculate a point in 3D space which is orthogonal/perpendicular to a line vector.
So I have P1 and P2 which form the line. I’m then trying to find a point with a radius centred at P1, which is orthogonal to the line.
I'd like to do this using trigonometry, without any programming language specific functions.
At the moment I'm testing how accurate this function is by potting a circle around the line vector.
I also rotate the line vector in 3D space to see what happens to the plotted circle, this is where my results vary.
Some of the unwanted effects include:
The circle rotating and passing through the line vector.
The circle's radius appearing to reducing to zero before growing as the line vector changes direction.
I used this question to get me started, and have since made some adjustments to the code.
Any help with this would be much appreciated - I've spent 3 days drawing circles now. Here's my code so far
//Define points which form the line vector
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;
// Normalize line vector
d = sqrt(dx*dx + dy*dy + dz*dz);
// Line vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;
// Angle and distance to plot point around line vector
angle = 123 * pi/180 //convert to radians
radius = 4;
// Begin calculating point
s = sqrt(v3x*v3x + v3y*v3y + v3z*v3z);
// Calculate v1.
// I have been playing with these variables (v1x, v1y, v1z) to try out different configurations.
v1x = s * v3x;
v1y = s * v3y;
v1z = s * -v3z;
// Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;
// Point in space around the line vector
px = p1x + (radius * (v1x * cos(angle)) + (v2x * sin(angle)));
py = p1y + (radius * (v1y * cos(angle)) + (v2y * sin(angle)));
pz = p1z + (radius * (v1z * cos(angle)) + (v2z * sin(angle)));
EDIT
After wrestling with this for days while in lockdown, I've finally managed to get this working. I'd like to thank MBo and Futurologist for their invaluable input.
Although I wasn't able to get their examples working (more likely due to me being at fault), their answers pointed me in the right direction and to that eureka moment!
The key was in swapping the correct vectors.
So thank you to you both, you really helped me along with this. This is my final (working) code:
//Set some vars
angle = 123 * pi/180;
radius = 4;
//P1 & P2 represent vectors that form the line.
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;
d = sqrt(dx*dx + dy*dy + dz*dz)
//Normalized vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;
//Store vector elements in an array
p = [v3x, v3y, v3z];
//Store vector elements in second array, this time with absolute value
p_abs = [abs(v3x), abs(v3y), abs(v3z)];
//Find elements with MAX and MIN magnitudes
maxval = max(p_abs[0], p_abs[1], p_abs[2]);
minval = min(p_abs[0], p_abs[1], p_abs[2]);
//Initialise 3 variables to store which array indexes contain the (max, medium, min) vector magnitudes.
maxindex = 0;
medindex = 0;
minindex = 0;
//Loop through p_abs array to find which magnitudes are equal to maxval & minval. Store their indexes for use later.
for(i = 0; i < 3; i++) {
if (p_abs[i] == maxval) maxindex = i;
else if (p_abs[i] == minval) minindex = i;
}
//Find the remaining index which has the medium magnitude
for(i = 0; i < 3; i++) {
if (i!=maxindex && i!=minindex) {
medindex = i;
break;
}
}
//Store the maximum magnitude for now.
storemax = (p[maxindex]);
//Swap the 2 indexes that contain the maximum & medium magnitudes, negating maximum. Set minimum magnitude to zero.
p[maxindex] = (p[medindex]);
p[medindex] = -storemax;
p[minindex] = 0;
//Calculate v1. Perpendicular to v3.
s = sqrt(v3x*v3x + v3z*v3z + v3y*v3y);
v1x = s * p[0];
v1y = s * p[1];
v1z = s * p[2];
//Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;
//For each circle point.
circlepointx = p2x + radius * (v1x * cos(angle) + v2x * sin(angle))
circlepointy = p2y + radius * (v1y * cos(angle) + v2y * sin(angle))
circlepointz = p2z + radius * (v1z * cos(angle) + v2z * sin(angle))
Your question is too vague, but I may suppose what you really want.
You have line through two point p1 and p2. You want to build a circle of radius r centered at p1 and perpendicular to the line.
At first find direction vector of this line - you already know how - normalized vector v3.
Now you need arbitrary vector perpendicular to v3: find components of v3 with the largest magnitude and with the second magnitude. For example, abs(v3y) is the largest and abs(v3x) has the second magnitude. Exchange them, negate the largest, and make the third component zero:
p = (-v3y, v3x, 0)
This vector is normal to v3 (their dot product is zero)
Now normalize it
pp = p / length(p)
Now get binormal vector as cross product of v3 and pp (I has unit length, no need to normalize), it is perpendicular to both v3 and pp
b = v3 x pp
Now build needed circle
circlepoint(theta) = p1 + radius * pp * Cos(theta) + radius * b * Sin(theta)
Aslo note that angle in radians is
angle = degrees * pi / 180
#Input:
# Pair of points which determine line L:
P1 = [x_P1, y_P1, z_P1]
P2 = [x_P1, y_P1, z_P1]
# Radius:
Radius = R
# unit vector aligned with the line passing through the points P1 and P2:
V3 = P1 - P2
V3 = V3 / norm(V3)
# from the three basis vectors, e1 = [1,0,0], e2 = [0,1,0], e3 = [0,0,1]
# pick the one that is the most transverse to vector V3
# this means, look at the entries of V3 = [x_V3, y_V3, z_V3] and check which
# one has the smallest absolute value and record its index. Take the coordinate
# vector that has 1 at that selected index. In other words,
# if min( abs(x_V3), abs(y_V)) = abs(y_V3),
# then argmin( abs(x_V3), abs(y_V3), abs(z_V3)) = 2 and so take e = [0,1,0]:
e = [0,0,0]
i = argmin( abs(V3[1]), abs(V3[2]), abs(V3[3]) )
e[i] = 1
# a unit vector perpendicular to both e and V3:
V1 = cross(e, V3)
V1 = V1 / norm(V1)
# third unit vector perpendicular to both V3 and V1:
V2 = cross(V3, V1)
# an arbitrary point on the circle (i.e. equation of the circle with parameter s):
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 )
# E.g. say you want to find point P on the circle, 60 degrees relative to vector V1:
s = pi/3
P = P1 + Radius*( cos(s)*V1 + sin(s)*V2 )
Test example in Python:
import numpy as np
#Input:
# Pair of points which determine line L:
P1 = np.array([1, 1, 1])
P2 = np.array([3, 2, 3])
Radius = 3
V3 = P1 - P2
V3 = V3 / np.linalg.norm(V3)
e = np.array([0,0,0])
e[np.argmin(np.abs(V3))] = 1
V1 = np.cross(e, V3)
V1 = V1 / np.linalg.norm(V3)
V2 = np.cross(V3, V1)
# E.g., say you want to rotate point P along the circle, 60 degrees along rel to V1:
s = np.pi/3
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 )

Super-ellipse Point Picking

https://en.wikipedia.org/wiki/Superellipse
I have read the SO questions on how to point-pick from a circle and an ellipse.
How would one uniformly select random points from the interior of a super-ellipse?
More generally, how would one uniformly select random points from the interior of the curve described by an arbitrary super-formula?
https://en.wikipedia.org/wiki/Superformula
The discarding method is not considered a solution, as it is mathematically unenlightening.
In order to sample the superellipse, let's assume without loss of generality that a = b = 1. The general case can be then obtained by rescaling the corresponding axis.
The points in the first quadrant (positive x-coordinate and positive y-coordinate) can be then parametrized as:
x = r * ( cos(t) )^(2/n)
y = r * ( sin(t) )^(2/n)
with 0 <= r <= 1 and 0 <= t <= pi/2:
Now, we need to sample in r, t so that the sampling transformed into x, y is uniform. To this end, let's calculate the Jacobian of this transform:
dx*dy = (2/n) * r * (sin(2*t)/2)^(2/n - 1) dr*dt
= (1/n) * d(r^2) * d(f(t))
Here, we see that as for the variable r, it is sufficient to sample uniformly the value of r^2 and then transform back with a square root. The dependency on t is a bit more complicated. However, with some effort, one gets
f(t) = -(n/2) * 2F1(1/n, (n-1)/n, 1 + 1/n, cos(t)^2) * cos(t)^(2/n)
where 2F1 is the hypergeometric function.
In order to obtain uniform sampling in x,y, we need now to sample uniformly the range of f(t) for t in [0, pi/2] and then find the t which corresponds to this sampled value, i.e., to solve for t the equation u = f(t) where u is a uniform random variable sampled from [f(0), f(pi/2)]. This is essentially the same method as for r, nevertheless in that case one can calculate the inverse directly.
One small issue with this approach is that the function f is not that well-behaved near zero - the infinite slope makes it quite challenging to find a root of u = f(t). To circumvent this, we can sample only the "upper part" of the first quadrant (i.e., area between lines x=y and x=0) and then obtain all the other points by symmetry (not only in the first quadrant but also for all the other ones).
An implementation of this method in Python could look like:
import numpy as np
from numpy.random import uniform, randint, seed
from scipy.optimize import brenth, ridder, bisect, newton
from scipy.special import gamma, hyp2f1
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
seed(100)
def superellipse_area(n):
#https://en.wikipedia.org/wiki/Superellipse#Mathematical_properties
inv_n = 1. / n
return 4 * ( gamma(1 + inv_n)**2 ) / gamma(1 + 2*inv_n)
def sample_superellipse(n, num_of_points = 2000):
def f(n, x):
inv_n = 1. / n
return -(n/2)*hyp2f1(inv_n, 1 - inv_n, 1 + inv_n, x)*(x**inv_n)
lb = f(n, 0.5)
ub = f(n, 0.0)
points = [None for idx in range(num_of_points)]
for idx in range(num_of_points):
r = np.sqrt(uniform())
v = uniform(lb, ub)
w = bisect(lambda w: f(n, w**n) - v, 0.0, 0.5**(1/n))
z = w**n
x = r * z**(1/n)
y = r * (1 - z)**(1/n)
if uniform(-1, 1) < 0:
y, x = x, y
x = (2*randint(0, 2) - 1)*x
y = (2*randint(0, 2) - 1)*y
points[idx] = [x, y]
return points
def plot_superellipse(ax, n, points):
coords_x = [p[0] for p in points]
coords_y = [p[1] for p in points]
ax.set_xlim(-1.25, 1.25)
ax.set_ylim(-1.25, 1.25)
ax.text(-1.1, 1, '{n:.1f}'.format(n = n), fontsize = 12)
ax.scatter(coords_x, coords_y, s = 0.6)
params = np.array([[0.5, 1], [2, 4]])
fig = plt.figure(figsize = (6, 6))
gs = gridspec.GridSpec(*params.shape, wspace = 1/32., hspace = 1/32.)
n_rows, n_cols = params.shape
for i in range(n_rows):
for j in range(n_cols):
n = params[i, j]
ax = plt.subplot(gs[i, j])
if i == n_rows-1:
ax.set_xticks([-1, 0, 1])
else:
ax.set_xticks([])
if j == 0:
ax.set_yticks([-1, 0, 1])
else:
ax.set_yticks([])
#ensure that the ellipses have similar point density
num_of_points = int(superellipse_area(n) / superellipse_area(2) * 4000)
points = sample_superellipse(n, num_of_points)
plot_superellipse(ax, n, points)
fig.savefig('fig.png')
This produces:

Perlin noise for terrain generation

I'm trying to implement 2D Perlin noise to create Minecraft-like terrain (Minecraft doesn't actually use 2D Perlin noise) without overhangs or caves and stuff.
The way I'm doing it, is by creating a [50][20][50] array of cubes, where [20] will be the maximum height of the array, and its values will be determined with Perlin noise. I will then fill that array with arrays of cube.
I've been reading from this article and I don't understand, how do I compute the 4 gradient vector and use it in my code? Does every adjacent 2D array such as [2][3] and [2][4] have a different 4 gradient vector?
Also, I've read that the general Perlin noise function also takes a numeric value that will be used as seed, where do I put that in this case?
I'm going to explain Perlin noise using working code, and without relying on other explanations. First you need a way to generate a pseudo-random float at a 2D point. Each point should look random relative to the others, but the trick is that the same coordinates should always produce the same float. We can use any hash function to do that - not just the one that Ken Perlin used in his code. Here's one:
static float noise2(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
return (float) (1.0-((n*(n*n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0);
}
I use this to generate a "landscape" landscape[i][j] = noise2(i,j); (which I then convert to an image) and it always produces the same thing:
...
But that looks too random - like the hills and valleys are too densely packed. We need a way of "stretching" each random point over, say, 5 points. And for the values between those "key" points, you want a smooth gradient:
static float stretchedNoise2(float x_float, float y_float, float stretch) {
// stretch
x_float /= stretch;
y_float /= stretch;
// the whole part of the coordinates
int x = (int) Math.floor(x_float);
int y = (int) Math.floor(y_float);
// the decimal part - how far between the two points yours is
float fractional_X = x_float - x;
float fractional_Y = y_float - y;
// we need to grab the 4x4 nearest points to do cubic interpolation
double[] p = new double[4];
for (int j = 0; j < 4; j++) {
double[] p2 = new double[4];
for (int i = 0; i < 4; i++) {
p2[i] = noise2(x + i - 1, y + j - 1);
}
// interpolate each row
p[j] = cubicInterp(p2, fractional_X);
}
// and interpolate the results each row's interpolation
return (float) cubicInterp(p, fractional_Y);
}
public static double cubicInterp(double[] p, double x) {
return cubicInterp(p[0],p[1],p[2],p[3], x);
}
public static double cubicInterp(double v0, double v1, double v2, double v3, double x) {
double P = (v3 - v2) - (v0 - v1);
double Q = (v0 - v1) - P;
double R = v2 - v0;
double S = v1;
return P * x * x * x + Q * x * x + R * x + S;
}
If you don't understand the details, that's ok - I don't know how Math.cos() is implemented, but I still know what it does. And this function gives us stretched, smooth noise.
->
The stretchedNoise2 function generates a "landscape" at a certain scale (big or small) - a landscape of random points with smooth slopes between them. Now we can generate a sequence of landscapes on top of each other:
public static double perlin2(float xx, float yy) {
double noise = 0;
noise += stretchedNoise2(xx, yy, 5) * 1; // sample 1
noise += stretchedNoise2(xx, yy, 13) * 2; // twice as influential
// you can keep repeating different variants of the above lines
// some interesting variants are included below.
return noise / (1+2); // make sure you sum the multipliers above
}
To put it more accurately, we get the weighed average of the points from each sample.
( + 2 * ) / 3 =
When you stack a bunch of smooth noise together, usually about 5 samples of increasing "stretch", you get Perlin noise. (If you understand the last sentence, you understand Perlin noise.)
There are other implementations that are faster because they do the same thing in different ways, but because it is no longer 1983 and because you are getting started with writing a landscape generator, you don't need to know about all the special tricks and terminology they use to understand Perlin noise or do fun things with it. For example:
1) 2) 3)
// 1
float smearX = interpolatedNoise2(xx, yy, 99) * 99;
float smearY = interpolatedNoise2(xx, yy, 99) * 99;
ret += interpolatedNoise2(xx + smearX, yy + smearY, 13)*1;
// 2
float smearX2 = interpolatedNoise2(xx, yy, 9) * 19;
float smearY2 = interpolatedNoise2(xx, yy, 9) * 19;
ret += interpolatedNoise2(xx + smearX2, yy + smearY2, 13)*1;
// 3
ret += Math.cos( interpolatedNoise2(xx , yy , 5)*4) *1;
About perlin noise
Perlin noise was developed to generate a random continuous surfaces (actually, procedural textures). Its main feature is that the noise is always continuous over space.
From the article:
Perlin noise is function for generating coherent noise over a space. Coherent noise means that for any two points in the space, the value of the noise function changes smoothly as you move from one point to the other -- that is, there are no discontinuities.
Simply, a perlin noise looks like this:
_ _ __
\ __/ \__/ \__
\__/
But this certainly is not a perlin noise, because there are gaps:
_ _
\_ __/
___/ __/
Calculating the noise (or crushing gradients!)
As #markspace said, perlin noise is mathematically hard. Lets simplify by generating 1D noise.
Imagine the following 1D space:
________________
Firstly, we define a grid (or points in 1D space):
1 2 3 4
________________
Then, we randomly chose a noise value to each grid point (This value is equivalent to the gradient in the 2D noise):
1 2 3 4
________________
-1 0 0.5 1 // random noise value
Now, calculating the noise value for a grid point it is easy, just pick the value:
noise(3) => 0.5
But the noise value for a arbitrary point p needs to be calculated based in the closest grid points p1 and p2 using their value and influence:
// in 1D the influence is just the distance between the points
noise(p) => noise(p1) * influence(p1) + noise(p2) * influence(p2)
noise(2.5) => noise(2) * influence(2, 2.5) + noise(3) * influence(3, 2.5)
=> 0 * 0.5 + 0.5 * 0.5 => 0.25
The end! Now we are able to calculate 1D noise, just add one dimension for 2D. :-)
Hope it helps you understand! Now read #mk.'s answer for working code and have happy noises!
Edit:
Follow up question in the comments:
I read in wikipedia article that the gradient vector in 2d perlin should be length of 1 (unit circle) and random direction. since vector has X and Y, how do I do that exactly?
This could be easily lifted and adapted from the original perlin noise code. Find bellow a pseudocode.
gradient.x = random()*2 - 1;
gradient.y = random()*2 - 1;
normalize_2d( gradient );
Where normalize_2d is:
// normalizes a 2d vector
function normalize_2d(v)
size = square_root( v.x * v.x + v.y * v.y );
v.x = v.x / size;
v.y = v.y / size;
Compute Perlin noise at coordinates x, y
function perlin(float x, float y) {
// Determine grid cell coordinates
int x0 = (x > 0.0 ? (int)x : (int)x - 1);
int x1 = x0 + 1;
int y0 = (y > 0.0 ? (int)y : (int)y - 1);
int y1 = y0 + 1;
// Determine interpolation weights
// Could also use higher order polynomial/s-curve here
float sx = x - (double)x0;
float sy = y - (double)y0;
// Interpolate between grid point gradients
float n0, n1, ix0, ix1, value;
n0 = dotGridGradient(x0, y0, x, y);
n1 = dotGridGradient(x1, y0, x, y);
ix0 = lerp(n0, n1, sx);
n0 = dotGridGradient(x0, y1, x, y);
n1 = dotGridGradient(x1, y1, x, y);
ix1 = lerp(n0, n1, sx);
value = lerp(ix0, ix1, sy);
return value;
}

Trilateration with limits?

I'm in need of help solving an issue, the problem came up doing one of my small robot experiments, the basic idea, is that each little robot has the ability to approximate the distance, from themselves to an object, however the approximate I'm getting is way too rough, and I'm hoping to calculate something more accurate.
So:
Input: A list of vertex (v_1, v_2, ... v_n), a vertex v_* (robots)
Output: The coordinates for the unknown vertex v_* (object)
Each vertex v_1 to v_n's coordinates are well known (supplied by calling getX() and getY() on the vertex), and its possible to get the approximate range to v_* by calling; getApproximateDistance(v_*), function getApproximateDistance() returns two variables variables, that is; minDistance and maxDistance. - The actual distance lies in between these.
So what I've been trying to do to obtain the coordinates for v_*, is to use trilateration, however I can't seem to find a formula for doing trilateration with limits (lower and upperbound), so that's really what I'm looking for (not really good enough at math, to figure it out myself).
Note: is triangulation the way to go instead?
Note: I would possibly love to know a way to do, performance/accuracy trade-offs.
An example of data:
[Vertex . `getX()` . `getY()` . `minDistance` . `maxDistance`]
[`v_1` . 2 . 2 . 0.5 . 1 ]
[`v_2` . 1 . 2 . 0.3 . 1 ]
[`v_3` . 1.5 . 1 . 0.3 . 0.5]
Picture to show data: http://img52.imageshack.us/img52/6414/unavngivetcb.png
It's obvious that the approximate for v_1 can be better, than [0.5; 1], as the figure that the above data creates is small cut of a annulus (limited by v_3), however how would I calculate that, and possibly find the approximate within that figure (this figure is possibly concave)?
Would this be better suited for MathOverflow?
I would go for a simple discrete approach. The implicit formula for an annulus is trivial and the intersection of multiple annulus if the number of them is high can be computed somewhat efficently with a scanline based approach.
For getting high accuracy with a fast computation an option could be using a multiresolution approach (i.e. first starting in low-res and then recomputing in high-res only samples that are close to a valid point.
A small python toy I wrote can generate a 400x400 pixel image of the intersection area in about 0.5 secs (this is the kind of computation that would get a 100x speedup if done with C).
# x, y, r0, r1
data = [(2.0, 2.0, 0.5, 1.0),
(1.0, 2.0, 0.3, 1.0),
(1.5, 1.0, 0.3, 0.5)]
x0 = max(x - r1 for x, y, r0, r1 in data)
y0 = max(y - r1 for x, y, r0, r1 in data)
x1 = min(x + r1 for x, y, r0, r1 in data)
y1 = min(y + r1 for x, y, r0, r1 in data)
def hit(x, y):
for cx, cy, r0, r1 in data:
if not (r0**2 <= ((x - cx)**2 + (y - cy)**2) <= r1**2):
return False
return True
res = 400
step = 16
white = chr(255)
grey = chr(192)
black = chr(0)
img = [black] * (res * res)
# Low-res pass
cells = {}
for i in xrange(0, res, step):
y = y0 + i * (y1 - y0) / res
for j in xrange(0, res, step):
x = x0 + j * (x1 - x0) / res
if hit(x, y):
for h in xrange(-step*2, step*3, step):
for v in xrange(-step*2, step*3, step):
cells[(i+v, j+h)] = True
# High-res pass
for i in xrange(0, res, step):
for j in xrange(0, res, step):
if cells.get((i, j), False):
img[i * res + j] = grey
img[(i + step - 1) * res + j] = grey
img[(i + step - 1) * res + (j + step - 1)] = grey
img[i * res + (j + step - 1)] = grey
for v in xrange(step):
y = y0 + (i + v) * (y1 - y0) / res
for h in xrange(step):
x = x0 + (j + h) * (x1 - x0) / res
if hit(x, y):
img[(i + v)*res + (j + h)] = white
open("result.pgm", "wb").write(("P5\n%i %i 255\n" % (res, res)) +
"".join(img))
Another interesting option could be using a GPU if available. Starting from a white picture and drawing in black the exterior of each annulus will leave at the end the intersection area in white.
For example with Python/Qt the code for doing this computation is simply:
img = QImage(res, res, QImage.Format_RGB32)
dc = QPainter(img)
dc.fillRect(0, 0, res, res, QBrush(QColor(255, 255, 255)))
dc.setPen(Qt.NoPen)
dc.setBrush(QBrush(QColor(0, 0, 0)))
for x, y, r0, r1 in data:
xa1 = (x - r1 - x0) * res / (x1 - x0)
xb1 = (x + r1 - x0) * res / (x1 - x0)
ya1 = (y - r1 - y0) * res / (y1 - y0)
yb1 = (y + r1 - y0) * res / (y1 - y0)
xa0 = (x - r0 - x0) * res / (x1 - x0)
xb0 = (x + r0 - x0) * res / (x1 - x0)
ya0 = (y - r0 - y0) * res / (y1 - y0)
yb0 = (y + r0 - y0) * res / (y1 - y0)
p = QPainterPath()
p.addEllipse(QRectF(xa0, ya0, xb0-xa0, yb0-ya0))
p.addEllipse(QRectF(xa1, ya1, xb1-xa1, yb1-ya1))
p.addRect(QRectF(0, 0, res, res))
dc.drawPath(p)
and the computation part for an 800x800 resolution image takes about 8ms (and I'm not sure it's hardware accelerated).
If only the barycenter of the intersection is to be computed then there is no memory allocation at all. For example a "brute-force" approach is just a few lines of C
typedef struct TReading {
double x, y, r0, r1;
} Reading;
int hit(double xx, double yy,
Reading *readings, int num_readings)
{
while (num_readings--)
{
double dx = xx - readings->x;
double dy = yy - readings->y;
double d2 = dx*dx + dy*dy;
if (d2 < readings->r0 * readings->r0) return 0;
if (d2 > readings->r1 * readings->r1) return 0;
readings++;
}
return 1;
}
int computeLocation(Reading *readings, int num_readings,
int resolution,
double *result_x, double *result_y)
{
// Compute bounding box of interesting zone
double x0 = -1E20, y0 = -1E20, x1 = 1E20, y1 = 1E20;
for (int i=0; i<num_readings; i++)
{
if (readings[i].x - readings[i].r1 > x0)
x0 = readings[i].x - readings[i].r1;
if (readings[i].y - readings[i].r1 > y0)
y0 = readings[i].y - readings[i].r1;
if (readings[i].x + readings[i].r1 < x1)
x1 = readings[i].x + readings[i].r1;
if (readings[i].y + readings[i].r1 < y1)
y1 = readings[i].y + readings[i].r1;
}
// Scan processing
double ax = 0, ay = 0;
int total = 0;
for (int i=0; i<=resolution; i++)
{
double yy = y0 + i * (y1 - y0) / resolution;
for (int j=0; j<=resolution; j++)
{
double xx = x0 + j * (x1 - x0) / resolution;
if (hit(xx, yy, readings, num_readings))
{
ax += xx; ay += yy; total += 1;
}
}
}
if (total)
{
*result_x = ax / total;
*result_y = ay / total;
}
return total;
}
And on my PC can compute the barycenter with resolution = 100 in 0.08 ms (x=1.50000, y=1.383250) or with resolution = 400 in 1.3ms (x=1.500000, y=1.383308). Of course a double-step speedup could be implemented even for the barycenter-only version.
I would switch from "max/min" to trying to minimize an error function. That gets you to the problem discussed at Finding a point that best fits the intersection of n spheres which is more tractable than intersecting a series of complicated shapes. (And what if one robot's sensor is messed up and it gives an impossible value? That variation will still usually give a reasonable answer.)
Not sure about your case, but in a typical robotics application you're going to be reading sensors periodically and crunching the data. If that's the case, you're trying to estimate the location based on noisy data and that's a common problem. As a simple (less rigorous) method, you could take the existing position and adjust it toward or away from each known point. Take the measured distance to target minus the present distance to target, multiply that delta (error) by some value between 0 and 1, and move your estimated position that much toward the target. Repeat for each target. Then repeat each time you get a new set of measurements. The multiplier will have an effect like a low-pass filter, smaller values will give you a more stable position estimate with slower response to movement. For the distance, use the average of the min and max. If you can put tighter bounds on the range to one target, you can increase the multiplier closer to 1 for just that target.
This is of course a crude position estimator. The math guys can probably be more rigorous, but also more complicated. The solution is definitely not anything to do with intersecting areas and working with geometric shapes.

Draw Lines Over a Circle

There's a line A-B and C at the center between A and B. It forms a circle as in the figure. If we assume A-B line as a diameter of the circle and then C is it's center. My problem is I have no idea how to draw another three lines (in blue) each 45 degree away from AC or AB. No, this is not a homework, it's part of my complex geometry in a rendering.
alt text http://www.freeimagehosting.net/uploads/befcd84d8c.png
There are a few ways to solve this problem, one of which is to find the angle of the line and then add 45 degrees to this a few times. Here's an example, it's in Python, but translating the math should be easy (and I've tried to write the Python in a simplistic way).
Here's the output for a few lines:
The main function is calc_points, the rest is just to give it A and B that intersect the circle, and make the plots.
from math import atan2, sin, cos, sqrt, pi
from matplotlib import pyplot
def calc_points(A, B, C):
dx = C[0]-A[0]
dy = C[1]-A[1]
line_angle = atan2(dy, dx)
radius = sqrt(dy*dy + dx*dx)
new_points = []
# now go around the circle and find the points
for i in range(3):
angle = line_angle + (i+1)*45*(pi/180) # new angle in radians
x = radius*cos(angle) + C[0]
y = radius*sin(angle) + C[1]
new_points.append([x, y])
return new_points
# test this with some reasonable values
pyplot.figure()
for i, a in enumerate((-20, 20, 190)):
radius = 5
C = [2, 2]
# find an A and B on the circle and plot them
angle = a*(pi/180)
A = [radius*cos(pi+angle)+C[0], radius*sin(pi+angle)+C[1]]
B = [radius*cos(angle)+C[0], radius*sin(angle)+C[1]]
pyplot.subplot(1,3,i+1)
pyplot.plot([A[0], C[0]], [A[1], C[1]], 'r')
pyplot.plot([B[0], C[0]], [B[1], C[1]], 'r')
# now run these through the calc_points function and the new lines
new_points = calc_points(A, B, C)
for np in new_points:
pyplot.plot([np[0], C[0]], [np[1], C[1]], 'b')
pyplot.xlim(-8, 8)
pyplot.ylim(-8, 8)
for x, X in (("A", A), ("B", B), ("C", C)):
pyplot.text(X[0], X[1], x)
pyplot.show()
If you want to find coordinates of blue lines, may be you will find helpful some information about tranformations (rotations):
http://en.wikipedia.org/wiki/Rotation_matrix
You need to rotate for example vector AC and then you can find coordinate of end point of blue line.
start with this and add a button with code:
private void btnCircleLined_Click(object sender, System.EventArgs e)
{
Graphics graph = Graphics.FromImage(DrawArea);
int x = 100, y = 100, diameter = 50;
myPen.Color = Color.Green;
myPen.Width = 10;
graph.DrawEllipse(myPen, x, y, diameter, diameter);
myPen.Color = Color.Red;
double radian = 45 * Math.PI / 180;
int xOffSet = (int)(Math.Cos(radian) * diameter / 2);
int yOffSet = (int)(Math.Sin(radian) * diameter / 2);
graph.DrawLine(myPen, x, y + yOffSet + myPen.Width + diameter / 2, x + xOffSet + myPen.Width + diameter / 2, y);
graph.DrawLine(myPen, x, y, x + xOffSet + myPen.Width + diameter / 2, y + yOffSet + myPen.Width + diameter / 2);
graph.Dispose();
this.Invalidate();
}
edit: could not see your picture so I misinterpeted your question, but this should get you started.
Translate A with C at the origin (i.e. A-C), rotate CW 45°, then translate back. Repeat three more times.
If I were doing this I'd use polar co-ordinates (apologies for including the link if you are already well aware what they are) as an easy way of figuring out the co-ordinates of the points on the circumference that you need. Then draw lines to there from the centre of the circle.

Resources