import geopandas as gpd import fiona import zipfile import tempfile import os import shutil from shapely.geometry import shape def read_shp(path: str): if not path: raise ValueError("Path shapefile tidak boleh kosong.") tmpdir = None shp_path = None if path.lower().endswith(".zip"): tmpdir = tempfile.mkdtemp() with zipfile.ZipFile(path, "r") as zip_ref: zip_ref.extractall(tmpdir) shp_files = [] for root, _, files in os.walk(tmpdir): for f in files: if f.lower().endswith(".shp"): shp_files.append(os.path.join(root, f)) if not shp_files: raise ValueError("Tidak ditemukan file .shp di dalam ZIP.") shp_path = shp_files[0] print(f"[DEBUG] Membaca shapefile: {os.path.basename(shp_path)}") else: shp_path = path try: gdf = gpd.read_file(shp_path) except Exception as e: raise ValueError(f"Gagal membaca shapefile: {e}") if "geometry" not in gdf.columns or gdf.geometry.is_empty.all(): print("[WARN] Geometry kosong. Mencoba membangun ulang dari fitur mentah...") with fiona.open(shp_path) as src: features = [] for feat in src: geom = shape(feat["geometry"]) if feat["geometry"] else None props = feat["properties"] props["geometry"] = geom features.append(props) gdf = gpd.GeoDataFrame(features, geometry="geometry", crs=src.crs) if gdf.crs is None: # print("[WARN] CRS tidak terdeteksi. Diasumsikan EPSG:4326") gdf.set_crs("EPSG:4326", inplace=True) if tmpdir and os.path.exists(tmpdir): shutil.rmtree(tmpdir) return gdf