I am trying to produce a distribution for points within a circle where there are more towards the center, but for a donut shape
I can produce a uniformly distributed donut shape (1), or a circle where there are more points towards the center (2) but not a donut shape that has so many points towards its inside boundary.
(1)
r = sqrt(runif(250, min = 0.25, max =1))
p = runif(250)
theta = p *2*pi
a = r * cos(theta) #coordinates for circle
b = r * sin(theta)
plot(a,b)
(2)
r = runif(250)
p = runif(250)
theta = p *2*pi
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
My closest attempt is modifying program (2) where r is bound between 0.5 and 1 but this removes most of the points closest to the center and does not have as many around its inside.
As #RobertDodier said, try to use some advanced distribution for radius. What I would like to propose is Beta distribution.
First, it is naturally in the [0...1] range, no need to truncate, accept/reject etc.
Second, it has two parameters (a,b) which could be used to get single peak, zero at 0, and slope to 1. Look at graphs in the wiki page. And last, it is implemented in R. a being smaller than b means peak is on the lef of 0.5, a being larger than b means peak is on the right of 0.5.
Along the lines
N = 10000
r = rbeta(N, 7.0, 5.0)
theta = 2.0*pi*runif(N)
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
will produce plot like that
Does it look like at donut?
UPDATE
This one is with clear hole at the center and shape proposed by #RobertDodier
N = 10000
hole = 0.25
r = hole + (1.0-hole)*rbeta(N, 1.0, 3.0)
theta = 2.0*pi*runif(N)
a = r * cos(theta)
b = r * sin(theta)
plot(a,b)
Another one with clear hole in the center and symmetric shape, like a true donut
r = hole + (1.0-hole)*rbeta(N, 2.0, 2.0)
Related
I am getting familiar with 3D representations. I want to check if a set of trivariate data points falls inside an specific region. For gaussian data this may be easily done using something like:
data = cbind(rnorm(1000),rnorm(1000),rnorm(1000))
inside = data[,1]^2+data[,2]^2 + data[,3]^2 <= qchisq(0.95,3)
which(inside==T)
But, how can I do this manually? There is an R package called library(ptinpoly) to do so, but it requires a Triangular mesh, and I do not know how to obtain a triangular mesh these trivariate grid points.
b = 30
x = seq(0,1,length.out = b)
grid = expand.grid(x,x)
u = grid[,1]
v = grid[,2]
theta <- 2 * pi * u
phi <- acos(2 * v - 1)
tau = 0.95
polygon =(t(c(0,0,0) + sqrt(qchisq(tau,3))*t(chol(diag(1,3)))%*%
rbind(sin(phi) * cos(theta) ,sin(theta) * sin(phi),cos(phi))))
require(rgl)
plot3d(polygon,col="grey")
Any clue?
Given 2D uniform variable we can generate a uniform distribution in a unit-disk as discussed here.
My problem is similar in that i wish to uniformly sample the intersection area of two intersecting disks where one disk is always the unit-disk and the other can be freely moved and resized like here
I was trying to split the area into two regions (as depicted above) and sample each region individual based on the respected disk. My approach is based on uniform disk algorithm cited above. To sample the first region right of the center line I would restrict theta to be within the two intersection points. Next r would need to be projected based on that theta
such that the points are pushed in the area between our mid line and the radius of the disk. The python sample code can be found here.
u = unifrom2D()
A;B; // Intersection points
for p in allPoints
theta = u.x * (getTheta(A) - getTheta(B)) + getTheta(B)
r = sqrt(u.y + (1- u.y)*length2(lineIntersection(theta)))
p = (r * cos(theta), r * sin(theta))
However this approach is rather expensive and further fails to preserve uniformity. Just to clarify i do not want to use rejection sampling.
I am not sure if this is better than rejection sampling, but here is a solution for uniform sampling of a circle segment (with center angle <= pi) involving the numerical computation of an inverse function. (The uniform sampling of the intersection of two circles can then be composed of the sampling of segments, sectors and triangles - depending on how the intersection can be split into simpler figures.)
First we need to know how to generate a random value Z with given distribution F, i.e. we want
P(Z < x) = F(x) <=> (x = F^-1(y))
P(Z < F^-1(y)) = F(F^-1(y)) = y <=> (F is monotonous)
P(F(Z) < y) = y
This means: if Z has the requested distribution F, then F(Z) is distributed uniformly. The other way round:
Z = F^-1(Y),
where Y is distributed uniformly in [0,1], has the requested distribution.
If F is of the form
/ 0, x < a
F(x) = | (F0(x)-F0(a)) / (F0(b)-F0(a)), a <= x <= b
\ 1, b < x
then we can choose a Y0 uniformly in [F(a),F(b)] and set Z = F0^-1(Y0).
We choose to parametrize the segment by (theta,r), where the center angle theta is measured from one segment side. When the segment's center angle is alpha, the area of the segment intersected with a sector of angle theta starting where the segment starts is (for the unit circle, theta in [0,alpha/2])
F0_theta(theta) = 0.5*(theta - d*(s - d*tan(alpha/2-theta)))
where s = AB/2 = sin(alpha/2) and d = dist(M,AB) = cos(alpha/2) (the distance of the circle center to the segment). (The case alpha/2 <= theta <= alpha is symmetric and not considered here.)
We need a random theta with P(theta < x) = F_theta(x). The inverse of F_theta cannot be computed symbolically - it must be determined by some optimization algorithm (e.g. Newton-Raphson).
Once theta is fixed we need a random radius r in the range
[r_min, 1], r_min = d/cos(alpha/2-theta).
For x in [0, 1-r_min] the distribution must be
F0_r(x) = (x+r_min)^2 - r_min^2 = x^2 + 2*x*r_min.
Here the inverse can be computed symbolically:
F0_r^-1(y) = -r_min + sqrt(r_min^2+y)
Here is an implementation in Python for proof of concept:
from math import sin,cos,tan,sqrt
from scipy.optimize import newton
# area of segment of unit circle
# alpha: center angle of segment (0 <= alpha <= pi)
def segmentArea(alpha):
return 0.5*(alpha - sin(alpha))
# generate a function that gives the area of a segment of a unit circle
# intersected with a sector of given angle, where the sector starts at one end of the segment.
# The returned function is valid for [0,alpha/2].
# For theta=alpha/2 the returned function gives half of the segment area.
# alpha: center angle of segment (0 <= alpha <= pi)
def segmentAreaByAngle_gen(alpha):
alpha_2 = 0.5*alpha
s,d = sin(alpha_2),cos(alpha_2)
return lambda theta: 0.5*(theta - d*(s - d*tan(alpha_2-theta)))
# generate derivative function generated by segmentAreaByAngle_gen
def segmentAreaByAngleDeriv_gen(alpha):
alpha_2 = 0.5*alpha
d = cos(alpha_2)
return lambda theta: (lambda dr = d/cos(alpha_2-theta): 0.5*(1 - dr*dr))()
# generate inverse of function generated by segmentAreaByAngle_gen
def segmentAreaByAngleInv_gen(alpha):
x0 = sqrt(0.5*segmentArea(alpha)) # initial guess by approximating half of segment with right-angled triangle
return lambda area: newton(lambda theta: segmentAreaByAngle_gen(alpha)(theta) - area, x0, segmentAreaByAngleDeriv_gen(alpha))
# for a segment of the unit circle in canonical position
# (i.e. symmetric to x-axis, on positive side of x-axis)
# generate uniformly distributed random point in upper half
def randomPointInSegmentHalf(alpha):
FInv = segmentAreaByAngleInv_gen(alpha)
areaRandom = random.uniform(0,0.5*segmentArea(alpha))
thetaRandom = FInv(areaRandom)
alpha_2 = 0.5*alpha
d = cos(alpha_2)
rMin = d/cos(alpha_2-thetaRandom)
secAreaRandom = random.uniform(0, 1-rMin*rMin)
rRandom = sqrt(rMin*rMin + secAreaRandom)
return rRandom*cos(alpha_2-thetaRandom), rRandom*sin(alpha_2-thetaRandom)
The visualisation seems to verify uniform distribution (of the upper half of a segment with center angle pi/2):
import matplotlib.pyplot as plot
segmentPoints = [randomPointInSegmentHalf(pi/2) for _ in range(500)]
plot.scatter(*zip(*segmentPoints))
plot.show()
I have a normalized direction vector (from a 3d position to a light position) and I would like this vector to be rotated by some angle so I can create a "cone".
Id like to simulate cone tracing by using the direction vector as the center of the cone and create an X number of samples to create more rays to sample from.
What I would like to know is basically the math behind:
https://docs.unrealengine.com/latest/INT/BlueprintAPI/Math/Random/RandomUnitVectorinCone/index.html
Which seems to do exactly what Im looking for.
1) Make arbitrary vector P, perpendicular to your direction vector D.
You can choose component with max magnitude, exchange it with middle-magnitude component, negate it, and make min magnitude component zero.
For example, if z- component is maximal and y-component is minimal, you may make such P:
D = (dx, dy, dz)
p = (-dz, 0, dx)
P = Normalize(p) //unit vector
2) Make vector Q perpendicular both D and P through vector product:
Q = D x P //unit vector
3) Generate random point in the PQ plane disk
RMax = Tan(Phi) //where Phi is cone angle
Theta = Random(0..2*Pi)
r = RMax * Sqrt(Random(0..1))
V = r * (P * Cos(Theta) + Q * Sin(Theta))
4) Normalize vector V
Note that distribution of vectors is slightly non-uniform on the sphere segment.(it is uniform on the plane disk). There are methods to generate uniform distribution on the sphere but some work needed to apply them to segment (my first attempt before edit was wrong).
Edit: Modification to make sphere-uniform distribution (not checked thoroughly)
RMax = Tan(Phi) //where Phi is cone angle
Theta = Random(0..2*Pi)
u = Random(Cos(Phi)..1)
r = RMax * Sqrt(1 - u^2)
V = r * (P * Cos(Theta) + Q * Sin(Theta))
I've been doing a lot of research on the topic and found a couple of post that where helpful but I just can't get this right.
I am developing a very simple structural analysis app. In this app I need to display a graph showing the internal stress of the beam. The graph is obtained by the formula:
y = (100 * X / 2) * (L - X)
where L is the known length of the beam (lets say its 1 for simplicity). And X is a value between 0 and the Length of be beam. So the final formula would be:
y = (100 * X / 2) * (1 - x) where 0 < X < 1.
Assuming my start and end points are P0 = (0,0) and P2 = (1,0). How can I obtain P2 (control point)?? I have been searching in the Wikipedia page but I am unsure how to obtain the control point from the quadratic bezier curve formula:
B(t) = (1 - t)^2 * P0 + 2*(1 - t)*t * P1 + t^2 * P2
I'm sure it must be such an easy problem to fix… Can anyone help me out?
P.S.: I also found this, How to find the mathematical function defining a bezier curve, which seems to explain how to do the opposite of what I am trying to achieve. I just can't figure out how to turn it around.
We want the quadratic curve defined by y to match the quadratic Bezier curve
defined by B(t).
Among the many points that must match is the peak which occurs at x =
0.5. When x = 0.5,
y = (100 * x / 2) * (1 - x)
100 1 25
y = ---- * --- = ---- = 12.5
4 2 2
Therefore, let's arrange for B(0.5) = (0.5, 12.5):
B(t) = (1-t)^2*(0,0) + 2*(1-t)*t*(Px, Py) + t^2*(1,0)
(0.5, 12.5) = B(0.5) = (0,0) + 2*(0.5)*(0.5)*(Px, Py) + (0.25)*(1,0)
0.5 = 0.5 * Px + 0.25
12.5 = 0.5 * Py
Solving for Px and Py, we get
(Px, Py) = (0.5, 25)
And here is visual confirmation (in Python) that we've found the right point:
# test.py
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 1, 100)
y = (100*x/2)*(1-x)
t = np.linspace(0, 1, 100)
P0 = np.array([0,0])
P1 = np.array([0.5,25])
P2 = np.array([1,0])
B = ((1-t)**2)[:,np.newaxis]*P0 + 2*((1-t)*t)[:,np.newaxis]*P1 + (t**2)[:,np.newaxis]*P2
plt.plot(x, y)
plt.plot(B[:,0], B[:,1])
plt.show()
Running python test.py, we see the two curves overlap:
How did I know to choose t = 0.5 as the parameter value when B(t) reaches its maximum height?
Well, it was mainly based on intuition, but here is a more formal way to prove it:
The y-component of B'(t) equals 0 when B(t) reaches its maximum height. So, taking the derivative of B(t), we see
0 = 2*(1-2t)*Py
t = 0.5 or Py = 0
If Py = 0 then B(t) is a horizontal line from (0,0) to (1,0). Rejecting this degenerate case, we see B(t) reaches its maximum height when t = 0.5.
Your quadratic bezier curve formula has a typo in the middle term. It should be:
B(t) = (1 - t)^2 * P0 + 2 * (1 - t) * t * P1 + t^2 * P2
This means you should take the P1=(1,50) that #unutbu found and divide the coordinates in half to get P1=(.5,25). (This won't matter if you're plotting the parametric equation on your own, but if you want something like LaTeX's \qbezier(0,0)(.5,25)(1,0), then you'll need the corrected point.)
The P1 control point is defined so that the tangent lines at P0 and P2 intersect at P1. Which means that if (P1)x=(P2)x, the graph should be vertical on its righthand side (which you don't want).
In response to your comment, if you have a quadratic y=f(x), then it is symmetrical about its axis (almost tautologically). So the maximum/minimum will occur at the average of the roots (as well as the control point).
What is best way or an algorithm for generating a random 3d point [x,y,z] inside the volume of the circular cylinder if radius r and height h of the cylinder are given?
How about -- in Python pseudocode, letting R be the radius and H be the height:
s = random.uniform(0, 1)
theta = random.uniform(0, 2*pi)
z = random.uniform(0, H)
r = sqrt(s)*R
x = r * cos(theta)
y = r * sin(theta)
z = z # .. for symmetry :-)
The problem with simply taking x = r * cos(angle) and y = r * sin(angle) is that then when r is small, i.e. at the centre of the circle, a tiny change in r doesn't change the x and y positions very much. IOW, it leads to a nonuniform distribution in Cartesian coordinates, and the points get concentrated toward the centre of the circle. Taking the square root corrects this, at least if I've done my arithmetic correctly.
[Ah, it looks like the sqrt was right.]
(Note that I assumed without thinking about it that the cylinder is aligned with the z-axis and the cylinder centre is located at (0,0,H/2). It'd be less arbitrary to set (0,0,0) at the cylinder centre, in which case z should be chosen to be between -H/2 and H/2, not 0,H.)
Generate a random point inside the rectangular solid circumscribing the cylinder; if it's inside the cylinder (probability pi/4), keep it, otherwise discard it and try again.
Generate a random angle (optionally less than 2π), a random r less than the radius, and a random z less than the height.
x = r * cos(angle)
y = r * sin(angle)
The z axis is easy: -0.5 * h <= z <= 0.5 * h
The x and y are equal to a circle will be:
x^2 + y^2 <= r^2
Buth math is long ago for me :-)