Skip to content

Commit

Permalink
don't encode the closing point of a polygon ring
Browse files Browse the repository at this point in the history
  • Loading branch information
Jake Guthmiller committed Jul 14, 2017
1 parent 79acdb6 commit 30ec182
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 42 deletions.
52 changes: 29 additions & 23 deletions geobuf/decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ class Decoder:
geometry_types = ('Point', 'MultiPoint', 'LineString', 'MultiLineString',
'Polygon', 'MultiPolygon', 'GeometryCollection')

def __init__(self):
self.data = None
self.e = None
self.dim = None

def decode(self, data_str):

data = self.data = geobuf_pb2.Data()
data.ParseFromString(data_str)

self.e = pow(10, data.precision)
self.dim = data.dimensions
self.transformed = False

data_type = data.WhichOneof('data_type')

Expand Down Expand Up @@ -82,7 +86,6 @@ def decode_id(obj, obj_json):
def decode_geometry(self, geometry):
obj = collections.OrderedDict()
gt = obj['type'] = self.geometry_types[geometry.type]
coords_or_arcs = 'coordinates'

self.decode_properties(geometry.custom_properties, geometry.values, obj)

Expand All @@ -91,67 +94,70 @@ def decode_geometry(self, geometry):
elif gt == 'Point':
obj['coordinates'] = self.decode_point(geometry.coords)
elif gt == 'MultiPoint':
obj['coordinates'] = self.decode_line(geometry.coords, True)
obj['coordinates'] = self.decode_line(geometry.coords)
elif gt == 'LineString':
obj[coords_or_arcs] = self.decode_line(geometry.coords)
elif (gt == 'MultiLineString') or (gt == 'Polygon'):
obj[coords_or_arcs] = self.decode_multi_line(geometry)
obj['coordinates'] = self.decode_line(geometry.coords)
elif gt == 'MultiLineString':
obj['coordinates'] = self.decode_multi_line(geometry)
elif gt == 'Polygon':
obj['coordinates'] = self.decode_multi_line(geometry, is_closed=True)
elif gt == 'MultiPolygon':
obj[coords_or_arcs] = self.decode_multi_polygon(geometry)
obj['coordinates'] = self.decode_multi_polygon(geometry)

return obj

def decode_coord(self, coord):
return coord if self.transformed else float(coord) / self.e
return float(coord) / self.e

def decode_point(self, coords):
return [self.decode_coord(x) for x in coords]

def decode_line(self, coords, is_multi_point=False):
def decode_line(self, coords, is_closed=False):
obj = []

d = self.dim
r = range(d)
r2 = range(0, len(coords), d)
p0 = [0 for _ in r]
r = range(self.dim)
r2 = range(0, len(coords), self.dim)
p0 = [0] * self.dim
for i in r2:
p = [p0[j] + coords[i + j] for j in r]
obj.append(self.decode_point(p))
p0 = p

if is_closed:
p = [coords[j] for j in r]
obj.append(self.decode_point(p))

return obj

def decode_multi_line(self, geometry):
def decode_multi_line(self, geometry, is_closed=False):
if len(geometry.lengths) == 0:
return [self.decode_line(geometry.coords)]
return [self.decode_line(geometry.coords, is_closed=is_closed)]

obj = []
i = 0
d = self.dim

for l in geometry.lengths:
obj.append(self.decode_line(geometry.coords[i:i + l * d]))
i += l * d
obj.append(self.decode_line(geometry.coords[i:i + l * self.dim], is_closed=is_closed))
i += l * self.dim

return obj

def decode_multi_polygon(self, geometry):
if len(geometry.lengths) == 0:
return [[self.decode_line(geometry.coords)]]
return [[self.decode_line(geometry.coords, is_closed=True)]]

obj = []
i = 0
num_polygons = geometry.lengths[0]
j = 1
d = self.dim
num_polygons = geometry.lengths[0]

