# -*- coding: utf-8 -*- """Convert a survey DWG into GIS feature classes and inventory its layers. Run with ArcGIS Desktop's Python 2.7 (arcpy): C:\\Python27\\ArcGIS10.8\\python.exe tools/city-massing/convert-dwg-to-gis.py ArcGIS splits a CAD drawing into Polyline / Polygon / Point / Annotation feature classes and records the original CAD layer in a `Layer` field. Nothing is filtered here: the script reports what the drawing actually contains, so a building layer can be chosen from evidence. """ import sys import os import io import json import arcpy def main(): if len(sys.argv) < 3: print('usage: convert-dwg-to-gis.py [referenceScale]') return 2 dwg = os.path.abspath(sys.argv[1]) gdb = os.path.abspath(sys.argv[2]) # ArcGIS requires a reference scale; survey drawings here are 1:500 topographic sheets. reference_scale = sys.argv[3] if len(sys.argv) > 3 else '500' if not os.path.exists(dwg): print('missing input: %s' % dwg) return 2 work = os.path.dirname(gdb) if not os.path.isdir(work): os.makedirs(work) inventory_only = '--inventory-only' in sys.argv if inventory_only: if not arcpy.Exists(gdb): print('missing geodatabase: %s' % gdb) return 2 else: if arcpy.Exists(gdb): arcpy.Delete_management(gdb) arcpy.CreateFileGDB_management(work, os.path.basename(gdb)) print('converting %s -> %s (reference scale 1:%s)' % (dwg, gdb, reference_scale)) arcpy.CADToGeodatabase_conversion(dwg, gdb, 'cad', reference_scale, '') arcpy.env.workspace = gdb # CADToGeodatabase puts the feature classes inside a feature dataset, so walk both levels. targets = [] for dataset in arcpy.ListDatasets() or []: for name in arcpy.ListFeatureClasses(feature_dataset=dataset) or []: targets.append((dataset, name)) for name in arcpy.ListFeatureClasses() or []: targets.append((None, name)) report = {'input': dwg, 'gdb': gdb, 'featureClasses': []} for dataset, name in targets: entry = {'name': name, 'dataset': dataset, 'featureType': arcpy.Describe(name).shapeType, 'featureCount': 0, 'layers': {}} fields = [f.name for f in arcpy.ListFields(name)] entry['fields'] = fields hasLayer = 'Layer' in fields with arcpy.da.SearchCursor(name, ['Layer'] if hasLayer else ['OID@']) as cursor: for row in cursor: entry['featureCount'] += 1 if hasLayer: key = row[0] if row[0] is not None else u'(none)' entry['layers'][key] = entry['layers'].get(key, 0) + 1 report['featureClasses'].append(entry) print('%-10s %-28s %-9s %6d features, %d layers' % ( dataset or '-', name, entry['featureType'], entry['featureCount'], len(entry['layers']))) for layer, count in sorted(entry['layers'].items(), key=lambda kv: -kv[1])[:40]: line = u' %6d %s' % (count, layer) print(line.encode('utf-8')) out = os.path.join(work, os.path.basename(gdb) + '-inventory.json') with io.open(out, 'w', encoding='utf-8') as handle: handle.write(unicode(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True))) print('inventory: %s' % out) return 0 if __name__ == '__main__': sys.exit(main())