Which spatial Data structure to use when Coordinates of the features is updating frequently? I have tried R tree, 2d Grid - multidimensional-array

I have N numbers of geographical points and coordinates of the points are being updated frequently. And the number N is very big.
I need to find points within a rectangle.
I have tried searching by all points, by using 2d Array grid and R tree.
I had to remove and then insert again which is costly operation.

Indexing spatial data is a complex topic. If you just have points you can index them using a sparse grid (better memory utilization than just 2d array):
class SpatialGrid:
def __init__(self, cell_size):
self._cells: DefaultDict[Tuple, Set] = defaultdict(set)
self._cell_size = cell_size
def __len__(self):
return len(self._cells)
def _key(self, x: float, y: float) -> Tuple:
return int(x / self._cell_size), int(y / self._cell_size)
def add(self, x: float, y: float, obj: object) -> None:
i_x, i_y = self._key(x, y)
for i in (-1, 0, 1):
for j in (-1, 0, 1):
self._cells[(i_x + i, i_y + j)].add(obj)
def get(self, x: float, y: float) -> Set:
return self._cells[self._key(x, y)]
def contains(self, x: float, y: float) -> bool:
return self._key(x, y) in self._cells
if you need to find by rectangle then you can just iterate over grid cells that are in that rectangle
But of course you will need to remove and insert points whenever the coordinates change. Indexing is costly.

Related

How to draw a circular sector in the Julia language?

I am new to the Julia language and need to draw a circular sector on an image (2-dimensional UInt8 array for gray version or 3-dimensional UInt8 array for an RGB version). Afterwards this image is to be used as a mask to select data in other arrays, so I need the result, not as an image object, but as an array of booleans or integers.
There is the way to draw a circle by means of the ImageDraw package:
draw!(img, Ellipse(CirclePointRadius(350,200,100), fill = tue))
but found no way to provide a start and end angle.
You can use Luxor.jl's pie or sector function:
julia> begin
img = readpng("/path/Images/deepam.png")
Drawing(img.width, img.height, "sector-on-img.png")
placeimage(img)
origin()
sethue("orange")
pie(0, 0, 100, π/2, π, :fill)
sethue("olive")
sector(25, 125, 3π/2, 0, 15, :fill)
finish()
end
true
Result:
(Original png image scaled down, for comparison:
)
I think Julia is a great language, because (among other things) all libraries are implemented in the same language and you have ease acces to their sources.
And in this way, I have been able to modify the ellipse2d.jl script of the ImageDraw library.
The modification consits of adding another definition of the draw! funciton for ellipse objects (multiple dispatch of Julia is also great) that accepts a start and end angle.
I think the best way could be to define new objects, ellipse_sector and circle_sector, which would be the same as the ellipse and circle objects but with two more members: start_angle and end_angle. Then the correspondent drawing functions should be implemented. I would like to write to the ImageDraw package developers in order to make this suggestion or even offer me to make these changes, but I do not know the manage of github.
My solution, instead, does not modify any existing object, just adds a method to the draw! function that accpets two more arguments: startAngle and endAngle.
Here is the code, to be copied to the end of the ellipse2d.jl script:
function draw!(img::AbstractArray{T, 2}, ellipse::Ellipse, startAng::Real, endAng::Real, color::T) where T<:Colorant
# Solution to find out if an angle lies between two given ones, borrowed from:
# https://stackoverflow.com/questions/11406189/determine-if-angle-lies-between-2-other-angles/11412077#11412077
# Make all angles to lie in [0, 2π)
# rem2pi(ϕ, RoundNearest) returns the remainder of the division by 2π in the range [−π,π]
# mod2pi returns the remainder of the division by 2π in the range [0,2π)
Angle1 = mod2pi(startAng)
Angle2 = mod2pi(endAng)
# make the angle from angle1 to angle2 to be <= 180 degrees
rAngle = mod2pi( mod2pi(Angle2 - Angle1) + 2π)
if rAngle >= π
Angle1, Angle2 = Angle2, Angle1 # Swaps the values
end # if
ys = Int[]
xs = Int[]
break_point = 0
if ellipse.fill == false
break_point = ((ellipse.ρy - ellipse.thickness) / ellipse.ρy) ^ 2 + ((ellipse.ρx - ellipse.thickness) / ellipse.ρx) ^ 2
end
for i in ellipse.center.y - ellipse.ρy : ellipse.center.y + ellipse.ρy
for j in ellipse.center.x - ellipse.ρx: ellipse.center.x + ellipse.ρx
y = i - ellipse.center.y
x = j - ellipse.center.x
val = (x / ellipse.ρy) ^ 2 + (y / ellipse.ρx) ^ 2
# atan(y, x) returns the angle in the correct quadrant [−π,π], not like atan(y/x)
# But make it to be in the range [0, 2π)by means of mod2pi()
ang = mod2pi( atan(y, x) )
# Test if the angle lies betwen the startAngle and the endAngle
if (Angle1 <= Angle2)
AngleIsBetween = ang >= Angle1 && ang <= Angle2
else
AngleIsBetween = ang >= Angle1 || ang <= Angle2
end # if
if val < 1 && val >= break_point && AngleIsBetween
push!(ys, i)
push!(xs, j)
end
end
end
for (yi, xi) in zip(ys, xs)
drawifinbounds!(img, yi, xi, color)
end
img
end

