def write_coordinate_value(output_file, coord): value = coord2int(coord) write_value(output_file, value, data_format=DTYPE_FORMAT_SIGNED_I, lower_value_limit=THRES_DTYPE_SIGNED_I_LOWER, upper_value_limit=THRES_DTYPE_SIGNED_I_UPPER)
def compute_exact_shortcuts(xmax, xmin, ymax, ymin, line): shortcuts_for_line = set() # x_longs = binary_reader.x_coords_of(line) x_longs, y_longs = ints_of(line) # y_longs = binary_reader.y_coords_of(line) y_longs.append(y_longs[0]) x_longs.append(x_longs[0]) step = 1 / NR_SHORTCUTS_PER_LAT # print('checking the latitudes') for lat in latitudes_to_check(ymax, ymin): # print(lat) # print(coordinate_to_longlong(lat)) # print(y_longs) # print(x_intersections(coordinate_to_longlong(lat), x_longs, y_longs)) # raise ValueError intersects = sorted([int2coord(x) for x in x_intersections(coord2int(lat), x_longs, y_longs)]) # print(intersects) nr_of_intersects = len(intersects) if nr_of_intersects % 2 != 0: raise ValueError('an uneven number of intersections has been accounted') for i in range(0, nr_of_intersects, 2): possible_longitudes = [] # collect all the zones between two intersections [in,out,in,out,...] iplus = i + 1 intersection_in = intersects[i] intersection_out = intersects[iplus] if intersection_in == intersection_out: # the polygon has a point exactly on the border of a shortcut zone here! # only select the top shortcut if it is actually inside the polygon (point a little up is inside) if contained(coord2int(intersection_in), coord2int(lat) + 1, x_longs, y_longs): shortcuts_for_line.add((x_shortcut(intersection_in), y_shortcut(lat) - 1)) # the bottom shortcut is always selected shortcuts_for_line.add((x_shortcut(intersection_in), y_shortcut(lat))) else: # add all the shortcuts for the whole found area of intersection possible_y_shortcut = y_shortcut(lat) # both shortcuts should only be selected when the polygon doesnt stays on the border middle = intersection_in + (intersection_out - intersection_in) / 2 if contained(coord2int(middle), coord2int(lat) + 1, x_longs, y_longs): while intersection_in < intersection_out: possible_longitudes.append(intersection_in) intersection_in += step possible_longitudes.append(intersection_out) # the shortcut above and below of the intersection should be selected! possible_y_shortcut_min1 = possible_y_shortcut - 1 for possible_x_coord in possible_longitudes: shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut)) shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut_min1)) else: # polygon does not cross the border! while intersection_in < intersection_out: possible_longitudes.append(intersection_in) intersection_in += step possible_longitudes.append(intersection_out) # only the shortcut above of the intersection should be selected! for possible_x_coord in possible_longitudes: shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut)) # print('now all the longitudes to check') # same procedure horizontally step = 1 / NR_SHORTCUTS_PER_LAT for lng in longitudes_to_check(xmax, xmin): # print(lng) # print(coordinate_to_longlong(lng)) # print(x_longs) # print(x_intersections(coordinate_to_longlong(lng), x_longs, y_longs)) intersects = sorted([int2coord(y) for y in y_intersections(coord2int(lng), x_longs, y_longs)]) # print(intersects) nr_of_intersects = len(intersects) if nr_of_intersects % 2 != 0: raise ValueError('an uneven number of intersections has been accounted') possible_latitudes = [] for i in range(0, nr_of_intersects, 2): # collect all the zones between two intersections [in,out,in,out,...] iplus = i + 1 intersection_in = intersects[i] intersection_out = intersects[iplus] if intersection_in == intersection_out: # the polygon has a point exactly on the border of a shortcut here! # only select the left shortcut if it is actually inside the polygon (point a little left is inside) if contained(coord2int(lng) - 1, coord2int(intersection_in), x_longs, y_longs): shortcuts_for_line.add((x_shortcut(lng) - 1, y_shortcut(intersection_in))) # the right shortcut is always selected shortcuts_for_line.add((x_shortcut(lng), y_shortcut(intersection_in))) else: # add all the shortcuts for the whole found area of intersection possible_x_shortcut = x_shortcut(lng) # both shortcuts should only be selected when the polygon doesnt stays on the border middle = intersection_in + (intersection_out - intersection_in) / 2 if contained(coord2int(lng) - 1, coord2int(middle), x_longs, y_longs): while intersection_in < intersection_out: possible_latitudes.append(intersection_in) intersection_in += step possible_latitudes.append(intersection_out) # both shortcuts right and left of the intersection should be selected! possible_x_shortcut_min1 = possible_x_shortcut - 1 for possible_latitude in possible_latitudes: shortcuts_for_line.add((possible_x_shortcut, y_shortcut(possible_latitude))) shortcuts_for_line.add((possible_x_shortcut_min1, y_shortcut(possible_latitude))) else: while intersection_in < intersection_out: possible_latitudes.append(intersection_in) intersection_in += step # only the shortcut right of the intersection should be selected! possible_latitudes.append(intersection_out) for possible_latitude in possible_latitudes: shortcuts_for_line.add((possible_x_shortcut, y_shortcut(possible_latitude))) return shortcuts_for_line
def ints_of(line=0): x_coords, y_coords = polygons[line] return [coord2int(x) for x in x_coords], [coord2int(x) for x in y_coords]
def test_distance_computation(self): def km2rad(km): return km / 6371 def km2deg(km): return degrees(km2rad(km)) p_test_cases = [ # (x,y), (0, 1), (1, 0), (0, -1), (-1, 0), # on the line test cases # (-0.5, 0.5), # (0, 0.5), # (-0.5, 0), # (0.5, 0), ] p1_lng_rad = radians(0.0) p1_lat_rad = radians(0.0) for x, y in p_test_cases: result = distance_to_point_on_equator(radians(x), radians(y), p1_lng_rad) if km2deg(result) != 1: raise AssertionError('should be equal:', km2deg(result), 1) hav_result = haversine(radians(x), radians(y), p1_lng_rad, 0) if km2deg(hav_result) != 1.0: raise AssertionError('should be equal:', km2deg(hav_result), 1.0) for i in range(1000): rnd_point = random_point() lng_rnd_point2 = random_point()[0] hav_result = degrees( haversine(radians(rnd_point[0]), radians(rnd_point[1]), lng_rnd_point2, 0)) result = degrees( distance_to_point_on_equator(radians(rnd_point[0]), radians(rnd_point[1]), lng_rnd_point2)) if abs(hav_result - result) > 0.000001: raise AssertionError(i, 'should be equal:', hav_result, result, rnd_point, lng_rnd_point2) x_coords = [0.5, -0.5, -0.5, 0.5] y_coords = [0.5, 0.5, -0.5, -0.5] points = [ [coord2int(x) for x in x_coords], [coord2int(x) for x in y_coords], ] trans_points = [ [None for x in x_coords], [None for x in y_coords], ] x_rad = radians(1.0) y_rad = radians(0.0) print(km2deg(haversine(x_rad, y_rad, p1_lng_rad, p1_lat_rad))) assert km2deg(haversine(x_rad, y_rad, p1_lng_rad, p1_lat_rad)) == 1 distance_exact = distance_to_polygon_exact(x_rad, y_rad, len(x_coords), points, trans_points) print(km2deg(distance_exact)) assert km2deg(distance_exact) == 0.5 print('=====') distance = distance_to_polygon(x_rad, y_rad, len(x_coords), points) print(km2deg(distance)) assert abs(km2deg(distance) - sqrt(2) / 2) < 0.00001
def compile_binaries(): global nr_of_lines global shortcuts def print_shortcut_statistics(): frequencies = [] max_val = max(*nr_of_entries_in_shortcut) print('shortcut statistics:') print('highest entry amount is', max_val) while max_val >= 0: frequencies.append(nr_of_entries_in_shortcut.count(max_val)) max_val -= 1 frequencies.reverse() print('frequencies of entry amounts (from 0 to max entries):') print(frequencies) empty_shortcuts = frequencies[0] print('relative accumulated frequencies [%]:') acc = accumulated_frequency(frequencies) print(acc) print([round(100 - x, 2) for x in acc]) print(percent(empty_shortcuts, amount_of_shortcuts), '% of all shortcuts are empty\n') amount_of_different_zones = [] for entry in shortcut_entries: registered_zone_ids = [] for polygon_nr in entry: id = poly_zone_ids[polygon_nr] if id not in registered_zone_ids: registered_zone_ids.append(id) amount_of_different_zones.append(len(registered_zone_ids)) frequencies = [] max_val = max(*amount_of_different_zones) print('highest amount of different zones in one shortcut is', max_val) while max_val >= 1: frequencies.append(amount_of_different_zones.count(max_val)) max_val -= 1 # show the proper amount of shortcuts with 0 zones (=nr of empty shortcuts) frequencies.append(empty_shortcuts) frequencies.reverse() print('frequencies of entry amounts (from 0 to max):') print(frequencies) print('relative accumulated frequencies [%]:') acc = accumulated_frequency(frequencies) print(acc) print([round(100 - x, 2) for x in acc]) print('--------------------------------\n') def included_shortcut_row_nrs(max_lat, min_lat): return list(range(y_shortcut(max_lat), y_shortcut(min_lat) + 1)) def included_shortcut_column_nrs(max_lng, min_lng): return list(range(x_shortcut(min_lng), x_shortcut(max_lng) + 1)) def longitudes_to_check(max_lng, min_lng): output_list = [] step = 1 / NR_SHORTCUTS_PER_LNG current = ceil(min_lng * NR_SHORTCUTS_PER_LNG) / NR_SHORTCUTS_PER_LNG end = floor(max_lng * NR_SHORTCUTS_PER_LNG) / NR_SHORTCUTS_PER_LNG while current < end: output_list.append(current) current += step output_list.append(end) return output_list def latitudes_to_check(max_lat, min_lat): output_list = [] step = 1 / NR_SHORTCUTS_PER_LAT current = ceil(min_lat * NR_SHORTCUTS_PER_LAT) / NR_SHORTCUTS_PER_LAT end = floor(max_lat * NR_SHORTCUTS_PER_LAT) / NR_SHORTCUTS_PER_LAT while current < end: output_list.append(current) current += step output_list.append(end) return output_list def compute_x_intersection(y, x1, x2, y1, y2): """returns the x intersection from a horizontal line in y with the line from x1,y1 to x1,y2 """ delta_y = y2 - y1 if delta_y == 0: return x1 return ((y - y1) * (x2 - x1) / delta_y) + x1 def compute_y_intersection(x, x1, x2, y1, y2): """returns the y intersection from a vertical line in x with the line from x1,y1 to x1,y2 """ delta_x = x2 - x1 if delta_x == 0: return x1 return ((x - x1) * (y2 - y1) / delta_x) + y1 def x_intersections(y, x_coords, y_coords): intersects = [] for i in range(len(y_coords) - 1): iplus1 = i + 1 if y_coords[i] <= y: # print('Y1<=y') if y_coords[iplus1] > y: # this was a crossing. compute the intersect # print('Y2>y') intersects.append( compute_x_intersection(y, x_coords[i], x_coords[iplus1], y_coords[i], y_coords[iplus1])) else: # print('Y1>y') if y_coords[iplus1] <= y: # this was a crossing. compute the intersect # print('Y2<=y') intersects.append(compute_x_intersection(y, x_coords[i], x_coords[iplus1], y_coords[i], y_coords[iplus1])) return intersects def y_intersections(x, x_coords, y_coords): intersects = [] for i in range(len(y_coords) - 1): iplus1 = i + 1 if x_coords[i] <= x: if x_coords[iplus1] > x: # this was a crossing. compute the intersect intersects.append( compute_y_intersection(x, x_coords[i], x_coords[iplus1], y_coords[i], y_coords[iplus1])) else: if x_coords[iplus1] <= x: # this was a crossing. compute the intersect intersects.append(compute_y_intersection(x, x_coords[i], x_coords[iplus1], y_coords[i], y_coords[iplus1])) return intersects def compute_exact_shortcuts(xmax, xmin, ymax, ymin, line): shortcuts_for_line = set() # x_longs = binary_reader.x_coords_of(line) x_longs, y_longs = ints_of(line) # y_longs = binary_reader.y_coords_of(line) y_longs.append(y_longs[0]) x_longs.append(x_longs[0]) step = 1 / NR_SHORTCUTS_PER_LAT # print('checking the latitudes') for lat in latitudes_to_check(ymax, ymin): # print(lat) # print(coordinate_to_longlong(lat)) # print(y_longs) # print(x_intersections(coordinate_to_longlong(lat), x_longs, y_longs)) # raise ValueError intersects = sorted([int2coord(x) for x in x_intersections(coord2int(lat), x_longs, y_longs)]) # print(intersects) nr_of_intersects = len(intersects) if nr_of_intersects % 2 != 0: raise ValueError('an uneven number of intersections has been accounted') for i in range(0, nr_of_intersects, 2): possible_longitudes = [] # collect all the zones between two intersections [in,out,in,out,...] iplus = i + 1 intersection_in = intersects[i] intersection_out = intersects[iplus] if intersection_in == intersection_out: # the polygon has a point exactly on the border of a shortcut zone here! # only select the top shortcut if it is actually inside the polygon (point a little up is inside) if contained(coord2int(intersection_in), coord2int(lat) + 1, x_longs, y_longs): shortcuts_for_line.add((x_shortcut(intersection_in), y_shortcut(lat) - 1)) # the bottom shortcut is always selected shortcuts_for_line.add((x_shortcut(intersection_in), y_shortcut(lat))) else: # add all the shortcuts for the whole found area of intersection possible_y_shortcut = y_shortcut(lat) # both shortcuts should only be selected when the polygon doesnt stays on the border middle = intersection_in + (intersection_out - intersection_in) / 2 if contained(coord2int(middle), coord2int(lat) + 1, x_longs, y_longs): while intersection_in < intersection_out: possible_longitudes.append(intersection_in) intersection_in += step possible_longitudes.append(intersection_out) # the shortcut above and below of the intersection should be selected! possible_y_shortcut_min1 = possible_y_shortcut - 1 for possible_x_coord in possible_longitudes: shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut)) shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut_min1)) else: # polygon does not cross the border! while intersection_in < intersection_out: possible_longitudes.append(intersection_in) intersection_in += step possible_longitudes.append(intersection_out) # only the shortcut above of the intersection should be selected! for possible_x_coord in possible_longitudes: shortcuts_for_line.add((x_shortcut(possible_x_coord), possible_y_shortcut)) # print('now all the longitudes to check') # same procedure horizontally step = 1 / NR_SHORTCUTS_PER_LAT for lng in longitudes_to_check(xmax, xmin): # print(lng) # print(coordinate_to_longlong(lng)) # print(x_longs) # print(x_intersections(coordinate_to_longlong(lng), x_longs, y_longs)) intersects = sorted([int2coord(y) for y in y_intersections(coord2int(lng), x_longs, y_longs)]) # print(intersects) nr_of_intersects = len(intersects) if nr_of_intersects % 2 != 0: raise ValueError('an uneven number of intersections has been accounted') possible_latitudes = [] for i in range(0, nr_of_intersects, 2): # collect all the zones between two intersections [in,out,in,out,...] iplus = i + 1 intersection_in = intersects[i] intersection_out = intersects[iplus] if intersection_in == intersection_out: # the polygon has a point exactly on the border of a shortcut here! # only select the left shortcut if it is actually inside the polygon (point a little left is inside) if contained(coord2int(lng) - 1, coord2int(intersection_in), x_longs, y_longs): shortcuts_for_line.add((x_shortcut(lng) - 1, y_shortcut(intersection_in))) # the right shortcut is always selected shortcuts_for_line.add((x_shortcut(lng), y_shortcut(intersection_in))) else: # add all the shortcuts for the whole found area of intersection possible_x_shortcut = x_shortcut(lng) # both shortcuts should only be selected when the polygon doesnt stays on the border middle = intersection_in + (intersection_out - intersection_in) / 2 if contained(coord2int(lng) - 1, coord2int(middle), x_longs, y_longs): while intersection_in < intersection_out: possible_latitudes.append(intersection_in) intersection_in += step possible_latitudes.append(intersection_out) # both shortcuts right and left of the intersection should be selected! possible_x_shortcut_min1 = possible_x_shortcut - 1 for possible_latitude in possible_latitudes: shortcuts_for_line.add((possible_x_shortcut, y_shortcut(possible_latitude))) shortcuts_for_line.add((possible_x_shortcut_min1, y_shortcut(possible_latitude))) else: while intersection_in < intersection_out: possible_latitudes.append(intersection_in) intersection_in += step # only the shortcut right of the intersection should be selected! possible_latitudes.append(intersection_out) for possible_latitude in possible_latitudes: shortcuts_for_line.add((possible_x_shortcut, y_shortcut(possible_latitude))) return shortcuts_for_line def construct_shortcuts(): print('building shortucts...') print('currently at polygon nr:') line = 0 for xmax, xmin, ymax, ymin in all_boundaries: # xmax, xmin, ymax, ymin = boundaries_of(line=line) if line % 100 == 0: print(line) # print([xmax, xmin, ymax, ymin]) column_nrs = included_shortcut_column_nrs(xmax, xmin) row_nrs = included_shortcut_row_nrs(ymax, ymin) if big_zone(xmax, xmin, ymax, ymin): # print('line ' + str(line)) # print('This is a big zone! computing exact shortcuts') # print('Nr of entries before') # print(len(column_nrs) * len(row_nrs)) # print('columns and rows before optimisation:') # print(column_nrs) # print(row_nrs) # print(ints_of(line)) # This is a big zone! compute exact shortcuts with the whole polygon points shortcuts_for_line = compute_exact_shortcuts(xmax, xmin, ymax, ymin, line) # n += len(shortcuts_for_line) min_x_shortcut = column_nrs[0] max_x_shortcut = column_nrs[-1] min_y_shortcut = row_nrs[0] max_y_shortcut = row_nrs[-1] shortcuts_to_remove = [] # remove shortcuts from outside the possible/valid area for x, y in shortcuts_for_line: if x < min_x_shortcut or x > max_x_shortcut or y < min_y_shortcut or y > max_y_shortcut: shortcuts_to_remove.append((x, y)) for s in shortcuts_to_remove: shortcuts_for_line.remove(s) # print('and after:') # print(len(shortcuts_for_line)) # print(shortcuts_for_line) # column_nrs_after = set() # row_nrs_after = set() # for x, y in shortcuts_for_line: # column_nrs_after.add(x) # row_nrs_after.add(y) # print(column_nrs_after) # print(row_nrs_after) # print(shortcuts_for_line) if len(shortcuts_for_line) > len(column_nrs) * len(row_nrs): raise ValueError( 'there are more shortcuts than before now. there is something wrong with the algorithm!') if len(shortcuts_for_line) < 3: raise ValueError('algorithm not valid! less than 3 zones detected (should be at least 3)') else: shortcuts_for_line = [] for column_nr in column_nrs: for row_nr in row_nrs: shortcuts_for_line.append((column_nr, row_nr)) # print(shortcuts_for_line) for shortcut in shortcuts_for_line: shortcuts[shortcut] = shortcuts.get(shortcut, []) + [line] line += 1 # print('collected entries:') # print(n) start_time = datetime.now() construct_shortcuts() end_time = datetime.now() print('calculating the shortcuts took:', end_time - start_time, '\n') # there are two floats per coordinate (lng, lat) nr_of_floats = 2 * sum(all_lengths) # write number of entries in shortcut field (x,y) nr_of_entries_in_shortcut = [] shortcut_entries = [] amount_filled_shortcuts = 0 def sort_poly_shortcut(poly_nrs): # TODO write test # the list of polygon ids in each shortcut is sorted after freq. of appearance of their zone id # this is critical for ruling out zones faster # (as soon as just polygons of one zone are left this zone can be returned) # only around 5% of all shortcuts include polygons from more than one zone # in most of those cases there are only two types of zones (= entries in counted_zones) and one of them # has only one entry (important to check the zone with one entry first!). polygon_ids = [poly_zone_ids[poly_nr] for poly_nr in poly_nrs] id_freq = [polygon_ids.count(id) for id in polygon_ids] zipped = list(zip(poly_nrs, polygon_ids, id_freq)) # also make sure polygons with the same zone freq. are ordered after their zone id # (polygons from different zones should not get mixed up) sort = sorted((sorted(zipped, key=lambda x: x[1])), key=lambda x: x[2]) return [x[0] for x in sort] # take only the polygon nrs # count how many shortcut addresses will be written: # flatten out the shortcuts in one list in the order they are going to be written inside the polygon file for x in range(360 * NR_SHORTCUTS_PER_LNG): for y in range(180 * NR_SHORTCUTS_PER_LAT): try: shortcuts_this_entry = shortcuts[(x, y)] shortcut_entries.append(sort_poly_shortcut(shortcuts_this_entry)) amount_filled_shortcuts += 1 nr_of_entries_in_shortcut.append(len(shortcuts_this_entry)) # print((x,y,this_lines_shortcuts)) except KeyError: nr_of_entries_in_shortcut.append(0) amount_of_shortcuts = len(nr_of_entries_in_shortcut) print_shortcut_statistics() if amount_of_shortcuts != 360 * 180 * NR_SHORTCUTS_PER_LNG * NR_SHORTCUTS_PER_LAT: print(amount_of_shortcuts) raise ValueError('this number of shortcut zones is wrong') print('The number of filled shortcut zones are:', amount_filled_shortcuts, '(=', round((amount_filled_shortcuts / amount_of_shortcuts) * 100, 2), '% of all shortcuts)') # for every shortcut <H and <I is written (nr of entries and address) shortcut_space = 360 * NR_SHORTCUTS_PER_LNG * 180 * NR_SHORTCUTS_PER_LAT * (NR_BYTES_H + NR_BYTES_I) for nr in nr_of_entries_in_shortcut: # every line in every shortcut takes up 2bytes shortcut_space += NR_BYTES_H * nr print('The number of polygons is:', nr_of_lines) print('The number of floats in all the polygons is (2 per point):', nr_of_floats) path = 'poly_nr2zone_id.bin' print('writing file', path) output_file = open(path, 'wb') for zone_id in poly_nr2zone_id: output_file.write(pack(b'<H', zone_id)) output_file.close() print('Done\n') # write zone_ids path = 'poly_zone_ids.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for zone_id in poly_zone_ids: output_file.write(pack(b'<H', zone_id)) output_file.close() # write boundary_data path = 'poly_max_values.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for xmax, xmin, ymax, ymin in all_boundaries: output_file.write(pack(b'<iiii', coord2int(xmax), coord2int(xmin), coord2int(ymax), coord2int(ymin))) output_file.close() # write polygon_data, addresses and number of values path = 'poly_data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') addresses = [] i = 0 for x_coords, y_coords in all_coords: addresses.append(output_file.tell()) if all_lengths[i] != len(x_coords): raise ValueError('x_coords do not have the expected length!', all_lengths[i], len(x_coords)) for x in x_coords: output_file.write(pack(b'<i', coord2int(x))) for y in y_coords: output_file.write(pack(b'<i', coord2int(y))) i += 1 output_file.close() path = 'poly_adr2data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for adr in addresses: output_file.write(pack(b'<I', adr)) output_file.close() path = 'poly_coord_amount.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for length in all_lengths: output_file.write(pack(b'<I', length)) output_file.close() # [SHORTCUT AREA] # write all nr of entries path = 'shortcuts_entry_amount.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for nr in nr_of_entries_in_shortcut: if nr > 300: raise ValueError("There are too many polygons in this shortcut:", nr) output_file.write(pack(b'<H', nr)) output_file.close() # write Address of first Polygon_nr in shortcut field (x,y) # Attention: 0 is written when no entries are in this shortcut adr = 0 path = 'shortcuts_adr2data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for nr in nr_of_entries_in_shortcut: if nr == 0: output_file.write(pack(b'<I', 0)) else: output_file.write(pack(b'<I', adr)) # each line_nr takes up 2 bytes of space adr += 2 * nr output_file.close() # write Line_Nrs for every shortcut path = 'shortcuts_data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for entries in shortcut_entries: for entry in entries: if entry > nr_of_lines: raise ValueError(entry) output_file.write(pack(b'<H', entry)) output_file.close() # write corresponding zone id for every shortcut (iff unique) path = 'shortcuts_unique_id.bin' print('writing file "', path, '"') output_file = open(path, 'wb') if poly_zone_ids[-1] >= INVALID_ZONE_ID: raise ValueError( 'There are too many zones for this data type (H). The shortcuts_unique_id file need a Invalid Id!') for x in range(360 * NR_SHORTCUTS_PER_LNG): for y in range(180 * NR_SHORTCUTS_PER_LAT): try: shortcuts_this_entry = shortcuts[(x, y)] unique_id = poly_zone_ids[shortcuts_this_entry[0]] for nr in shortcuts_this_entry: if poly_zone_ids[nr] != unique_id: # there is a polygon from a different zone (hence an invalid id should be written) unique_id = INVALID_ZONE_ID break output_file.write(pack(b'<H', unique_id)) except KeyError: # also write an Invalid Id when there is no polygon at all output_file.write(pack(b'<H', INVALID_ZONE_ID)) output_file.close() # [HOLE AREA, Y = number of holes (very few: around 22)] hole_space = 0 # '<H' for every hole store the related line path = 'hole_poly_ids.bin' print('writing file "', path, '"') output_file = open(path, 'wb') i = 0 for line in polynrs_of_holes: if line > nr_of_lines: raise ValueError(line, nr_of_lines) output_file.write(pack(b'<H', line)) i += 1 hole_space += output_file.tell() output_file.close() if i > amount_of_holes: raise ValueError('There are more related lines than holes.') # '<H' Y times [H unsigned short: nr of values (coordinate PAIRS! x,y in int32 int32) in this hole] path = 'hole_coord_amount.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for length in all_hole_lengths: output_file.write(pack(b'<H', length)) hole_space += output_file.tell() output_file.close() # '<I' Y times [ I unsigned int: absolute address of the byte where the data of that hole starts] adr = 0 path = 'hole_adr2data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for length in all_hole_lengths: output_file.write(pack(b'<I', adr)) # each pair of points takes up 8 bytes of space adr += 2 * NR_BYTES_I * length hole_space += output_file.tell() output_file.close() # Y times [ 2x i signed ints for every hole: x coords, y coords ] # write hole polygon_data path = 'hole_data.bin' print('writing file "', path, '"') output_file = open(path, 'wb') for x_coords, y_coords in all_holes: for x in x_coords: output_file.write(pack(b'<i', coord2int(x))) for y in y_coords: output_file.write(pack(b'<i', coord2int(y))) hole_space += output_file.tell() output_file.close() polygon_space = nr_of_floats * NR_BYTES_I total_space = polygon_space + hole_space + shortcut_space print('the polygon data makes up', percent(polygon_space, total_space), '% of the data') print('the shortcuts make up', percent(shortcut_space, total_space), '% of the data') print('holes make up', percent(hole_space, total_space), '% of the data') print('Success!') return