Select to view content in your preferred language

Multipatch Union3D

315
2
2 weeks ago
KiroAndreevGDI
Emerging Contributor
import arcpy
import os
from collections import defaultdict
from arcpy import AddFieldDelimiters, Describe
import time

start = time.time()
# === Setup ===
gdb_path = r"C:\Users\Administrator\Desktop\Downloaded\QC02002-ESA-MOD-BIM-ARC-06-V06-00001 (1).gdb"
arcpy.env.workspace = gdb_path
arcpy.env.overwriteOutput = True

columns = os.path.join(gdb_path, "Spaces_BIMFileToGeodatab")
footprint_fc = "Columns_Footprint"
footprint_path = os.path.join(gdb_path, footprint_fc)
count_over = os.path.join(gdb_path, "count_over")
count_over_tab = os.path.join(gdb_path, "columns_tab")
singlePart = os.path.join(gdb_path, "singlePart")
arcpy.management.MultipartToSinglepart(columns, singlePart)
# === Geometry repair and footprint ===
arcpy.management.RepairGeometry(singlePart)
arcpy.ddd.MultiPatchFootprint(singlePart, footprint_path)
arcpy.analysis.CountOverlappingFeatures(footprint_path, count_over, "", count_over_tab)

# === Prepare ===
union_all = []
union_one = []

if arcpy.Exists(count_over_tab):
fields = [f.name for f in arcpy.ListFields(count_over_tab) if f.type != "OID"]
if len(fields) < 2:
print("‌‌ Table does not have at least two fields.")
else:
key_field = fields[0]
value_field = fields[1]
print(f"Using: key = {key_field}, value = {value_field}")

result_dict = defaultdict(list)
with arcpy.da.SearchCursor(count_over_tab, [key_field, value_field]) as cursor:
for key, value in cursor:
result_dict[key].append(value)

# === Get OID field and prepare layer ===
oid_field = Describe(singlePart).OIDFieldName
field_name = AddFieldDelimiters(singlePart, oid_field)
arcpy.MakeFeatureLayer_management(singlePart, "columns_layer")

# === Export all single-feature groups at once ===
single_oids = [str(oid_list[0]) for oid_list in result_dict.values() if len(oid_list) == 1]
if single_oids:
where_clause = f"{field_name} IN ({','.join(single_oids)})"
single_fc = os.path.join(gdb_path, "single_all")
arcpy.conversion.FeatureClassToFeatureClass(
in_features=singlePart,
out_path=gdb_path,
out_name="single_all",
where_clause=where_clause
)
print(f"‌‌ Exported {len(single_oids)} single-feature groups.")
union_one.append(single_fc)

# === Process multi-feature groups using selections ===
for group_id, oid_list in result_dict.items():
if len(oid_list) > 1:
oid_values = ", ".join(str(oid) for oid in oid_list)
where_clause = f"{field_name} IN ({oid_values})"
arcpy.SelectLayerByAttribute_management("columns_layer", "NEW_SELECTION", where_clause)

group_fc = os.path.join(gdb_path, f"group_{group_id}")
arcpy.CopyFeatures_management("columns_layer", group_fc)
count_group = int(arcpy.management.GetCount(group_fc)[0])
print(f"‌‌ Exported group {group_id} with {count_group} features.")

if count_group < 2:
print(f"‌‌ Skipping group {group_id} — not enough features.")
continue

enclosed_fc = os.path.join(gdb_path, f"enclosed_{group_id}")
try:
arcpy.ddd.EncloseMultiPatch(group_fc, enclosed_fc)
print(f"‌‌ Enclosed: {enclosed_fc}")
except Exception as e:
print(f"‌‌ Enclose failed for group {group_id}: {e}")
continue

