import json from app.apiController import apiController def swap_latlon(coords): # return [[lon, lat] for lat, lon in coords] # print(coords) # return [ # [ [lon, lat] for lat, lon in ring ] # for ring in coords # ] return [ [ [ [lon, lat] for lat, lon in ring ] for ring in polygon ] for polygon in coords ] def swap_latlon2(coords): try: sample = coords[0][0][0] if not (-180 <= sample[0] <= 180 and -90 <= sample[1] <= 90): return [ [ [ [lon, lat] for lat, lon in ring ] for ring in polygon ] for polygon in coords ] else: # Sudah benar [lon, lat] return coords except Exception as e: print(f"[swap_latlon] Error during coordinate swap: {e}") return None def normalize_to_multipolygon(coords): if isinstance(coords, list): if ( isinstance(coords[0], list) and isinstance(coords[0][0], list) and isinstance(coords[0][0][0], list) and isinstance(coords[0][0][0][0], (int, float)) ): return coords # Sudah valid else: # Kurang dimensi → bungkus return [[[coord for coord in ring] for ring in coords]] return coords def audit_geojson_paths(conn, table): cur = conn.cursor() cur.execute(f"SELECT id, path FROM {table}") errors = [] for row in cur.fetchall(): try: coords = json.loads(row[1]) sample_point = coords[0][0][0] if not (-180 <= sample_point[0] <= 180 and -90 <= sample_point[1] <= 90): errors.append(row[0]) except Exception as e: errors.append(row[0]) # print(f"[AUDIT] Invalid GeoJSON paths found in {table}: {errors}") return errors #MAP DATA #========================================================= def fetch_geojson(conn, level, parent_code=None): table_name = { 'provinsi': 'wil_provinsi', 'kabupaten': 'wil_kabupatenkota', 'kecamatan': 'wil_kecamatan', 'desa': 'wil_desa' }.get(level) if not table_name: return {"type": "FeatureCollection", "features": []} # Jalankan audit # invalid_ids = audit_geojson_paths(conn, table_name) cur = conn.cursor() if level == 'provinsi': old_sql = """ SELECT id, kode, nama, lat, lng, CONCAT( REPEAT('[', 4 - (LENGTH(path) - LENGTH(REPLACE(path, '[', '')))), path, REPEAT(']', 4 - (LENGTH(path) - LENGTH(REPLACE(path, ']', '')))) ) AS path FROM wil_provinsi """ sql = """ SELECT wp.id, wp.kode, wp.nama, lat, lng, path, pip.persen as idx FROM wil_provinsi wp JOIN vw_persentase_indeks_provinsi pip on pip.kode = wp.kode WHERE lower(pip.status) in ('maju','mandiri') """ cur.execute(sql) elif level == 'kabupaten': cur.execute(""" SELECT wk.id, wk.kode, wk.nama,lat,wk.lng,wk.path, pik.persen_per_status as idx FROM wil_kabupatenkota wk JOIN vw_persentase_indeks_kabkota pik on pik.kode = wk.kode WHERE provinsi_id = %s """, (parent_code,)) elif level == 'kecamatan': cur.execute(""" SELECT wkc.id, wkc.kode, wkc.nama,wkc.lat,wkc.lng,wkc.path , pic.persen as idx FROM wil_kecamatan wkc JOIN vw_persentase_indeks_kecamatan as pic on pic.id = wkc.id WHERE kabupatenkota_id = %s""", (parent_code,)) elif level == 'desa': cur.execute(""" SELECT wd.id, wd.kode, wd.nama, wd.lat, wd.lng,wd.path, CASE WHEN lower(mid.status) = 'mandiri' THEN 100 WHEN lower(mid.status) = 'maju' THEN 70 WHEN lower(mid.status) = 'berkembang' THEN 50 WHEN lower(mid.status) = 'tertinggal' THEN 20 WHEN lower(mid.status) = 'sangat tertinggal' THEN 0 END as idx FROM wil_desa wd JOIN metrik_indeks_desa mid on mid.kode_desa = wd.kode_int WHERE kecamatan_id = %s""", (parent_code,)) else: return {"type": "FeatureCollection", "features": []} features = [] for row in cur.fetchall(): path = row[5] #Multi poligons try: parsed_path = json.loads(path) normalized = normalize_to_multipolygon(parsed_path) corrected_path = swap_latlon2(normalized) except Exception as e: print(f"Error parsing path for row {row[0]}: {e}") continue if not corrected_path: continue geometry = { "type": "MultiPolygon", "coordinates": corrected_path } feature = { "type": "Feature", "geometry": geometry, "properties": { "id": row[0], "kode": row[1], "nama": row[2], "lat": row[3], "lng": row[4], "idx": row[6] } } features.append(feature) return { "type": "FeatureCollection", "features": features }