for n in range(num_polygons): # for every polygon
num_rings = geometry.lengths[j]
j += 1
rings = []
for l in geometry.lengths[j:j + num_rings]:
rings.append(self.decode_line(geometry.coords[i:i + l * d]))
rings.append(self.decode_line(geometry.coords[i:i + l * self.dim], is_closed=True))
j += 1
i += l * d
i += l * self.dim
obj.append(rings)
return obj
47 changes: 28 additions & 19 deletions geobuf/encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ class Encoder:
'GeometryCollection': 6,
}

def __init__(self):
self.json = None
self.data = None
self.precision = None
self.dim = None
self.e = None
self.keys = collections.OrderedDict()

def encode(self, data_json, precision=6, dim=2):
obj = self.json = data_json
data = self.data = geobuf_pb2.Data()
Expand All @@ -27,9 +35,6 @@ def encode(self, data_json, precision=6, dim=2):
self.dim = dim
self.e = pow(10, precision) # multiplier for converting coordinates into integers

self.keys = collections.OrderedDict()
self.transformed = False

data_type = obj['type']

if data_type == 'FeatureCollection':
Expand All @@ -56,7 +61,6 @@ def encode_geometry(self, geometry, geometry_json):

gt = geometry_json['type']
coords = geometry_json.get('coordinates')
coords_or_arcs = coords

geometry.type = self.geometry_types[gt]

Expand All @@ -69,13 +73,15 @@ def encode_geometry(self, geometry, geometry_json):
elif gt == 'Point':
self.add_point(geometry.coords, coords)
elif gt == 'MultiPoint':
self.add_line(geometry.coords, coords, True)
self.add_line(geometry.coords, coords)
elif gt == 'LineString':
self.add_line(geometry.coords, coords_or_arcs)
elif gt == 'MultiLineString' or gt == 'Polygon':
self.add_multi_line(geometry, coords_or_arcs)
self.add_line(geometry.coords, coords)
elif gt == 'MultiLineString':
self.add_multi_line(geometry, coords)
elif gt == 'Polygon':
self.add_multi_line(geometry, coords, is_closed=True)
elif gt == 'MultiPolygon':
self.add_multi_polygon(geometry, coords_or_arcs)
self.add_multi_polygon(geometry, coords)

def encode_properties(self, obj, props_json):
if props_json:
Expand Down Expand Up @@ -135,35 +141,38 @@ def encode_id(obj, id):
obj.id = str(id)

def add_coord(self, coords, coord):
coords.append(coord if self.transformed else int(round(coord * self.e)))
coords.append(int(round(coord * self.e)))

def add_point(self, coords, point):
for x in point:
self.add_coord(coords, x)

def add_line(self, coords, points, is_multi_point=False):
def add_line(self, coords, points, is_closed=False):
r = range(self.dim)
for i, p in enumerate(points):
# delta-encode coordinates
sum = [0] * self.dim
r2 = range(0, len(points) - int(is_closed))
for i in r2:
for j in r:
self.add_coord(coords, p[j] - (points[i - 1][j] if i else 0))
n = round(points[i][j] * self.e) - sum[j]
coords.append(n)
sum[j] += n

def add_multi_line(self, geometry, lines):
def add_multi_line(self, geometry, lines, is_closed=False):
if len(lines) != 1:
for points in lines:
geometry.lengths.append(len(points))
geometry.lengths.append(len(points) - int(is_closed))

for points in lines:
self.add_line(geometry.coords, points)
self.add_line(geometry.coords, points, is_closed)

def add_multi_polygon(self, geometry, polygons):
if len(polygons) != 1 or len(polygons[0]) != 1:
geometry.lengths.append(len(polygons))
for rings in polygons:
geometry.lengths.append(len(rings))
for points in rings:
geometry.lengths.append(len(points))
geometry.lengths.append(len(points) - 1)

for rings in polygons:
for points in rings:
self.add_line(geometry.coords, points)
self.add_line(geometry.coords, points, is_closed=True)

0 comments on commit 30ec182

Please sign in to comment.