140 lines
4.2 KiB
Python
140 lines
4.2 KiB
Python
from os import write
|
|
import sys
|
|
import csv
|
|
|
|
_DIVISORS = [180.0 / 2 ** n for n in range(32)]
|
|
|
|
class MBR:
|
|
def __init__(self, id, xlow, xhigh, ylow, yhigh):
|
|
self.xlow = xlow
|
|
self.xhigh = xhigh
|
|
self.ylow = ylow
|
|
self.yhigh = yhigh
|
|
self.id = id
|
|
self.zcurve = self.findZcurve()
|
|
|
|
def findZcurve(self):
|
|
x_median = (self.xlow + self.xhigh) / 2
|
|
y_median = (self.ylow + self.yhigh) / 2
|
|
return interleave_latlng(y_median, x_median)
|
|
|
|
def interleave_latlng(lat, lng):
|
|
if lng > 180:
|
|
x = (lng % 180) + 180.0
|
|
elif lng < -180:
|
|
x = (-((-lng) % 180)) + 180.0
|
|
else:
|
|
x = lng + 180.0
|
|
if lat > 90:
|
|
y = (lat % 90) + 90.0
|
|
elif lat < -90:
|
|
y = (-((-lat) % 90)) + 90.0
|
|
else:
|
|
y = lat + 90.0
|
|
|
|
morton_code = ""
|
|
for dx in _DIVISORS:
|
|
digit = 0
|
|
if y >= dx:
|
|
digit |= 2
|
|
y -= dx
|
|
if x >= dx:
|
|
digit |= 1
|
|
x -= dx
|
|
morton_code += str(digit)
|
|
|
|
return morton_code
|
|
|
|
# Given a set of coordinates find the MBR
|
|
def findMBR(objId, points):
|
|
x_min = min(points, key=lambda p: p[0])[0]
|
|
x_max = max(points, key=lambda p: p[0])[0]
|
|
y_min = min(points, key=lambda p: p[1])[1]
|
|
y_max = max(points, key=lambda p: p[1])[1]
|
|
|
|
return MBR(objId, x_min, x_max, y_min, y_max)
|
|
|
|
# Given a set of MBRs find the MBR
|
|
def createMBR(nodeId, mbrs):
|
|
x_min = min(mbr.xlow for mbr in mbrs)
|
|
x_max = max(mbr.xhigh for mbr in mbrs)
|
|
y_min = min(mbr.ylow for mbr in mbrs)
|
|
y_max = max(mbr.yhigh for mbr in mbrs)
|
|
|
|
return MBR(nodeId, x_min, x_max, y_min, y_max)
|
|
|
|
# Read data from input files
|
|
def inputReader(filename1, filename2):
|
|
set_of_points = []
|
|
with open(filename1, 'r') as offsets, open(filename2, 'r') as coords:
|
|
reader = csv.reader(offsets, delimiter=',', quoting=csv.QUOTE_NONE)
|
|
for row in reader:
|
|
points = []
|
|
for i in range(int(row[2]) - int(row[1]) + 1):
|
|
points.append([float(x) for x in coords.readline().split(',')])
|
|
set_of_points.append([row[0], points])
|
|
|
|
return set_of_points
|
|
|
|
# Write data into output file
|
|
def outputWriter(filename, rTree):
|
|
with open(filename, 'w') as rtree:
|
|
numNode = 0
|
|
leaves = 0
|
|
for level in rTree:
|
|
for node in level:
|
|
rtree.write("[{}, {}, [[".format(leaves, numNode))
|
|
for i in range(len(node) - 1):
|
|
rtree.write("{}, [{}, {}, {}, {}]],[".format(
|
|
node[i].id, node[i].xlow, node[i].xhigh, node[i].ylow, node[i].yhigh))
|
|
rtree.write("{}, [{}, {}, {}, {}]]]]".format(
|
|
node[-1].id, node[-1].xlow, node[-1].xhigh, node[-1].ylow, node[-1].yhigh))
|
|
rtree.write("\n")
|
|
numNode += 1
|
|
leaves = 1
|
|
|
|
#
|
|
def makeRtree(collection):
|
|
level = [] # list of levels(of nodes) of nodes(of mbrs) of mbrs(of points)
|
|
nodeId = 0
|
|
rank = 0
|
|
# Until we reach the root node
|
|
while len(collection) > 1:
|
|
# Split the mbr collection into nodes of 20
|
|
nodes = [collection[x:x+20] for x in range(0, len(collection), 20)]
|
|
|
|
# If the last node has less than 8 mbrs, fill with mbrs of the previous
|
|
balance = 8 - len(nodes[-1])
|
|
if balance > 0 and len(nodes) > 1:
|
|
migrate = len(nodes[-2])
|
|
nodes[-1] = nodes[-2][migrate-balance:] + nodes[-1]
|
|
nodes[-2] = nodes[-2][:migrate-balance]
|
|
|
|
# Make the new MBRs based on the corners of each 20-piece
|
|
collection = []
|
|
for node in nodes: #for every 20 MBRs in 500 MBRs
|
|
collection.append(createMBR(nodeId, node))
|
|
nodeId += 1
|
|
|
|
level.append(nodes)
|
|
print("{} nodes at level {}".format(len(nodes), rank))
|
|
rank += 1
|
|
|
|
return level
|
|
|
|
if __name__ == '__main__':
|
|
# Read the coordinates of the polygons points
|
|
set_of_points = inputReader(filename1=sys.argv[1], filename2=sys.argv[2])
|
|
|
|
# Create the mbrs of the polygons
|
|
mbrs = []
|
|
for sp in set_of_points:
|
|
mbrs.append(findMBR(sp[0], sp[1]))
|
|
|
|
# Sort the mbrs based on the Z curve
|
|
mbrs.sort(key=lambda ld: ld.zcurve)
|
|
|
|
# Make the Rtree
|
|
rTree = makeRtree(mbrs)
|
|
outputWriter("Rtree.txt", rTree)
|