I am having difficulty of producing X,Y coordinates of a circle and then drawing line segments to it. Basically what I want to do is draw 360 lines from the center of a circle to the outside of the circle in perfect spacing. This is how I am currently doing it but it is not working. If there is a different way to do this, that works great as well! Also I am hoping that degree 0 starts at the left side of the circle.
t <- seq(0,2*pi,length=360)
coords <- t(rbind( sin(t)*127.28125, cos(t)*127.28125))
plot(coords,type='n',xlim=c(-63.625625,63.625625),ylim=c(0,127.28125))
lines(coords)
deg=data.frame(coords[,1],coords[,2])
head(deg)
deg$count=1
deg$degree=1
for(i in 1:nrow(coords)){
if(deg$count[i]<=270){
deg$degree[i]=i-1+90-45
} else {
deg$degree[i]=i-1-270-45
}
}
names(deg)[1] <- "X"
names(deg)[2] <- "Y"
i=1
for(i in 1:19){
segments(0,0,deg$X[deg$degree==((5*(i-1)))],deg$Y[deg$degree==((5*(i-1)))])
cat(((5*(i-1))),'\t')
}
Update:
I am having some issues with where the lines get drawn. Basically as we go around the circle the errors get larger so when pi/2 radians happens and it is straight up, the value is slightly to the right of x=0. This may not be possible to get but thought I would ask to see if there was anyway to fix that! The 45 90 and 135 should all match on the lines.
How about this
th <- seq(0, 2*pi, length.out=360)
r <- 2
x <- r*cos(th)
y <- r*sin(th)
plot(x,y, type="n")
segments(0,0,x,y)
Basically i choose th and r in polar space and convert to Cartesian.
If you want to start with 0 on the left, use
x <- -r*cos(th)
instead.
Related
I have a large rivernetwork as a SpatialLines(DataFrame) and want to subset it so I get a SpatialLine with only the shortest/fastest path between two SpatialPoints(DataFrame) which propably need to be snapped onto the line first.
In the example Code, I want to get the closest line between the red dots, while moving on the lines. Also I want to move between the left red point and the right blue point, which needs to be snapped to the closest SpatialLine
library(sp)
x <- c(1,5,6,8)
y1 <- c(1,3,4,7)
y2 <- c(5,5,5,2)
L <- SpatialLines(list(Lines(Line(cbind(x,y1)), ID="a"),Lines(Line(cbind(x,y2)), ID="b")))
P <- SpatialPoints(data.frame(x=c(1,8),y=c(1,2)))
P_snap <- SpatialPoints(data.frame(x=c(8),y=c(1)))
plot(L)
points(P,col="red")
points(P_snap,col="blue")
I want to create 50 concentric circles. I did it with python but now I want to do this in R. I have tried the symbols function but with no result. I want my circles to start from x,y coordinates and the radius of each circle to be 3times bigger than the previous.
step=1
for(i in seq(1,50,1)){
symbols (x, y, circles=50, col="grey")
step=step+3
}
From this I get one circle as a result.
I am new in programming so it is probably very simple. Should I use a specific package?
The beauty of R is that many things can be vectorized, including the imput to the 'symbols' function. Here's an example for you:
#vector of radii
#written in a way that's easily changable
n_circles <- 50
my_circles <- seq(1,by=1,length.out = n_circles)
#generate x and y
x <- rep(1,n_circles)
y <- rep(1, n_circles)
#plot
symbols(x,y,1:n_circles)
I have image as below and i want to detect the line in the image using PET package's hough tranform. I need help to understand how to get the line from that image.
library("PET", lib.loc="~/R/win-library/3.1")
library("raster", lib.loc="~/R/win-library/3.1")
p=matrix(diag(100), 100)
library(raster)
r <- raster(p)
plot(r)
abc=hough(p)
viewData(list(p, abc$hData), list("Phantom", "Hough transformed phantom"))
I applied hough transformation as above. The original image and image that i get after running the last line are as below
any inputs on how to get line's coordinates (from original image)? I understand that white point from the second image right side pane represents the line. That line is plotted using Polar Cordinate system. But i dont know how to use the second image to get coordinate of the original line
I looked at PET package's documentation but found it hard to understand :( I ran their sample code but i didn't understand it
==============================================================================
I followed advice given in comments by user NicE and updated my code as below
library("PET", lib.loc="~/R/win-library/3.1")
library("raster", lib.loc="~/R/win-library/3.1")
#p=matrix(diag(1000), 1000)
p=matrix(rep(0,10000), 100, 100)
# for (i in 1:100)
# {p[i,100-i+1]=1
# }
for (i in 1:100)
{p[i,50]=1
}
# library(raster)
# r <- raster(p)
# plot(r)
abc=hough(p)
maxPoint<-which(abc$hData==max(abc$hData),arr.ind=T)
library(pracma)
a<-cot(maxPoint[1,"row"]*pi/180)
b<-maxPoint[1,"col"]/sin(maxPoint[1,"row"]*pi/180)
a
b
par(pty="s")
par(mfrow=c(1,2))
#image(r, main="org")
image(p,main="original")
image(abc$hData, main="Houghmatrix")
Are new values of a and b correct? I feel that b should be 50 (perpendicular distance of the original line from the (0,0)). What am I doing wrong?
I would also like to know why does abc$hData has 181 rows and 143 columns. I can imagine 181 rows has something to do with PI radians is 180 degrees. But I dont have any clue about 143 columns...
=======================================================================
update 2
If i update my original matrix as I feel that i get weird answers. I get a=-57.6 and b=1786.12.
p=matrix(rep(0,10000), 100, 100)
for (i in 1:100)
{p[80,i]=1
}
Once you have the Hough transformation of the data, find the indices of the max of the matrix (assuming you have only one line):
maxPoint<-which(abc$hData==max(abc$hData),arr.ind=T)
You can also take the average of all the maxPoitns if you know there is only one line. In your case, you get this:
row col
[1,] 137 72
You need the default parameters of the function as well
houghParam<-unlist(abc$Header)
These give you RhoMin, ThethaMin, and DeltaMin and DeltaRho, the increments of both variables. With these you can get rho and theta from the matrix coordinates.
theta=(maxPoint[1,"row"]-1)*houghParam["DeltaXY1"]+houghParam["XYmin1"]
rho=(maxPoint[1,"col"]-1)*houghParam["DeltaXY2"]+houghParam["XYmin2"]
If the equation of the line is y=ax+b, you can get a and b using:
library(pracma)
a<--cot(theta)
b<-(rho)/sin(theta)
Also, in the man page of hough they state that they take the center of the image as (0,0) points.
For the math explanation, look at the Wikipedia page of Hough Transform ...
Edit: changed a formula and removed some wrong info
The total code would be:
library(PET)
library(pracma)
a=matrix(rep(0,10000), 100, 100)
for (i in 1:100)
{a[i,60]=1
}
d=matrix(rep(0,10000), 100, 100)
for (i in 1:100)
{d[60,i]=1
}
e=matrix(diag(100), 100)
getLineHough<-function(p){
abc=hough(p)
#get the brightest point in the hough tranform
maxPoint<-which(abc$hData==max(abc$hData),arr.ind=T)
#if there is only one line, can average the results in case there are several brightest points
maxPoint<-apply(maxPoint,2,mean)
houghParam<-unlist(abc$Header)
theta=(maxPoint[1]-1)*houghParam["DeltaXY1"]+houghParam["XYmin1"]
rho=(maxPoint[2]-1)*houghParam["DeltaXY2"]+houghParam["XYmin2"]
a<--cot(theta)
b<-rho/sin(theta)
par(mfrow=c(1,2))
image(p,main="original")
#add the predicted lines, also have to change the slope and intercept because
#the origin of the plot function is not the center of the image the bottom left corner
if(theta==0){
abline(v=(rho+50)/100)
} else{
abline((b+50-a*50)/100,a)
}
image(abc$hData, main="Houghmatrix")
}
getLineHough(a)
getLineHough(d)
getLineHough(e)
Edit2: the documentation doesn't really say what the value of the first row of the matrix is. Since there are 181 rows it should start at 0 and not 1*houghParam["DeltaXY1"]. Changed the code accordingly
Edit3: made the code into a function and added the predicted line to the plot
I wanted to draw 2 equilateral triangles. One upside down and the other upside up.
Here is my code:
ord<-c(1,3,5)
ord1<-c(2,4,6)
x1<-x[ord]
y1<-y[ord]
x2<-x[ord1]
y2<-y[ord1]
lines(x1,y1,col="blue")
lines(x2,y2,col="blue")
However, I can't get the figure to make complete triangle. I only get 2 sides of each triangle. What am I doing wrong?
lines will draw from the first coord to the second, second to third, etc. If you want it to come back to the first point, just duplicate it at the end:
ord <- c(1,3,5,1)
ord1 <- c(2,4,6,2)
to get it come back to the first point.
Using the fact that the third point is halfway between the first and the second, and the angle is pi/3, you can do this for example:
angle=pi/3
x <- c(0,0.5,0.5*cos(angle),0)
y <- c(0,0,sin(angle),0)
y1 <- c(0,0,-sin(angle),0)
plot(-1:1,-1:1,type='n')
polygon(x=x,y=y,col='red') ## you can replace polygon by lines here
polygon(x=x,y=y1,col='green')
I have a vector of coordinates where each row designates the centre of a circle:
x <- runif(5,0,2)
y <- runif(5,0,2)
As you can see the circles centres are all found within the square (0,2).
Each circle has a radius 0.2. I want to randomly shift the centre of the circles within the bounds of the original circle. I figured I could do this:
radii <- (sample(20,5,replace=TRUE))/100
angles <- sample(360,5,replace=TRUE)
newx <- x + radii*(cos(angles))
newy <- y + radii*(sin(angles))
However, I realise that doing this I could technically get circle centres that fall outside of the square (0,2). I could try and write a loop that rejects newx and newy values that are negative. But have to do this for 10s of thousands of rows and worried about the speed of this. Is it possible to run this conditional coordinate shift without resorting to a loop?
My rule set is as follows:
pick a new circle centre for each centre.
The new centres must fall within the area of each circle (radius 0.2 distance from the original centre)
The new centres must lie within the original square.
If a centre meets the border of the circle it should be reflected as of the law of reflection (be reflected the remaining length of the random radius distance selected)
Something like this:
#lets do only one point first
x <- runif(1,0,2)
y <- runif(1,0,2)
randomwalk <- function (pos) {
x <- pos[1]
y <- pos[2]
radius <- (sample(20,1,replace=TRUE))/100
angle <- sample(360,1,replace=TRUE)
newx <- x + radius*(cos(angle))
newy <- y + radius*(sin(angle))
if (newy > 2) { #check the geometric calculations
r2 <- (2-y)/sin(angle)
hitx <- x + r2*(cos(angle))
hity <- 2
newx <- hitx + (radius-r2)*sin(angle)
newy <- hity - (radius-r2)*cos(angle)
}
#implement other borders yourself
#and include a check, which border is hit first
#and include the possibility for multiple hits
#(e.g., left border and then top border)
cbind(newx,newy)
}
resx <- vector(50,mode="numeric")
resy <- vector(50,mode="numeric")
res <- cbind(resx,resy)
res[1,] <- cbind(x,y)
for (i in 2:50) {
res[i,] <- randomwalk(res[i-1,])
}
I suspect this still contains some geometric errors, but don't have time to check.
The functions inpip and inout from package splancs is quite useful; they can be used to check if points fall inside a polygon. You just need a matrix with 2 columns which represents any polygon (such as a square). This functions are made to be fast, using C and Fortran programs.
If your square is:
square <- cbind(c(0, 10, 10, 0), c(0, 0, 10, 10)) # In case side = 10
Then create all the new centers (I suggest using runif instead of sample for the radii and angle, but that's up to you). Then check if those centers fall inside the square with one line:
inside <- inout(newCenters, square)
newCenters <- newCenters[inside]
And afterwards you should do all the necessary steps to recreate the newCenters that where selected out, as many times as needed until they fall inside the square. Note that this needs a while loop (or equivalent).
Note also that in the same package (splancs) there is this function csr that create random points inside a polygon. So in principle you could cut a piece of every circumference that falls outside the square and then use the resulting polygons (the cut circles) as input to this function. This can become slow because you have to use a loop (or a lapply maybe) for all cut circles.
As a last idea, maybe you can combine the two strategies. First use your initial idea to all circumferences that fall completely inside the square (or equivalently, all the centers that are at a distance of 2 or more from the perimeter). Then use the csr function for all the rest of the circles.
Hope this helps!