1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| import json import argparse import os
def reduce_geometry(geometry, step): """ Reduces the number of points in a geometry by taking every n-th point (step). """ if geometry is None: return None geom_type = geometry.get('type') coords = geometry.get('coordinates') if geom_type == 'Point': return geometry if geom_type == 'MultiPoint': geometry['coordinates'] = coords[::step] return geometry if geom_type == 'LineString': new_coords = coords[::step] if len(new_coords) < 2 and len(coords) >= 2: new_coords = [coords[0], coords[-1]] geometry['coordinates'] = new_coords return geometry if geom_type == 'Polygon': new_coords = [] for ring in coords: sampled = ring[::step] if sampled[-1] != ring[-1]: sampled.append(ring[-1]) if len(sampled) < 4 and len(ring) >= 4: sampled = [ring[0], ring[len(ring)//3], ring[2*len(ring)//3], ring[-1]] new_coords.append(sampled) geometry['coordinates'] = new_coords return geometry
if geom_type in ['MultiLineString', 'MultiPolygon']: def process_recursive(c, depth): if depth == 1: sampled = c[::step] if geom_type == 'MultiPolygon' and sampled[-1] != c[-1]: sampled.append(c[-1]) return sampled return [process_recursive(sub, depth - 1) for sub in c] depth = 2 if geom_type == 'MultiLineString' else 3 geometry['coordinates'] = process_recursive(coords, depth) return geometry
return geometry
def main(): parser = argparse.ArgumentParser(description="Reduce GeoJSON file size by skipping coordinate points.") parser.add_argument("input", help="Path to the input data.geojson file") parser.add_argument("-s", "--step", type=int, default=3, help="The step size (e.g., 3 to keep every 3rd point). Default is 3.") parser.add_argument("-o", "--output", help="Output filename. Defaults to 'reduced_<input>'")
args = parser.parse_args()
if not args.output: base, ext = os.path.splitext(args.input) args.output = f"{base}_reduced{ext}"
try: with open(args.input, 'r') as f: data = json.load(f)
if data.get('type') == 'FeatureCollection': for feature in data.get('features', []): feature['geometry'] = reduce_geometry(feature.get('geometry'), args.step) elif data.get('type') == 'Feature': data['geometry'] = reduce_geometry(data.get('geometry'), args.step) else: data = reduce_geometry(data, args.step)
with open(args.output, 'w') as f: json.dump(data, f) print(f"Success! Reduced file saved as: {args.output}") print(f"Sampling rate: Kept 1 every {args.step} points.")
except FileNotFoundError: print(f"Error: The file '{args.input}' was not found.") except json.JSONDecodeError: print(f"Error: The file '{args.input}' is not a valid JSON/GeoJSON.")
if __name__ == "__main__": main()
|