I’m working on a Dynamo Python script for Civil3D, where I want to add inner loops (holes) to an existing Hatch object using closed polylines or circles.
import clr
clr.AddReference('AcMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AcCoreMgd')
from Autodesk.AutoCAD.ApplicationServices import Application
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
from Autodesk.AutoCAD.DatabaseServices import HatchLoopTypes
from System.Collections.Generic import List
# IN[0] = Existing Hatch
# IN[1] = List of closed polylines (includes outer boundary and inner holes)
hatch_input = IN[0]
poly_inputs = IN[1]
print("Python Script: Input received")
def flatten(x):
if isinstance(x, list):
return sum([flatten(i) for i in x], [])
else:
return [x]
def get_object_id(obj):
try:
return obj.InternalObjectId
except:
try:
return obj.ObjectId
except:
return None
flat_polys = flatten(poly_inputs)
poly_ids = [get_object_id(p) for p in flat_polys if get_object_id(p) is not None]
doc = Application.DocumentManager.MdiActiveDocument
db = doc.Database
ed = doc.Editor
result = None
tr = db.TransactionManager.StartTransaction()
try:
print("Python Script: Transaction started")
hatch_id = get_object_id(hatch_input)
hatch = tr.GetObject(hatch_id, OpenMode.ForWrite)
print("Hatch object acquired")
# Remove all existing loops (from last to first)
for i in reversed(range(hatch.NumberOfLoops)):
hatch.RemoveLoopAt(i)
print("Existing loops removed")
db_objs = [tr.GetObject(pid, OpenMode.ForRead) for pid in poly_ids]
# Calculate areas for each object
areas = []
for obj in db_objs:
if hasattr(obj, "Area"):
areas.append(obj.Area)
else:
areas.append(0)
if not areas or max(areas) == 0:
raise Exception("No valid closed shapes with measurable area found.")
# Find index of the largest area object (assumed to be outer loop)
max_idx = areas.index(max(areas))
outer_id = poly_ids[max_idx]
# Add outer loop
loop_ext = ObjectIdCollection()
loop_ext.Add(outer_id)
hatch.AppendLoop(HatchLoopTypes.External, loop_ext)
# Add inner loops (all except the outer one)
for i, pid in enumerate(poly_ids):
if i == max_idx:
continue
loop = ObjectIdCollection()
loop.Add(pid)
hatch.AppendLoop(HatchLoopTypes.Default, loop)
# Evaluate hatch to apply changes
hatch.EvaluateHatch(True)
print("Hatch evaluation complete")
result = hatch
tr.Commit()
except Exception as e:
print("Exception occurred:", e)
ed.WriteMessage("\nError: {}\n".format(str(e)))
result = "Error: " + str(e)
tr.Abort()
finally:
tr.Dispose()
print("Transaction ended")
OUT = result
Result
I ran the following code to update an existing Hatch entity by removing its loops and re-adding a new outer boundary and inner boundaries (holes). The script executes without any errors, but the result is not what I expected.
Instead of showing a hatched area with holes, the hatch only fills the inner shapes, and the outer boundary seems to disappear.
Could you help me understand what I’m doing wrong?
How should I modify this script to correctly add inner loops (holes) to an existing Hatch?
Any insight or working example would be greatly appreciated.
Uploading: TEST_OBJHatch.dwg…
Uploading: hatch2.dyn…