I am attempting to sample along multiple lines (roads) at regular intervals and am struggling to obtain exact perpendicular angles for each road segment. I have split each road into points giving the node at which each line changes orientation and what I have so far creates a point within a straight segment of each road and appears to be working fine.
This is the code I am using to produce perpendicular angles for each node segment.
# X and Y for 3 points along a line
road_node <- matrix(
c(
381103, 381112, 381117,
370373, 370301, 370290
),
ncol = 2,
)
road_node <- as.data.frame(road_node)
angle_inv <- c()
for (i in 2:nrow(road_node) - 1) {
n1 <- road_node[i, ]
n2 <- road_node[i + 1, ]
x <- as.numeric(n1[1] - n2[1])
y <- as.numeric(n1[2] - n2[2])
ang <- atan2(y, x) + 1 / 2 * pi
if (!is.na(ang) && ang < 0) {
ang <- 2 + ang
}
angle_inv <- rbind(angle_inv, ang)
}
Where road_node gives the coordinates of each node.
From this I take the mid points and the inverse angles to create two points either side of the mid points, to produce a line segment.
# X Y and Angles (angles for one segment are the same
mids <- matrix(
c(
381374.5, 381351.0, 381320.5,
371590.5,371560.0, 371533.590,
2.3, 2.3, 2.3
),
nrow = 3,
)
mids <- as.data.frame(mids)
pts <- c()
for (i in 1:nrow(mids)) {
x1 <- mids[i, 1] + 10 * cos(mids[i, 3])
y1 <- mids[i, 2] + 10 * sin(mids[i, 3])
x2 <- mids[i, 1] - 10 * cos(mids[i, 3])
y2 <- mids[i, 2] - 10 * sin(mids[i, 3])
p1 <- cbind(x1, y1)
p2 <- cbind(x2, y2)
pair <- rbind(p1, p2)
pts <- rbind(pts, pair)
}
Some line segments appear to be correctly perpendicular to the node they are associate with, however some are not. Each appear to correctly share the same length.
I believe the problem lies with either how I am selecting my angles using atan2, or with how I am selecting my points either side of the node segment.
Firstly, there's no need to use trigonometry to solve this. Instead you can use the inverse reciprocal of the slope intercept form of the line segment equation, then calculate points on a perpendicular line passing through a give point.
See Equation from 2 points using Slope Intercept Form
Also your mid points appear incorrect and there are only 2 mid points as 3 points = 2 line segments.
This code appears to work fine
# Function to calculate mid points
mid_point <- function(p1,p2) {
return(c(p1[1] + (p2[1] - p1[1]) / 2,p1[2] + (p2[2] - p1[2]) / 2))
}
# Function to calculate slope of line between 2 points
slope <- function(p1,p2) {
return((p2[2] - p1[2]) / (p2[1] - p1[1]))
}
# Function to calculate intercept of line passing through given point wiht slope m
calc_intercept <- function(p,m) {
return(p[2] - m * p[1])
}
# Function to calculate y for a given x, slope m and intercept b
calc_y <- function(x,m,b) {
return(c(x, m * x + b))
}
# X and Y for 3 points along a line
road_node <- matrix(
c(
381103, 381112, 381117,
370373, 370301, 370290
),
ncol = 2,
)
road_node <- as.data.frame(road_node)
perp_segments <- c()
for (i in 2:nrow(road_node) - 1) {
n1 <- road_node[i, ]
n2 <- road_node[i + 1, ]
# Calculate mid point
mp <- mid_point(n1,n2)
# Calculate slope
m <- slope(n1,n2)
# Calculate intercept subsituting n1
b <- calc_intercept(n1,m)
# Calculate inverse reciprocal of slope
new_m <- -1.0 / m
# Calculate intercept of perpendicular line through mid point
new_b <- calc_intercept(mp,new_m)
# Calculate points 10 units away in x direction at mid_point
p1 <- rbind(calc_y(as.numeric(mp[1])-10,new_m,new_b))
p2 <- rbind(calc_y(as.numeric(mp[1])+10,new_m,new_b))
# Add point pair to output vector
pair <- rbind(p1,p2)
perp_segments <- rbind(perp_segments,pair)
}
This is how it looks geometrically (image)
I hope this helps.
Edit 1:
I thought about this more and came up with this simplified function. If you tink of the problem as a right isosceles triangle (45,45,90), then all you need to do is find the point which is the required distance from the reference point interpolated along the line segment, then invert its x and y distances from the reference points, then add and subtract these from the reference point.
Function calc_perp
Arguments:
p1, p2 - two point vectors defining the end points of the line segment
n - the distance from the line segment
interval - the interval along the line segment of the reference point from the start (default 0.5)
proportion - Boolean defining whether the interval is a proportion of the length or a constant (default TRUE)
# Function to calculate Euclidean distance between 2 points
euclidean_distance <-function(p1,p2) {
return(sqrt((p2[1] - p1[1])**2 + (p2[2] - p1[2])**2))
}
# Function to calculate 2 points on a line perpendicular to another defined by 2 points p,p2
# For point at interval, which can be a proportion of the segment length, or a constant
# At distance n from the source line
calc_perp <-function(p1,p2,n,interval=0.5,proportion=TRUE) {
# Calculate x and y distances
x_len <- p2[1] - p1[1]
y_len <- p2[2] - p1[2]
# If proportion calculate reference point from tot_length
if (proportion) {
point <- c(p1[1]+x_len*interval,p1[2]+y_len*interval)
}
# Else use the constant value
else {
tot_len <- euclidean_distance(p1,p2)
point <- c(p1[1]+x_len/tot_len*interval,p1[2]+y_len/tot_len*interval)
}
# Calculate the x and y distances from reference point to point on line n distance away
ref_len <- euclidean_distance(point,p2)
xn_len <- (n / ref_len) * (p2[1] - point[1])
yn_len <- (n / ref_len) * (p2[2] - point[2])
# Invert the x and y lengths and add/subtract from the refrence point
ref_points <- rbind(point,c(point[1] + yn_len,point[2] - xn_len),c(point[1] - yn_len,point[2] + xn_len))
# Return the reference points
return(ref_points)
}
Examples
> calc_perp(c(0,0),c(1,1),1)
[,1] [,2]
point 0.5000000 0.5000000
1.2071068 -0.2071068
-0.2071068 1.2071068
> calc_perp(c(0,0),c(1,1),sqrt(2)/2,0,proportion=FALSE)
[,1] [,2]
point 0.0 0.0
0.5 -0.5
-0.5 0.5
This is how the revised function looks geometrically with your example and n = 10 for distance from line:
Related
Consider the Togliatti implicit surface. I want to clip it to the ball centered at the origin with radius 4.8. A solution, with the misc3d package, consists in using the mask argument of the computeContour3d function, which allows to use only the points satisfying x^2+y^2+z^2 < 4.8^2:
library(misc3d)
# Togliatti surface equation: f(x,y,z) = 0
f <- function(x,y,z){
w <- 1
64*(x-w)*
(x^4-4*x^3*w-10*x^2*y^2-4*x^2*w^2+16*x*w^3-20*x*y^2*w+5*y^4+16*w^4-20*y^2*w^2) -
5*sqrt(5-sqrt(5))*(2*z-sqrt(5-sqrt(5))*w)*(4*(x^2+y^2-z^2)+(1+3*sqrt(5))*w^2)^2
}
# make grid
nx <- 220; ny <- 220; nz <- 220
x <- seq(-5, 5, length=nx)
y <- seq(-5, 5, length=ny)
z <- seq(-4, 4, length=nz)
g <- expand.grid(x=x, y=y, z=z)
# calculate voxel
voxel <- array(with(g, f(x,y,z)), dim = c(nx,ny,nz))
# mask: keep points satisfying x^2+y^2+z^2 < 4.8^2, in order to
# clip the surface to the ball of radius 4.8
mask <- array(with(g, x^2+y^2+z^2 < 4.8^2), dim = c(nx,ny,nz))
# compute isosurface
surf <- computeContour3d(voxel, maxvol=max(voxel), level=0, mask=mask, x=x, y=y, z=z)
# draw isosurface
drawScene.rgl(makeTriangles(surf, smooth=TRUE))
But the borders of the resulting surface are irregular:
How to get regular, smooth borders?
The solution I found resorts to spherical coordinates. It consists in defining the function f in terms of spherical coordinates (ρ, θ, ϕ), then to compute the isosurface with ρ running from 0 to the desired radius, and then to transform the result to Cartesian coordinates:
# Togliatti surface equation with spherical coordinates
f <- function(ρ, θ, ϕ){
w <- 1
x <- ρ*cos(θ)*sin(ϕ)
y <- ρ*sin(θ)*sin(ϕ)
z <- ρ*cos(ϕ)
64*(x-w)*
(x^4-4*x^3*w-10*x^2*y^2-4*x^2*w^2+16*x*w^3-20*x*y^2*w+5*y^4+16*w^4-20*y^2*w^2) -
5*sqrt(5-sqrt(5))*(2*z-sqrt(5-sqrt(5))*w)*(4*(x^2+y^2-z^2)+(1+3*sqrt(5))*w^2)^2
}
# make grid
nρ <- 300; nθ <- 400; nϕ <- 300
ρ <- seq(0, 4.8, length = nρ) # ρ runs from 0 to the desired radius
θ <- seq(0, 2*pi, length = nθ)
ϕ <- seq(0, pi, length = nϕ)
g <- expand.grid(ρ=ρ, θ=θ, ϕ=ϕ)
# calculate voxel
voxel <- array(with(g, f(ρ,θ,ϕ)), dim = c(nρ,nθ,nϕ))
# calculate isosurface
surf <- computeContour3d(voxel, maxvol=max(voxel), level=0, x=ρ, y=θ, z=ϕ)
# transform to Cartesian coordinates
surf <- t(apply(surf, 1, function(rtp){
ρ <- rtp[1]; θ <- rtp[2]; ϕ <- rtp[3]
c(
ρ*cos(θ)*sin(ϕ),
ρ*sin(θ)*sin(ϕ),
ρ*cos(ϕ)
)
}))
# draw isosurface
drawScene.rgl(makeTriangles(surf, smooth=TRUE, color = "violetred"))
Now the resulting surface has regular, smooth borders:
Your solution is excellent for the problem you stated, because spherical coordinates are so natural for that boundary. However, here is a more general solution that would work for other smooth boundaries.
The idea is to allow input of a boundary function, and cull points when they are too large or too small. In your case it would be the squared distance from the origin, and you would want to cull points where the value is bigger than 4.8^2. But sometimes the triangles being drawn to make the smooth surface should only be partially culled: one point would be kept and two deleted, or two kept and one deleted. If you cull the whole triangle that leads to the jagged edges in your original plot.
To fix this, the points can be modified. If only one is supposed to be kept, then the other two points can be shrunk towards it until they lie on an approximation to the boundary. If two are supposed to be kept you want the shape to be a quadrilateral, so you would build that out of two triangles.
This function does that, assuming the input surf is the output of computeContour3d:
boundSurface <- function(surf, boundFn, bound = 0, greater = TRUE) {
# Surf is n x 3: each row is a point, triplets are triangles
values <- matrix(boundFn(surf) - bound, 3)
# values is (m = n/3) x 3: each row is the boundFn value at one point
# of a triangle
if (!greater)
values <- -values
keep <- values >= 0
# counts is m vector counting number of points to keep in each triangle
counts <- apply(keep, 2, sum)
# result is initialized to an empty array
result <- matrix(nrow = 0, ncol = 3)
# singles is set to all the rows of surf where exactly one
# point in the triangle is kept, say s x 3
singles <- surf[rep(counts == 1, each = 3),]
if (length(singles)) {
# singleValues is a subset of values where only one vertex is kept
singleValues <- values[, counts == 1]
singleIndex <- 3*col(singleValues) + 1:3 - 3
# good is the index of the vertex to keep, bad are those to fix
good <- apply(singleValues, 2, function(col) which(col >= 0))
bad <- apply(singleValues, 2, function(col) which(col < 0))
for (j in 1:ncol(singleValues)) {
goodval <- singleValues[good[j], j]
for (i in 1:2) {
badval <- singleValues[bad[i,j], j]
alpha <- goodval/(goodval - badval)
singles[singleIndex[bad[i,j], j], ] <-
(1-alpha)*singles[singleIndex[good[j], j],] +
alpha *singles[singleIndex[bad[i,j], j],]
}
}
result <- rbind(result, singles)
}
doubles <- surf[rep(counts == 2, each = 3),]
if (length(doubles)) {
# doubleValues is a subset of values where two vertices are kept
doubleValues <- values[, counts == 2]
doubleIndex <- 3*col(doubleValues) + 1:3 - 3
doubles2 <- doubles
# good is the index of the vertex to keep, bad are those to fix
good <- apply(doubleValues, 2, function(col) which(col >= 0))
bad <- apply(doubleValues, 2, function(col) which(col < 0))
newvert <- matrix(NA, 2, 3)
for (j in 1:ncol(doubleValues)) {
badval <- doubleValues[bad[j], j]
for (i in 1:2) {
goodval <- doubleValues[good[i,j], j]
alpha <- goodval/(goodval - badval)
newvert[i,] <-
(1-alpha)*doubles[doubleIndex[good[i,j], j],] +
alpha *doubles[doubleIndex[bad[j], j],]
}
doubles[doubleIndex[bad[j], j],] <- newvert[1,]
doubles2[doubleIndex[good[1,j], j],] <- newvert[1,]
doubles2[doubleIndex[bad[j], j],] <- newvert[2,]
}
result <- rbind(result, doubles, doubles2)
}
# Finally add all the rows of surf where the whole
# triangle is kept
rbind(result, surf[rep(counts == 3, each = 3),])
}
You would use it after computeContour3d and before makeTriangles, e.g.
fn <- function(x) {
apply(x^2, 1, sum)
}
drawScene.rgl(makeTriangles(boundSurface(surf, fn, bound = 4.8^2,
greater = FALSE),
smooth = TRUE))
Here's the output I see:
It's not quite as good as yours, but it would work for many different boundary functions.
Edited to add: Version 0.100.26 of rgl now has a function clipMesh3d which incorporates these ideas.
I have specific x,y,z coordinates. I want to generate random points within a sphere given x as the center and x2 from another data frame as the edge of the radius (therefore the distance from x to x2 would be the length of the radius of the sphere).
I've seen a lot of discussion about how to do this appropriately mathematically (randomly distribute the points to avoid clustering) and was able to compile the easiest examples here and here for sample R code.
I also found this [R package sphereplot] (https://cran.r-project.org/web/packages/sphereplot/sphereplot.pdf) which might be easier, but am having a hard time understanding how to apply it.
These are all good starting points but using the sample code below I'm unsure how to apply it to specific starting points/spherical coordinates?
set.seed(101)
n <- 50
theta <- runif(n,0,2*pi)
u <- runif(n,-1,1)
x <- sqrt(1-u^2)*cos(theta)
y <- sqrt(1-u^2)*sin(theta)
z <- u
Using just one set/row of x,y,z coordinates from my data frame:
x = -0.0684486861
y= 0.0125857380
z= 0.0201056441
x2= -0.0684486861
y2 = 0.0125857380
z2= -0.0228805516
I want x,y,z to be the center of the sphere and the distance to x2,y2,z2 to be the radius length/edge of the sphere. Then generate random points from within the sphere with x,y,z as the center.
Eventually, I'm trying to do this with 100 spheres to compare if all the points in the second set of coordinates move in similar angles/directions in space.
Thanks for the guidance.
Well, lets split problem in several subproblems.
First, is generating points uniformly distributed on a sphere (either volumetrically, or on surface), with center at (0,0,0), and given radius. Following http://mathworld.wolfram.com/SpherePointPicking.html, and quite close to code you shown,
rsphere <- function(n, r = 1.0, surface_only = FALSE) {
phi <- runif(n, 0.0, 2.0 * pi)
cos_theta <- runif(n, -1.0, 1.0)
sin_theta <- sqrt((1.0-cos_theta)*(1.0+cos_theta))
radius <- r
if (surface_only == FALSE) {
radius <- r * runif(n, 0.0, 1.0)^(1.0/3.0)
}
x <- radius * sin_theta * cos(phi)
y <- radius * sin_theta * sin(phi)
z <- radius * cos_theta
cbind(x, y, z)
}
set.seed(312345)
sphere_points <- rsphere(10000)
Second problem - move those points to the center at point X
rsphere <- function(n, r = 1.0, surface_only = FALSE, center=cbind(Xx, Xy, Xz)) {
....
cbind(x+center[1], y+center[2], z+center[3])
}
Third problem - compute radius given center at (Xx, Xy, Xz) and surface point(Yx, Yy, Yz))
radius <- sqrt((Xx-Yx)**2+(Xy-Yy)**2+(Xz-Yz)**2)
Combine them all together for a full satisfaction. Ok, now that you provided values for center and radius, let's put it all together
rsphere <- function(n, r = 1.0, surface_only = FALSE, center=cbind(0.0, 0.0, 0.0)) {
phi <- runif(n, 0.0, 2.0 * pi)
cos_theta <- runif(n, -1.0, 1.0)
sin_theta <- sqrt((1.0-cos_theta)*(1.0+cos_theta))
radius <- r
if (surface_only == FALSE) {
radius <- r * runif(n, 0.0, 1.0)^(1.0/3.0)
}
x <- radius * sin_theta * cos(phi)
y <- radius * sin_theta * sin(phi)
z <- radius * cos_theta
# if radius is fixed, we could check it
# rr = sqrt(x^2+y^2+z^2)
# print(rr)
cbind(x+center[1], y+center[2], z+center[3])
}
x1 = -0.0684486861
y1 = 0.0125857380
z1 = 0.0201056441
x2 = -0.0684486861
y2 = 0.0125857380
z2 = -0.0228805516
R = sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2)
print(R)
set.seed(32345)
sphere_points <- rsphere(100000, R, FALSE, cbind(x1, y1, z1))
How it looks like?
UPDATE
Generated 10 points each on surface and in the volume and printed it, radius=2 looks ok to me
# 10 points uniform on surface, supposed to have fixed radius
sphere_points <- rsphere(10, 2, TRUE, cbind(x1, y1, z1))
for (k in 1:10) {
rr <- sqrt((sphere_points[k,1]-x1)^2+(sphere_points[k,2]-y1)^2+(sphere_points[k,3]-z1)^2)
print(rr)
}
# 10 points uniform in the sphere, supposed to have varying radius
sphere_points <- rsphere(10, 2, FALSE, cbind(x1, y1, z1))
for (k in 1:10) {
rr <- sqrt((sphere_points[k,1]-x1)^2+(sphere_points[k,2]-y1)^2+(sphere_points[k,3]-z1)^2)
print(rr)
}
got
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
[1] 2
and
[1] 1.32571
[1] 1.505066
[1] 1.255023
[1] 1.82773
[1] 1.219957
[1] 1.641258
[1] 1.881937
[1] 1.083975
[1] 0.4745712
[1] 1.900066
what did you get?
For a perceptual task, I wish to simulate multiple items, each consisting of a plotted single line with two 'breaking points' where the line abruptly changes direction. So in essence the line consists of three connected line segments (AB, BC, and CD), connecting four coordinates (Axy, Bxy, Cxy, Dyx), each with a different slope.
The line must agree with the following three conditions:
1) The total length of the line (L), which is the sum of the length of the three line segments (AB, BC, and CD) should vary between items, but always fall within the range of l1 and l2.
2) The line should fit within and take up an X*Y sized rectangle. That is, at least one x-coordinate (Ax, Bx, Cx, or Dx) should equal 0, at least one x-coordinate (Ax, Bx, Cx, or Dx) should equal X, at least one y-coordinate (Ay, By, Cy, or Dy) should be 0, at least one y-coordinate (Ay, By, Cy, or Dy) should equal Y; none of the x-coordinates should be lower than 0 or higher than X, none of the y-coordinates should be lower than 0 or higher than Y.
3) The line segments may not cross. That is, line segment AB and CD may not cross (as line BC is connected at one end to both other line segments, it cannot cross them).
I wish to do this in R. So far I've only managed a code wherein a random line is created and the code then checks if it meets all three conditions. If not, it starts anew. This method takes way too long!
Does anyone have an idea how I could make this code more efficient? Current R-code provided below.
#START WHILE LOOP
STOP = FALSE
CONDITION_COUNTER <- c(0,0,0)
while(STOP==FALSE){ #start condition checking loop
#SETTINGS:
l1 = 8 #minimum length L
l2 = 12 #maximum length L
L = runif(1,l1,l2) #length L
X = 5 #width square for length L
Y = 7 #heigth square for length L
#CREATE LINE SEGMENT:
Ax <- runif(1,0,X) #x-coordinate point A
Ay <- runif(1,0,Y) #y-coordinate point A
Bx <- runif(1,0,X) #x-coordinate point B
By <- runif(1,0,Y) #y-coordinate point B
Cx <- runif(1,0,X) #x-coordinate point C
Cy <- runif(1,0,Y) #y-coordinate point C
Dx <- runif(1,0,X) #x-coordinate point D
Dy <- runif(1,0,Y) #y-coordinate point D
#CHECK CONDITION 01 (line has to equal length L)
AB = sqrt((Ax-Bx)^2 + (Ay-By)^2) #length line segment AB
BC = sqrt((Bx-Cx)^2 + (By-Cy)^2) #length line segment BC
CD = sqrt((Cx-Dx)^2 + (Cy-Dy)^2) #length line segment CD
CONDITION_COUNTER[1] <- L == AB + BC + CD #Condition 1 satisfied (1) or not (0)?
#CHECK CONDITION 02 (line has to fill the square)
c1 = sum(c(Ax, Bx, Cx, Dx) == 0) > 0 #does one point have x-coordinate 0?
c2 = sum(c(Ax, Bx, Cx, Dx) == X) > 0 #does one point have x-coordinate X?
c3 = sum(c(Ay, By, Cy, Dy) == 0) > 0 #does one point have y-coordinate 0?
c4 = sum(c(Ay, By, Cy, Dy) == Y) > 0 #does one point have y-coordinate Y?
CONDITION_COUNTER[2] <- sum(c(c1,c2,c3,c4)) == 4 #Condition 2 satisfied (1) or not (0)?
#CHECK CONDITION 03 (line segments may not cross)
a <- max(c(Ax,Bx)); b <- min(c(Ax,Bx)); x <- a-b; x
a <- c(Ay,By)[which.max(c(Ax,Bx))]; b <- c(Ay,By)[which.min(c(Ax,Bx))]; y <- a-b; y
slopeAB <- y/x
InterceptAB <- Ay - slopeAB * Ax
c <- max(c(Cx,Dx)); d <- min(c(Cx,Dx)); x <- c-d; x
c <- c(Cy,Dy)[which.max(c(Cx,Dx))]; d <- c(Cy,Dy)[which.min(c(Cx,Dx))]; y <- c-d; y
slopeCD <- y/x
InterceptCD <- Cy - slopeCD * Cx
intersection <- (InterceptAB - InterceptCD)/(slopeCD - slopeAB) #what is the hypothetical x-coordinate of intersection?
c1 <- min(c(Ax,Bx)) <= intersection & intersection <= max(c(Ax,Bx)) #does AB contain that x-coordinate? (TRUE=yes, FALSE=no)
c1 <- (c1 -1)*-1
CONDITION_COUNTER[3] <- c1
CHECK <- (sum(CONDITION_COUNTER) == 3) #check if all conditions are met
if(CHECK == TRUE){STOP <- TRUE} #if all conditions are met, stop loop
} #END WHILE LOOP
#Plot:
plot(-1:10, -1:10, xaxt='n',yaxt='n',bty='n',pch='',ylab='',xlab='', col="white")
segments(Ax,Ay,Bx,By, lwd=2) #segment AB
segments(Bx,By,Cx,Cy, lwd=2) #segment BC
segments(Cx,Cy,Dx,Dy, lwd=2) #segment CD
#Add square that it has to fill
segments(0,0,X,0, col="red")
segments(0,0,0,Y, col="red")
segments(X,0,X,Y, col="red")
segments(0,Y,X,Y, col="red")
Since your constraints force the picture to look like your image (or perhaps a rotated copy) you can think of the problem as one of picking 4 numbers (a location on each edge) rather than 8. Intersections would be impossible, so no need to check. Pick the first three points, and then pause to check if it is
possible to extend it to the fourth (given the length constraints). As a safety valve, put a bound on the number of attempts to find a feasible solution:
dis <- function(x0,y0,x1,y1){
sqrt(sum((c(x1,y1)-c(x0,y0))^2))
}
broken.line <- function(X,Y,l1,l2,attempts = 1000){
Ax <- 0
By <- 0
Cx <- X
Dy <- Y
for(i in 1:attempts){
Ay <- runif(1,0,Y)
Bx <- runif(1,0,X)
Cy <- runif(1,0,Y)
L <- dis(Ax,Ay,Bx,By) + dis(Bx,By,Cx,Cy)
d.min <- Y - Cy #min dist to top edge
if(l1 < L + d.min && L + d.min < l2){
#it is feasible to complete this
#configuration -- calulate how much
#of top edge is a valid choice
#d.max is farthest that last point
#can be from the upper right corner:
d.max <- sqrt((l2 - L)^2 - d.min^2)
Dx <- runif(1,max(0,X-d.max),X)
points <- c(Ax,Bx,Cx,Dx,Ay,By,Cy,Dy)
return(matrix(points,ncol = 2))
}
}
NULL #can't find a feasible solution
}
It is fairly quick. With your parameters it can generate tens of thousands of solutions per second. For a quick test:
> m <- broken.line(5,7,8,12)
> m
[,1] [,2]
[1,] 0.000000 1.613904
[2,] 1.008444 0.000000
[3,] 5.000000 3.627471
[4,] 3.145380 7.000000
> plot(m,type = 'l')
Graph:
Let us consider a quadrilateral with vertices
x y
1 0.0057 -0.0249
2 0.0209 0.0028
3 -0.0058 0.0250
4 -0.0209 -0.0028.
Could anyone please suggest me if there is any package or code in R to find and draw circle of smallest radius around the above quadrilateral. Thanks.
I don't know about any library that can solve your problem from start but one way of doing it could be
Determine minimum radius (depending on what kind of cuadrilateral you have ie. square or rectangle)
Use this draw.circle from plotrix library as explained here
UPDATE
In this particular example the quadrilateral looks like this:
using
ggplot(rectangle,aes(x=x,y=y)) + geom_polygon(aes(x=x,y=y), colour="black", fill = NA)
where rectangle is
rectangle = data.frame("x"=c(0.0057,0.0209,-0.0058,-0.0209),"y"=c(-0.029,0.028,0.0250,-0.0028))
So you would have to calculate the center of the polygon:
Get the equation for diagonal one
Get the equation for diagonal two
Get the intersection of the lines (solve equation1 = equation 2) which is the center of the shape
Calculate the distances of the center to each side and use the minimum distance as the minimum radius.
Draw the circle with the previous radius calculated.
Should be easy to do all the calculations for this particular example.
i hope this will help you. goodluck
pack.circles <- function(config, size=c(100, 100), max.iter=1000, overlap=0) {
#
# Simple circle packing algorithm based on inverse size weighted repulsion
#
# config - matrix with two cols: radius, N
# size - width and height of bounding rectangle
# max.iter - maximum number of iterations to try
# overlap - allowable overlap expressed as proportion of joint radii
# ============================================================================
# Global constants
# ============================================================================
# round-off tolerance
TOL <- 0.0001
# convert overlap to proportion of radius
if (overlap < 0 | overlap >= 1) {
stop("overlap should be in the range [0, 1)")
}
PRADIUS <- 1 - overlap
NCIRCLES <- sum(config[,2])
# ============================================================================
# Helper function - Draw a circle
# ============================================================================
draw.circle <- function(x, y, r, col) {
lines( cos(seq(0, 2*pi, pi/180)) * r + x, sin(seq(0, 2*pi, pi/180)) * r + y , col=col )
}
# ============================================================================
# Helper function - Move two circles apart. The proportion of the required
# distance moved by each circle is proportional to the size of the other
# circle. For example, If a c1 with radius r1 overlaps c2 with radius r2,
# and the movement distance required to separate them is ds, then c1 will
# move ds * r2 / (r1 + r2) while c2 will move ds * r1 / (r1 + r2). Thus,
# when a big circle overlaps a little one, the little one moves a lot while
# the big one moves a little.
# ============================================================================
repel <- function(xyr, c0, c1) {
dx <- xyr[c1, 1] - xyr[c0, 1]
dy <- xyr[c1, 2] - xyr[c0, 2]
d <- sqrt(dx*dx + dy*dy)
r <- xyr[c1, 3] + xyr[c0, 3]
w0 <- xyr[c1, 3] / r
w1 <- xyr[c0, 3] / r
if (d < r - TOL) {
p <- (r - d) / d
xyr[c1, 1] <<- toroid(xyr[c1, 1] + p*dx*w1, 1)
xyr[c1, 2] <<- toroid(xyr[c1, 2] + p*dy*w1, 2)
xyr[c0, 1] <<- toroid(xyr[c0, 1] - p*dx*w0, 1)
xyr[c0, 2] <<- toroid(xyr[c0, 2] - p*dy*w0, 2)
return(TRUE)
}
return(FALSE)
}
# ============================================================================
# Helper function - Adjust a coordinate such that if it is distance d beyond
# an edge (ie. outside the area) it is moved to be distance d inside the
# opposite edge. This has the effect of treating the area as a toroid.
# ============================================================================
toroid <- function(coord, axis) {
tcoord <- coord
if (coord < 0) {
tcoord <- coord + size[axis]
} else if (coord >= size[axis]) {
tcoord <- coord - size[axis]
}
tcoord
}
# ============================================================================
# Main program
# ============================================================================
# ------------------------------------------
# create a random initial layout
# ------------------------------------------
xyr <- matrix(0, NCIRCLES, 3)
pos0 <- 1
for (i in 1:nrow(config)) {
pos1 <- pos0 + config[i,2] - 1
xyr[pos0:pos1, 1] <- runif(config[i, 2], 0, size[1])
xyr[pos0:pos1, 2] <- runif(config[i, 2], 0, size[2])
xyr[pos0:pos1, 3] <- config[i, 1] * PRADIUS
pos0 <- pos1 + 1
}
# ------------------------------------------
# iteratively adjust the layout
# ------------------------------------------
for (iter in 1:max.iter) {
moved <- FALSE
for (i in 1:(NCIRCLES-1)) {
for (j in (i+1):NCIRCLES) {
if (repel(xyr, i, j)) {
moved <- TRUE
}
}
}
if (!moved) break
}
cat(paste(iter, "iterations\n"));
# ------------------------------------------
# draw the layout
# ------------------------------------------
plot(0, type="n", xlab="x", xlim=c(0,size[1]), ylab="y", ylim=c(0, size[2]))
xyr[, 3] <- xyr[, 3] / PRADIUS
for (i in 1:nrow(xyr)) {
draw.circle(xyr[i, 1], xyr[i, 2], xyr[i, 3], "gray")
}
# ------------------------------------------
# return the layout
# ------------------------------------------
colnames(xyr) <- c("x", "y", "radius")
invisible(xyr)
}
source
I would like to calculate a density function of a distribution whose characteristics function is known. As a simple example take the normal distribution.
norm.char<-function(t,mu,sigma) exp((0+1i)*t*mu-0.5*sigma^2*t^2)
and then I would like to use R's fft function. but I don't get the multiplicative constants right and I have to reorder the result (take the 2nd half and then the first half of the values). I tried something like
xmax = 5
xmin = -5
deltat = 2*pi/(xmax-xmin)
N=2^8
deltax = (xmax-xmin)/(N-1)
x = xmin + deltax*seq(0,N-1)
t = deltat*seq(0,N-1)
density = Re(fft(norm.char(t*2*pi,mu,sigma)))
density = c(density[(N/2+1):N],density[1:(N/2)])
But this is still not correct. Does anybody know a good reference on the fft in R in the context of density calculations? Obviously the problem is the mixture of the continuous FFT and the discrete one. Can anybody recommend a procedure?
Thanks
It is just cumbersome: take a pen and paper,
write the integral you want to compute
(the Fourier transform of the characteristic function),
discretize it, and rewrite the terms so that they look like
a discrete Fourier transform (the FFT assumes that the interval starts
at zero).
Note that fft is an unnormalized transform: there is no 1/N factor.
characteristic_function_to_density <- function(
phi, # characteristic function; should be vectorized
n, # Number of points, ideally a power of 2
a, b # Evaluate the density on [a,b[
) {
i <- 0:(n-1) # Indices
dx <- (b-a)/n # Step size, for the density
x <- a + i * dx # Grid, for the density
dt <- 2*pi / ( n * dx ) # Step size, frequency space
c <- -n/2 * dt # Evaluate the characteristic function on [c,d]
d <- n/2 * dt # (center the interval on zero)
t <- c + i * dt # Grid, frequency space
phi_t <- phi(t)
X <- exp( -(0+1i) * i * dt * a ) * phi_t
Y <- fft(X)
density <- dt / (2*pi) * exp( - (0+1i) * c * x ) * Y
data.frame(
i = i,
t = t,
characteristic_function = phi_t,
x = x,
density = Re(density)
)
}
d <- characteristic_function_to_density(
function(t,mu=1,sigma=.5)
exp( (0+1i)*t*mu - sigma^2/2*t^2 ),
2^8,
-3, 3
)
plot(d$x, d$density, las=1)
curve(dnorm(x,1,.5), add=TRUE)