I need help with programming random vertices of regular polygon. I want to get a function, where for n regular polygon get vertices of random coordinates. I tried like this but I have to have coordinates of poly. Any help?
import random
def polygon_random_points (poly, num_points):
min_x, min_y, max_x, max_y = poly.bounds
points = []
while len(points) < num_points:
random_point = Point([random.uniform(min_x, max_x), random.uniform(min_y, max_y)])
if (random_point.within(poly)):
points.append(random_point)
return points
In R - I have imported a polyline shapefile that is not straight (represents a winding interstate highway) into the environment. I have read a .csv file that contains points (latitude/longitude in decimal degrees) into the environment. All of those points lie along the polyline.
If I take two random points I can calculate the "as the crow flies" distance between them using great circle distance calculation. But what is needed is distance traveled along the polyline. See reference image:
https://i.stack.imgur.com/zhorb.png
Is anyone aware of an R package that can calculate the distance between two lat/lon points along a polyline?
Package PBSmapping has a calcLength function which directly calculates the length of a polyline or polygon (in what it terms a PolySet). The package can import ESRI shapefiles as well, if your shapefile is in that format.
Example of a simple polyline:
line = read.table(text = "X, Y, POS, PID
37.772, -122.214, 1, 1
21.291, -157.821, 2, 1
-18.142, 178.431, 3, 1
-27.467, 153.027, 4, 1", header = TRUE, sep = ",")
library(PBSmapping)
pline = as.PolySet(line, projection = 1)
calcLength(pline)
PID length
1 1 404.8539
plotLines(pline)
I want to calculate projected distance between two points and between a point a polygon. All coordinates are specified under same projection lat,lon (WGS84).
I calculated the distance between a point and a polygon using pyproj as follows:
from pyproj import Proj, transform, Geod
geod = Geod(ellps='WGS84')
angle1,angle2,dist1 = geod.inv(wLong1, sLat1, wLong2, sLat2)
#this returns distance in m
I want to use the same function to calculate the distance between a point and a bounding box.
bbox = box(wLong1, sLat1, eLong1, nLat1)
point = Point(wLong2,sLat2)
dist2 = (point.distance(bbox))
Unlike the first example (dist1 in meter), I think the second example (dist2) returns distance in degrees. How can I translate this value into meter like example 1?
You need mean radius of earth's curvature (rm) for computation.
from pyproj import Geod
from math import radians
# ... some code
a = Geod.a
b = Geod.b
rm = (2.0*a + b)/3.0 # simple mean radius, as defined by IUGG
rm * radians(dist2) # your dist in meters
More accurate formulas for rm exist, but the above is good approximate.
I'm trying to find points at an equal distance between 2 other points in 3D space. For example, I have 2 cubes in my scene. I want to add 5 (or 3, or 80...) locators at an equal distance between these two spheres with Pymel.
I can easily find the midway point between the spheres like this:
import pymel.core as pm
import pymel.core.datatypes as dt
pos_1, pos_2 = pm.selected()
point_1 = dt.Vector(pos_1.getTranslation())
point_2 = dt.Vector(pos_2.getTranslation())
midway_point = (point_1 + point_2) / 2
However, I can't seem to figure out how to get multiple points on the line between the two spheres.
I tried something like this:
import pymel.core as pm
import pymel.core.datatypes as dt
pos_1, pos_2 = pm.selected()
point_1 = dt.Vector(pos_1.getTranslation())
point_2 = dt.Vector(pos_2.getTranslation())
distance = point_1.distanceTo(point_2)
divided_distance = distance / 5
for i in range (1, 5):
position = point_1 + (divided_distance * i)
pm.spaceLocator(position = position, absolute = True)
Which does add 5 locators between the two spheres, but they're not on the line connecting the two points in 3D space.
Can anyone point me in the right direction?
When you calculate the distance between the two points, you're getting a scalar, essentially a single number that is the number of units the points are away from each other. But what you're not getting is the direction from one to the other. That would be a vector. To get the vector, change this line:
distance = point_1.distanceTo(point_2)
to this:
difference = point_2 - point_1
Now instead of getting the single unit distance between the two points, you're getting a vector with the distance required for each of the three axes.
Almost miraculously, all the other code in your script will work if you just replace the variable distance with difference
I have a, not necessarily convex, polygon without intersections and a point outside this polygon. I'm wondering how calculate the Euclidian distance most efficiently in a 2-dimensional space. Is there a standard method in R?
My first idea was to calculate the minimum distance of all the lines of the polygon (extended infinitely so they are line, not line pieces) and then calculate the distance from the point to each individual line using the start of the line piece and Pythagoras.
Do you know about a package that implements an efficient algorithm?
You could use the rgeos package and the gDistance method. This will require you to prepare your geometries, creating spgeom objects from the data you have (I assume it is a data.frame or something similar). The rgeos documentation is very detailed (see the PDF manual of the package from the CRAN page), this is one relevant example from the gDistance documentation:
pt1 = readWKT("POINT(0.5 0.5)")
pt2 = readWKT("POINT(2 2)")
p1 = readWKT("POLYGON((0 0,1 0,1 1,0 1,0 0))")
p2 = readWKT("POLYGON((2 0,3 1,4 0,2 0))")
gDistance(pt1,pt2)
gDistance(p1,pt1)
gDistance(p1,pt2)
gDistance(p1,p2)
readWKT is included in rgeos as well.
Rgeos is based on the GEOS library, one of the de facto standards in geometric computing. If you don't feel like reinventing the wheel, this is a good way to go.
I decided to return and write up a theoretical solution, just for posterity. This isn't the most concise example, but it is fully transparent for those who want to know how to go about solving a problem like this by hand.
The theoretical algorithm
First, our assumptions.
We assume the polygon's vertices specify the points of a polygon in a rotational order going clockwise or counter-clockwise and the lines of the polygon cannot intersect. This means we have a normal geometric polygon, and not some strangely-defined vector graphic shape.
We assume this is a set of Cartesian coordinates, using 'x' and 'y' values that represent location on a 2-dimensional plane.
We assume the point must be outside the internal area of the polygon.
Finally, we assume that the distance desired is the minimum distance between the point and all of the infinite number of points on the perimeter of the polygon.
Now before coding, we should write out in basic terms what we want to do. We can assume that the shortest distance between the polygon and the point outside the polygon will always be one of two things: a vertex of the polygon or a point on a line between two vertices. With this in mind, we do the following steps:
Calculate the distances between all vertices and the target point.
Find the two vertices closest to the target point.
If either:
(a) the two closest vertices are not adjacent or
(b) the inside angles of either of the two vertices is greater or equal to 90 degrees,
then the closest vertex is the closest point. Calculate the distance between the closest point and the target point.
Otherwise, calculate the height of the triangle formed between the two points.
We're basically just looking to see if a vertex is closest to the point or if a point on a line is closest to the point. We have to use a few trig functions to make this work.
The code
To make this work properly, we want to avoid any 'for' loops and want to only use vectorized functions when looking at the entire list of polygon vertices. Luckily, this is pretty easy in R. We accept a data frame with 'x' and 'y' columns for our polygon's vertices, and we accept a vector with one 'x' and 'y' value for the point's location.
get_Point_Dist_from_Polygon <- function(.polygon, .point){
# Calculate all vertex distances from the target point.
vertex_Distance <- sqrt((.point[1] - .polygon$x)^2 + (.point[2] - .polygon$y)^2)
# Select two closest vertices.
min_1_Index <- which.min(vertex_Distance)
min_2_Index <- which.min(vertex_Distance[-min_1_Index])
# Calculate lengths of triangle sides made of
# the target point and two closest points.
a <- vertex_Distance[min_1_Index]
b <- vertex_Distance[min_2_Index]
c <- sqrt(diff(.polygon$x[c(min_1_Index, min_2_Index)])^2 + diff(.polygon$y[c(min_1_Index, min_2_Index)])^2)
if(abs(min_1_Index - min_2_Index) != 1 |
acos((b^2 + c^2 - a^2)/(2*b*c)) >= pi/2 |
acos((a^2 + c^2 - b^2)/(2*a*c)) >= pi/2
){
# Step 3 of algorithm.
return(vertex_Distance[min_1_Index])
} else {
# Step 4 of algorithm.
# Here we are using the law of cosines.
return(sqrt((a+b-c) * (a-b+c) * (-a+b+c) * (a+b+c)) / (2 * c))
}
}
Demo
polygon <- read.table(text="
x, y
0, 1
1, 0.8
2, 1.3
3, 1.4
2.5,0.3
1.5,0.5
0.5,0.1", header=TRUE, sep=",")
point <- c(3.2, 4.1)
get_Point_Dist_from_Polygon(polygon, point)
# 2.707397
Otherwise:
p2poly <- function(pt, poly){
# Closing the polygon
if(!identical(poly[1,],poly[nrow(poly),])){poly<-rbind(poly,poly[1,])}
# A simple distance function
dis <- function(x0,x1,y0,y1){sqrt((x0-x1)^2 +(y0-y1)^2)}
d <- c() # Your distance vector
for(i in 1:(nrow(poly)-1)){
ba <- c((pt[1]-poly[i,1]),(pt[2]-poly[i,2])) #Vector BA
bc <- c((poly[i+1,1]-poly[i,1]),(poly[i+1,2]-poly[i,2])) #Vector BC
dbc <- dis(poly[i+1,1],poly[i,1],poly[i+1,2],poly[i,2]) #Distance BC
dp <- (ba[1]*bc[1]+ba[2]*bc[2])/dbc #Projection of A on BC
if(dp<=0){ #If projection is outside of BC on B side
d[i] <- dis(pt[1],poly[i,1],pt[2],poly[i,2])
}else if(dp>=dbc){ #If projection is outside of BC on C side
d[i] <- dis(poly[i+1,1],pt[1],poly[i+1,2],pt[2])
}else{ #If projection is inside of BC
d[i] <- sqrt(abs((ba[1]^2 +ba[2]^2)-dp^2))
}
}
min(d)
}
Example:
pt <- c(3,2)
triangle <- matrix(c(1,3,2,3,4,2),byrow=T, nrow=3)
p2poly(pt,triangle)
[1] 0.3162278
I used distm() function in geosphere package to calculate the distence when points and apexes are presented in coordinate system. Also, you can easily make some alternation by substitude dis <- function(x0,x1,y0,y1){sqrt((x0-x1)^2 +(y0-y1)^2)}
for distm() .
algo.p2poly <- function(pt, poly){
if(!identical(poly[1,],poly[nrow(poly),])){poly<-rbind(poly,poly[1,])}
library(geosphere)
n <- nrow(poly) - 1
pa <- distm(pt, poly[1:n, ])
pb <- distm(pt, poly[2:(n+1), ])
ab <- diag(distm(poly[1:n, ], poly[2:(n+1), ]))
p <- (pa + pb + ab) / 2
d <- 2 * sqrt(p * (p - pa) * (p - pb) * (p - ab)) / ab
cosa <- (pa^2 + ab^2 - pb^2) / (2 * pa * ab)
cosb <- (pb^2 + ab^2 - pa^2) / (2 * pb * ab)
d[which(cosa <= 0)] <- pa[which(cosa <= 0)]
d[which(cosb <= 0)] <- pb[which(cosb <= 0)]
return(min(d))
}
Example:
poly <- matrix(c(114.33508, 114.33616,
114.33551, 114.33824,
114.34629, 114.35053,
114.35592, 114.35951,
114.36275, 114.35340,
114.35391, 114.34715,
114.34385, 114.34349,
114.33896, 114.33917,
30.48271, 30.47791,
30.47567, 30.47356,
30.46876, 30.46851,
30.46882, 30.46770,
30.47219, 30.47356,
30.47499, 30.47673,
30.47405, 30.47723,
30.47872, 30.48320),
byrow = F, nrow = 16)
pt1 <- c(114.33508, 30.48271)
pt2 <- c(114.6351, 30.98271)
algo.p2poly(pt1, poly)
algo.p2poly(pt2, poly)
Outcome:
> algo.p2poly(pt1, poly)
[1] 0
> algo.p2poly(pt2, poly)
[1] 62399.81