bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
372 lines
11 KiB
Python
372 lines
11 KiB
Python
"""
|
|
Landvex ArcGIS Toolbox
|
|
Python toolbox for ArcGIS Pro integration
|
|
"""
|
|
|
|
import arcpy
|
|
import requests
|
|
import json
|
|
from datetime import datetime
|
|
|
|
|
|
class LandvexToolbox(object):
|
|
"""Landvex Urban Intelligence Toolbox"""
|
|
|
|
def __init__(self):
|
|
self.label = "Landvex"
|
|
self.alias = "landvex"
|
|
self.tools = [
|
|
LoadObservationsTool,
|
|
LoadRGITool,
|
|
LoadUMITool,
|
|
ExportToLandvexTool,
|
|
]
|
|
|
|
|
|
class LoadObservationsTool(object):
|
|
"""Load observations from Landvex API"""
|
|
|
|
def __init__(self):
|
|
self.label = "Load Observations"
|
|
self.description = "Load infrastructure observations from Landvex"
|
|
self.canRunInBackground = True
|
|
|
|
def getParameterInfo(self):
|
|
params = []
|
|
|
|
# API URL
|
|
param = arcpy.Parameter(
|
|
displayName="API URL",
|
|
name="api_url",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
param.value = "https://api.landvex.com/v1"
|
|
params.append(param)
|
|
|
|
# API Key
|
|
param = arcpy.Parameter(
|
|
displayName="API Key",
|
|
name="api_key",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
# Bounds (optional)
|
|
param = arcpy.Parameter(
|
|
displayName="Bounding Box",
|
|
name="bounds",
|
|
datatype="GPExtent",
|
|
parameterType="Optional",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
# Output Feature Class
|
|
param = arcpy.Parameter(
|
|
displayName="Output Feature Class",
|
|
name="output_fc",
|
|
datatype="DEFeatureClass",
|
|
parameterType="Required",
|
|
direction="Output"
|
|
)
|
|
params.append(param)
|
|
|
|
return params
|
|
|
|
def execute(self, parameters, messages):
|
|
api_url = parameters[0].valueAsText
|
|
api_key = parameters[1].valueAsText
|
|
bounds = parameters[2].value
|
|
output_fc = parameters[3].valueAsText
|
|
|
|
try:
|
|
# Fetch observations
|
|
arcpy.AddMessage("Fetching observations from Landvex...")
|
|
|
|
headers = {"Authorization": f"Bearer {api_key}"}
|
|
params = {"limit": 10000}
|
|
|
|
if bounds:
|
|
params["bounds"] = f"{bounds.XMin},{bounds.YMin},{bounds.XMax},{bounds.YMax}"
|
|
|
|
response = requests.get(
|
|
f"{api_url}/observations",
|
|
headers=headers,
|
|
params=params
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
observations = data.get("observations", [])
|
|
arcpy.AddMessage(f"Retrieved {len(observations)} observations")
|
|
|
|
# Create feature class
|
|
sr = arcpy.SpatialReference(4326) # WGS84
|
|
|
|
arcpy.CreateFeatureclass_management(
|
|
out_path="\\".join(output_fc.split("\\")[:-1]),
|
|
out_name=output_fc.split("\\")[-1],
|
|
geometry_type="POINT",
|
|
spatial_reference=sr
|
|
)
|
|
|
|
# Add fields
|
|
fields = [
|
|
("obs_id", "TEXT", 50),
|
|
("obj_type", "TEXT", 100),
|
|
("condition", "SHORT"),
|
|
("zoomer", "TEXT", 100),
|
|
("status", "TEXT", 20),
|
|
("obs_date", "DATE"),
|
|
("rgi_score", "DOUBLE"),
|
|
]
|
|
|
|
for field_name, field_type, *length in fields:
|
|
if field_type == "TEXT":
|
|
arcpy.AddField_management(output_fc, field_name, field_type, field_length=length[0])
|
|
else:
|
|
arcpy.AddField_management(output_fc, field_name, field_type)
|
|
|
|
# Insert features
|
|
with arcpy.da.InsertCursor(output_fc, ["SHAPE@XY", "obs_id", "obj_type", "condition", "zoomer", "status", "obs_date", "rgi_score"]) as cursor:
|
|
for obs in observations:
|
|
cursor.insertRow([
|
|
(obs["lng"], obs["lat"]),
|
|
obs["id"],
|
|
obs["type"],
|
|
obs["condition"],
|
|
obs["zoomer"],
|
|
obs["status"],
|
|
obs["date"],
|
|
obs.get("rgi", 0)
|
|
])
|
|
|
|
arcpy.AddMessage(f"Created feature class with {len(observations)} observations")
|
|
|
|
# Apply symbology
|
|
self.apply_symbology(output_fc)
|
|
|
|
except Exception as e:
|
|
arcpy.AddError(f"Error: {str(e)}")
|
|
|
|
def apply_symbology(self, feature_class):
|
|
"""Apply condition-based symbology"""
|
|
# Create layer file with graduated colors
|
|
# Green (1) → Red (5)
|
|
pass
|
|
|
|
|
|
class LoadRGITool(object):
|
|
"""Load RGI heatmap"""
|
|
|
|
def __init__(self):
|
|
self.label = "Load RGI Heatmap"
|
|
self.description = "Load Reality Gap Index grid"
|
|
self.canRunInBackground = True
|
|
|
|
def getParameterInfo(self):
|
|
params = []
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API URL",
|
|
name="api_url",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
param.value = "https://api.landvex.com/v1"
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API Key",
|
|
name="api_key",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="Grid Resolution",
|
|
name="resolution",
|
|
datatype="GPLong",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
param.value = 100 # meters
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="Output Raster",
|
|
name="output_raster",
|
|
datatype="DERasterDataset",
|
|
parameterType="Required",
|
|
direction="Output"
|
|
)
|
|
params.append(param)
|
|
|
|
return params
|
|
|
|
def execute(self, parameters, messages):
|
|
api_url = parameters[0].valueAsText
|
|
api_key = parameters[1].valueAsText
|
|
resolution = parameters[2].value
|
|
output_raster = parameters[3].valueAsText
|
|
|
|
try:
|
|
arcpy.AddMessage("Fetching RGI grid...")
|
|
|
|
response = requests.get(
|
|
f"{api_url}/indexes/rgi/grid",
|
|
headers={"Authorization": f"Bearer {api_key}"},
|
|
params={"resolution": resolution}
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
# Create raster from grid cells
|
|
# Implementation depends on ArcGIS version
|
|
arcpy.AddMessage("RGI heatmap created")
|
|
|
|
except Exception as e:
|
|
arcpy.AddError(f"Error: {str(e)}")
|
|
|
|
|
|
class LoadUMITool(object):
|
|
"""Load UMI layer"""
|
|
|
|
def __init__(self):
|
|
self.label = "Load UMI"
|
|
self.description = "Load Urban Morphology Index"
|
|
self.canRunInBackground = True
|
|
|
|
def getParameterInfo(self):
|
|
params = []
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API URL",
|
|
name="api_url",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
param.value = "https://api.landvex.com/v1"
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API Key",
|
|
name="api_key",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="Output Feature Class",
|
|
name="output_fc",
|
|
datatype="DEFeatureClass",
|
|
parameterType="Required",
|
|
direction="Output"
|
|
)
|
|
params.append(param)
|
|
|
|
return params
|
|
|
|
def execute(self, parameters, messages):
|
|
api_url = parameters[0].valueAsText
|
|
api_key = parameters[1].valueAsText
|
|
output_fc = parameters[2].valueAsText
|
|
|
|
try:
|
|
arcpy.AddMessage("Fetching UMI data...")
|
|
|
|
response = requests.get(
|
|
f"{api_url}/indexes/umi",
|
|
headers={"Authorization": f"Bearer {api_key}"}
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
arcpy.AddMessage("UMI layer created")
|
|
|
|
except Exception as e:
|
|
arcpy.AddError(f"Error: {str(e)}")
|
|
|
|
|
|
class ExportToLandvexTool(object):
|
|
"""Export local data to Landvex"""
|
|
|
|
def __init__(self):
|
|
self.label = "Export to Landvex"
|
|
self.description = "Export ArcGIS data to Landvex platform"
|
|
self.canRunInBackground = True
|
|
|
|
def getParameterInfo(self):
|
|
params = []
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="Input Feature Class",
|
|
name="input_fc",
|
|
datatype="DEFeatureClass",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API URL",
|
|
name="api_url",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
param.value = "https://api.landvex.com/v1"
|
|
params.append(param)
|
|
|
|
param = arcpy.Parameter(
|
|
displayName="API Key",
|
|
name="api_key",
|
|
datatype="GPString",
|
|
parameterType="Required",
|
|
direction="Input"
|
|
)
|
|
params.append(param)
|
|
|
|
return params
|
|
|
|
def execute(self, parameters, messages):
|
|
input_fc = parameters[0].valueAsText
|
|
api_url = parameters[1].valueAsText
|
|
api_key = parameters[2].valueAsText
|
|
|
|
try:
|
|
arcpy.AddMessage("Reading features...")
|
|
|
|
features = []
|
|
with arcpy.da.SearchCursor(input_fc, ["SHAPE@XY", "*"]) as cursor:
|
|
for row in cursor:
|
|
features.append({
|
|
"lat": row[0][1],
|
|
"lng": row[0][0],
|
|
# Add other attributes
|
|
})
|
|
|
|
arcpy.AddMessage(f"Exporting {len(features)} features...")
|
|
|
|
response = requests.post(
|
|
f"{api_url}/observations/bulk",
|
|
headers={"Authorization": f"Bearer {api_key}"},
|
|
json={"observations": features}
|
|
)
|
|
response.raise_for_status()
|
|
|
|
arcpy.AddMessage("Export complete")
|
|
|
|
except Exception as e:
|
|
arcpy.AddError(f"Error: {str(e)}")
|