union_fc = os.path.join(gdb_path, f"union_{group_id}")
try:
arcpy.ddd.Union3D(enclosed_fc, union_fc, '', 'DISABLE', 'ENABLE')
print(f"‌‌ Union3D completed: {union_fc}")
count = int(arcpy.management.GetCount(union_fc)[0])
print(f"‌‌ Union result contains {count} feature(s)")
if count > 0:
union_all.append(union_fc)
except Exception as e:
print(f"‌‌ Union3D failed for group {group_id}: {e}")

try:
# === Final Union: union_all + union_one ===
union_full = []

# Union All
if union_all:
merge_all = os.path.join(gdb_path, "merge_all")
enclosed_all = os.path.join(gdb_path, "enclosed_all")
union_all_fc = os.path.join(gdb_path, "union_all")
arcpy.management.Merge(union_all, merge_all)
arcpy.ddd.EncloseMultiPatch(merge_all, enclosed_all)
arcpy.ddd.Union3D(enclosed_all, union_all_fc, '', 'DISABLE', 'ENABLE')
union_full.append(union_all_fc)
count_all = int(arcpy.management.GetCount(union_all_fc)[0])
print(f"‌‌ Union ALL result contains {count_all} feature(s)")

# Union One
if union_one:
merge_one = os.path.join(gdb_path, "merge_one")
enclosed_one = os.path.join(gdb_path, "enclosed_one")
union_one_fc = os.path.join(gdb_path, "union_one")
arcpy.management.Merge(union_one, merge_one)
arcpy.ddd.EncloseMultiPatch(merge_one, enclosed_one)
arcpy.ddd.Union3D(enclosed_one, union_one_fc, '', 'DISABLE', 'ENABLE')
union_full.append(union_one_fc)
count_one = int(arcpy.management.GetCount(union_one_fc)[0])
print(f"‌‌ Union ONE result contains {count_one} feature(s)")

# Final Full Union
if union_full:
merge_full = os.path.join(gdb_path, "merge_full")
enclosed_full = os.path.join(gdb_path, "enclosed_full")
union_full_fc = os.path.join(gdb_path, "union_full")
arcpy.management.Merge(union_full, merge_full)
arcpy.ddd.EncloseMultiPatch(merge_full, enclosed_full)
arcpy.ddd.Union3D(enclosed_full, union_full_fc, '', 'DISABLE', 'ENABLE')
count_full = int(arcpy.management.GetCount(union_full_fc)[0])
print(f"‌‌ FINAL Union FULL result contains {count_full} feature(s)")

except Exception as e:
print(f"‌‌ Final Union3D process failed: {e}")
# Elapsed time in minutes
elapsed_minutes = (end - start) / 60
print("Elapsed time:", round(elapsed_minutes, 2), "minutes")

Hello,

i would like to create union from feature class which have more of 2000 features.My iterations is:

  1. create feature class from gdb
  2. create MultipartToSinglepart
  3. RepairGeometry of  single part
  4. create MultiPatchFootprint
  5. CountOverlappingFeatures
  6. create Enclosed
  7. create union of two, tree... pair multipatch which is overloading(first encode)
  8. merge single feature class
  9. create encode of merget sigle feature class
  10. create union of encode

Apear error:

warning stating that the resulting feature is not simple

How to solved problem?

 



      

0 Kudos
2 Replies
DanPatterson
MVP Esteemed Contributor

to make the code readable

Code formatting ... the Community Version - Esri Community


... sort of retired...
DanPatterson
MVP Esteemed Contributor

Union 3D (3D Analyst)—ArcGIS Pro | Documentation

A warning stating that the resulting feature is not simple and could not be created is raised if two or more multipatch features share only an edge or a vertex. This message indicates that the features were not merged because they did not share a volume of space.

DISABLE  output all may be needed if features aren't overlapping.

Before you try scripting, have you tried the process manually to see at which step it is failing?

( PS  code formatting is still missing indentation, so sometimes, it is best to apply the code formatting to a new copy of the code)


... sort of retired...
0 Kudos