convert-dwg-to-gis.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. # -*- coding: utf-8 -*-
  2. """Convert a survey DWG into GIS feature classes and inventory its layers.
  3. Run with ArcGIS Desktop's Python 2.7 (arcpy):
  4. C:\\Python27\\ArcGIS10.8\\python.exe tools/city-massing/convert-dwg-to-gis.py <input.dwg> <out.gdb>
  5. ArcGIS splits a CAD drawing into Polyline / Polygon / Point / Annotation feature classes and
  6. records the original CAD layer in a `Layer` field. Nothing is filtered here: the script reports
  7. what the drawing actually contains, so a building layer can be chosen from evidence.
  8. """
  9. import sys
  10. import os
  11. import io
  12. import json
  13. import arcpy
  14. def main():
  15. if len(sys.argv) < 3:
  16. print('usage: convert-dwg-to-gis.py <input.dwg> <out.gdb> [referenceScale]')
  17. return 2
  18. dwg = os.path.abspath(sys.argv[1])
  19. gdb = os.path.abspath(sys.argv[2])
  20. # ArcGIS requires a reference scale; survey drawings here are 1:500 topographic sheets.
  21. reference_scale = sys.argv[3] if len(sys.argv) > 3 else '500'
  22. if not os.path.exists(dwg):
  23. print('missing input: %s' % dwg)
  24. return 2
  25. work = os.path.dirname(gdb)
  26. if not os.path.isdir(work):
  27. os.makedirs(work)
  28. inventory_only = '--inventory-only' in sys.argv
  29. if inventory_only:
  30. if not arcpy.Exists(gdb):
  31. print('missing geodatabase: %s' % gdb)
  32. return 2
  33. else:
  34. if arcpy.Exists(gdb):
  35. arcpy.Delete_management(gdb)
  36. arcpy.CreateFileGDB_management(work, os.path.basename(gdb))
  37. print('converting %s -> %s (reference scale 1:%s)' % (dwg, gdb, reference_scale))
  38. arcpy.CADToGeodatabase_conversion(dwg, gdb, 'cad', reference_scale, '')
  39. arcpy.env.workspace = gdb
  40. # CADToGeodatabase puts the feature classes inside a feature dataset, so walk both levels.
  41. targets = []
  42. for dataset in arcpy.ListDatasets() or []:
  43. for name in arcpy.ListFeatureClasses(feature_dataset=dataset) or []:
  44. targets.append((dataset, name))
  45. for name in arcpy.ListFeatureClasses() or []:
  46. targets.append((None, name))
  47. report = {'input': dwg, 'gdb': gdb, 'featureClasses': []}
  48. for dataset, name in targets:
  49. entry = {'name': name, 'dataset': dataset, 'featureType': arcpy.Describe(name).shapeType, 'featureCount': 0, 'layers': {}}
  50. fields = [f.name for f in arcpy.ListFields(name)]
  51. entry['fields'] = fields
  52. hasLayer = 'Layer' in fields
  53. with arcpy.da.SearchCursor(name, ['Layer'] if hasLayer else ['OID@']) as cursor:
  54. for row in cursor:
  55. entry['featureCount'] += 1
  56. if hasLayer:
  57. key = row[0] if row[0] is not None else u'(none)'
  58. entry['layers'][key] = entry['layers'].get(key, 0) + 1
  59. report['featureClasses'].append(entry)
  60. print('%-10s %-28s %-9s %6d features, %d layers' % (
  61. dataset or '-', name, entry['featureType'], entry['featureCount'], len(entry['layers'])))
  62. for layer, count in sorted(entry['layers'].items(), key=lambda kv: -kv[1])[:40]:
  63. line = u' %6d %s' % (count, layer)
  64. print(line.encode('utf-8'))
  65. out = os.path.join(work, os.path.basename(gdb) + '-inventory.json')
  66. with io.open(out, 'w', encoding='utf-8') as handle:
  67. handle.write(unicode(json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True)))
  68. print('inventory: %s' % out)
  69. return 0
  70. if __name__ == '__main__':
  71. sys.exit(main())