Determining if a point lies between two bearings from a central point

I am trying to determine if a point lies between two bearings from a central point.
The diagram below attempts to explain things
I have a central point labelled A
I have two points (labelled B & C) which provide the boundaries of the search area (based on bearing only - there is no distance element required).
I'm trying to determine if point D is within the sector formed by A-B and A-C
I've calculated the bearings from A to each B & C
In my real scenario the angle created between the bearings can be anything from 0 to 360.
There are some similar questions & answers
however in my case I'm not interested in restricting my search to the radius of a circle. And there seems to be some implementation issues around angle size and the location of the points in terms of clockwise vs counter-clockwise
It seems so simple in theory but my maths is clearly not up to scratch :(
Any advice or pseudo-code would be greatly appreciated.
Here would be my approach:
calculate first bearing angle X
calculate second bearing angle Y
calculate angle Z towards point D
if X < Z < Y, return true; otherwise, return false
In your example it looks like you'd calculate Z ~ 90deg and find 45 < 90 < 135 (is your picture wrong? is says 315).
You can use something like the "atan2" function in whatever language you're using. This is an extension of the basic arctangent function which takes not just the slope but both the rise and run and instead of returning an angle from only a 180-degree range, it returns the true angle from a 360-degree range. So
Z = atan2(Dy, Dx)
Should give you the angle (possibly in radians; be careful) that you can compare to your bearings to tell whether you're inside the search. Note that the order of X and Y matter since the order is what defines which of the two sections is in the search area (X to Y gives ~90 deg in your picture, but Y to X gives ~270 deg).
You can calculate and compare the cross products of the vectors (AB X BD), and (AC X CD).
if (AB X BD) > 0, you have a counter clock wise turn
if (AC X CD) < 0, you have a clock wise turn
If both above tests are true, then the point D is in the sector BAC
This allows you to completely avoid using expensive trig functions.
class Point:
"""small class for point arithmetic convenience
"""
def __init__(self, x: float = 0, y: float = 0) -> None:
self.x = x
self.y = y
def __sub__(self, other: 'Point') -> 'Vector':
return Vector(self.x - other.x, self.y - other.y)
class Vector:
"""small class for vector arithmetic convenience
"""
def __init__(self, x: float = 0, y: float = 0) -> None:
self.x = x
self.y = y
def cross(self, other: 'Vector') -> float:
return (self.x * other.y) - (self.y * other.x)
def in_sector(A: Point, B: Point, C: Point, D: Point) -> bool:
# construct vectors:
ab = B - A
bd = D - B
ac = C - A
cd = D - C
print(f'ab x bc = {ab.cross(bd)}, ac x cd = {ac.cross(cd)}')
return ab.cross(bd) > 0 and ac.cross(cd) < 0
if __name__ == '__main__':
A = Point(0, 0)
B = Point(1, 1)
C = Point(-1, 1)
D = Point(0, 1)
print(f'D in sector ABC: {in_sector(A, B, C, D)}', end='\n\n')
print(f'D in sector ACB: {in_sector(A, C, B, D)}') # inverting the sector definition so D is now outside
Output:
ab x bc = 1, ac x cd = -1
D in sector ABC: True
ab x bc = -1, ac x cd = 1
D in sector ACB: False

Learning Binary Search in python 3.7

I found this code on https://www.geeksforgeeks.org/binary-search/
# Python Program for recursive binary search.
# Returns index of x in arr if present, else -1
def binarySearch (arr, l, r, x):
# Check base case
if r >= l:
mid = l + (r - l)/2;
# If element is present at the middle itself
if arr[mid] == x:
return mid
# If element is smaller than mid, then it
# can only be present in left subarray
elif arr[mid] > x:
return binarySearch(arr, l, mid-1, x)
# Else the element can only be present
# in right subarray
else:
return binarySearch(arr, mid+1, r, x)
else:
# Element is not present in the array
return -1
# Test array
arr = [ 2, 3, 4, 10, 40, 50, 80, 140, 200, 2000, 100]
x = 50
# Function call
result = binarySearch(arr, 0, len(arr)-1, int)
if result != -1:
print ("Element is present at index %d" % result)
else:
print ("Element is not present in array")
However, when I run it I get this problem: TypeError: list indices must be integers or slices, not float
I'm not sure how to convert do that. I attempted to set the entire array as an int but that didn't work or replace x with int and that didn't work either.
Any suggestion?
The issue is on this line:
mid = l + (r - l)/2;
In Python 3 / does floating point division and as mid is used as an array index it needs to be an int. To do integer division use //
mid = l + (r - l) // 2;
There is also another issue with the call to the function:
result = binarySearch(arr, 0, len(arr) - 1, int)
The last parameter should not be int but x (the variable you are searching for):
result = binarySearch(arr, 0, len(arr) - 1, x)
when you pass in int as the last parameter you'll get an error TypeError: unorderable types: int() > type()

How do I reverse this formula which creates a spherical coordinate?

I have a formula that maps a random point in space to a point that sits in a sphere. I want to be able to reverse this formula to get the random point in space again.
My unspherize() function below is not working. Please show me the correct way to reverse the form.
function spherize(x,y,z){
var d = 1 / Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
x *= d;
y *= d;
z *= d;
return {x: x, y: y, z: z}
}
function unspherize(x,y,z){
var d = 1 * Math.pow(Math.sqrt(x) + Math.sqrt(y) + Math.sqrt(z), 2)
x /= d;
y /= d;
z /= d;
return {x: x, y: y, z: z}
}
There are an infinite number of points that get mapped to the same point on the sphere (e.g., for every (x,y,z) the point (2x,2y,2z) gets mapped to the same vector). Therefore, if you don't save the vector length d, the operation is not reversible.
Using r as the radius or Euclidean norm of the point (x,y,z),
x /= 1+r
y /= 1+r
z /= 1+r
gives you a point inside the sphere. Since this transformation is bijective, it can be reversed, for any point inside the sphere, the "unspherized" point is obtained as
x/= 1-r
y/= 1-r
z/= 1-r

How to get coordinates of closest free spot?

I have a space:
[.][.][.][.][.]
[.][.][.][.][.]
[.][.][x][.][.]
[.][.][.][.][.]
[.][.][.][.][.]
Each [.] represents a spot in 2D space. (need it for 3D, but doesn't matter for now)
By [x] I marked "current location" (let's say it's [0, 0, 0])
So I need to find what is the position of closest "not busy" spot.
For example if I had such area:
[.][.][.][.][.]
[.][b][b][b][.]
[.][b][x][.][.]
[.][b][b][b][.]
[.][.][.][.][.]
([b] for "busy")
Then I would need to get a result (x: 0, y: 1, z: 0) (because it's closest one that is free).
For now thinking to do something like this:
current_location = {x: 0, y: 0, z: 0}
radius = 0
closest_record = nil
begin
radius = radius + 1
# some way to iterate over each [x, y, z] spot within that radius until
# closest_record = Record.where(x: x1, y: y1, z: z1).first returns nil (meaning it's free)
end until record.present?
# (that's Ruby syntax, but doesn't matter really)
Is there some formula to do that?
I'm not familiar with Ruby, but in C++, you might do something like this:
for(int x=(radius*-1); x<=radius; ++x) {
for(int y=(radius*-1); y<=radius; ++y) {
for(int z=(radius*-1); z<=radius; ++z) {
if(x==0 && y==0 && z==0) {
continue;
} else {
//check location[x,y,z];
}
}
}
}
Are you asking for the distance formula? Not sure I understand the question, but the distance between two points with coordinates (x1,y1,z1) and (x2,y2,z2) is:
distance = sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2)

Resources