def test_clips_poygons(): clipped = clip([{ 'geometry': closed(geom1), 'type': 'Polygon', 'tags': 1, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 60 }, { 'geometry': closed(geom2), 'type': 'Polygon', 'tags': 2, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 10 }], 1, 10, 40, 0, float('-inf'), float('inf'), {}) expected = [{ 'id': None, 'type': 'Polygon', 'geometry': [[ 10., 0., 1., 40., 0., 1., 40., 10., 1., 20., 10., 0., 20., 20., 0., 30., 20., 0., 30., 30., 0., 40., 30., 1., 40., 40., 1., 25., 40., 0., 25., 50., 0., 10., 50., 1., 10., 60., 1., 25., 60., 0., 10., 24., 1., 10., 0., 1. ]], 'tags': 1, 'minX': 10, 'minY': 0, 'maxX': 40, 'maxY': 60 }, { 'id': None, 'type': 'Polygon', 'geometry': [[10., 0., 1., 40., 0., 1., 40., 10., 1., 10., 10., 1., 10., 0., 1.]], 'tags': 2, 'minX': 10, 'minY': 0, 'maxX': 40, 'maxY': 10 }] for c, e in zip(clipped, expected): assert c.get('geometry') == e.get('geometry')
def wrap(features, options): buffer = options.get('buffer') / options.get('extent') merged = features left = clip(features, 1, -1 - buffer, buffer, 0, -1, 2, options) # left world copy right = clip(features, 1, 1 - buffer, 2 + buffer, 0, -1, 2, options) # right world copy if left is not None or right is not None: c = clip(features, 1, -buffer, 1 + buffer, 0, -1, 2, options) merged = c if c is not None else [] # :nter world copy if left is not None: merged = shift_feature_coords(left, 1) + merged # merge left into center if right is not None: # merge right into center merged = merged + (shift_feature_coords(right, -1)) return merged
def test_clips_polylines(): clipped = clip([{ 'geometry': geom1, 'type': 'LineString', 'tags': 1, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 60 }, { 'geometry': geom2, 'type': 'LineString', 'tags': 2, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 10 }], 1, 10, 40, 0, float('-inf'), float('inf'), {}) expected = [{ 'id': None, 'type': 'MultiLineString', 'geometry': [[10, 0, 1, 40, 0, 1], [40, 10, 1, 20, 10, 0, 20, 20, 0, 30, 20, 0, 30, 30, 0, 40, 30, 1], [40, 40, 1, 25, 40, 0, 25, 50, 0, 10, 50, 1], [10, 60, 1, 25, 60, 0]], 'tags': 1, 'minX': 10, 'minY': 0, 'maxX': 40, 'maxY': 60 }, { 'id': None, 'type': 'MultiLineString', 'geometry': [[10, 0, 1, 40, 0, 1], [40, 10, 1, 10, 10, 1]], 'tags': 2, 'minX': 10, 'minY': 0, 'maxX': 40, 'maxY': 10 }] assert clipped == expected
def test_clips_line_metrics_on(): geom = Slice(geom1) geom.size = 0 for i in range(0, len(geom) - 3, 3): dx = geom[i + 3] - geom[i] dy = geom[i + 4] - geom[i + 1] geom.size += math.sqrt(dx * dx + dy * dy) geom.start = 0 geom.end = geom.size clipped = clip([{ 'geometry': geom, 'type': 'LineString', 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 60 }], 1, 10, 40, 0, float('-inf'), float('inf'), {'lineMetrics': True}) expected = [[10.0, 40.0], [70.0, 130.0], [160.0, 200.0], [230.0, 245.0]] for c, e in zip(clipped, expected): assert [c.get('geometry').start, c.get('geometry').end] == e
def test_clips_points(): clipped = clip([{ 'geometry': geom1, 'type': 'MultiPoint', 'tags': 1, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 60 }, { 'geometry': geom2, 'type': 'MultiPoint', 'tags': 2, 'minX': 0, 'minY': 0, 'maxX': 50, 'maxY': 10 }], 1, 10, 40, 0, float('-inf'), float('inf'), {}) assert clipped == [{ 'id': None, 'type': 'MultiPoint', 'geometry': [ 20, 10, 0, 20, 20, 0, 30, 20, 0, 30, 30, 0, 25, 40, 0, 25, 50, 0, 25, 60, 0 ], 'tags': 1, 'minX': 20, 'minY': 10, 'maxX': 30, 'maxY': 60 }]
def split_tile(self, features, z, x, y, cz=None, cx=None, cy=None): stack = [features, z, x, y] options = self.options # avoid recursion by using a processing queue while len(stack) > 0: y = stack.pop() x = stack.pop() z = stack.pop() features = stack.pop() z2 = 1 << z id_ = to_Id(z, x, y) tile = self.tiles.get(id_, None) if tile is None: logging.debug('creation start') self.tiles[id_] = create_tile(features, z, x, y, options) tile = self.tiles[id_] self.tile_coords.append({'z': z, 'x': x, 'y': y}) logging.debug( f'tile z{z}-{x}-{y} (features: {tile.get("numFeatures")}, points: {tile.get("numPoints")}, simplified: {tile.get("numSimplified")})' ) logging.debug(f'creation end') key = f'z{z}' self.stats[key] = self.stats.get(key, 0) + 1 self.total += 1 # save reference to original geometry in tile so that we can drill down later if we stop now tile['source'] = features # if it's the first-pass tiling if cz is None: # stop tiling if we reached max zoom, or if the tile is too simple if z == options.get('indexMaxZoom') or tile.get( 'numPoints') <= options.get('indexMaxPoints'): continue # if a drilldown to a specific tile elif z == options.get('maxZoom') or z == cz: # stop tiling if we reached base zoom or our target tile zoom continue elif cz is not None: # stop tiling if it's not an ancestor of the target tile zoomSteps = cz - z if x != (cx >> zoomSteps) or y != (cy >> zoomSteps): continue # if we slice further down, no need to keep source geometry tile['source'] = None if not features or len(features) == 0: continue logging.debug('clipping start') # values we'll use for clipping k1 = 0.5 * options.get('buffer') / options.get('extent') k2 = 0.5 - k1 k3 = 0.5 + k1 k4 = 1 + k1 tl = None bl = None tr = None br = None left = clip(features, z2, x - k1, x + k3, 0, tile['minX'], tile['maxX'], options) right = clip(features, z2, x + k2, x + k4, 0, tile['minX'], tile['maxX'], options) features = None if left is not None: tl = clip(left, z2, y - k1, y + k3, 1, tile['minY'], tile['maxY'], options) bl = clip(left, z2, y + k2, y + k4, 1, tile['minY'], tile['maxY'], options) left = None if right is not None: tr = clip(right, z2, y - k1, y + k3, 1, tile['minY'], tile['maxY'], options) br = clip(right, z2, y + k2, y + k4, 1, tile['minY'], tile['maxY'], options) right = None logging.debug(f'clipping took end') #stack.push(tl or [], z + 1, x * 2, y * 2) stack.append(tl if tl is not None else []) stack.append(z + 1) stack.append(x * 2) stack.append(y * 2) #stack.push(bl or [], z + 1, x * 2, y * 2 + 1) stack.append(bl if bl is not None else []) stack.append(z + 1) stack.append(x * 2) stack.append(y * 2 + 1) #stack.push(tr or [], z + 1, x * 2 + 1, y * 2) stack.append(tr if tr is not None else []) stack.append(z + 1) stack.append(x * 2 + 1) stack.append(y * 2) #stack.push(br or [], z + 1, x * 2 + 1, y * 2 + 1) stack.append(br if br is not None else []) stack.append(z + 1) stack.append(x * 2 + 1) stack.append(y * 2 + 1)