AutoCAD Hatch Boundary by Layer

So… it’s been one of those days…

All I want is to grab the hatch in a dwg, grab it’s outline and extrude them.

Seems simple…?! Hmmm…

I’ve been trawling the awesome LinkDwg package @Koz_Jono_Yeoh (I know biMorph also has some excellent work here @Thomas_Mahon ).

I can get the hatches, but they are not associated so the GetLoopAt method for comObjects fails.

So I need to stay within AutoCAD and use something like “-HatchEdit” or “HATCHGENERATEBOUNDARY” unfortunately this means using LISP (woop another coding language) and they all get dumped on the active layer, so I don’t know whether it’s to be extruded the height of a building or the height of a kerb.

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/recreate-multiple-hatch-boundaries-as-polygons-each-in-the-layer/td-p/3275725

This would be fine if I had the same number of objects as boundaries, unfortunately that doesn’t happen… So I need to iterate through each object, grab it’s layer and get any boundaries and dump that in it’s own list.

Unfortunately I haven’t been able to loop inside AutoCAD, I can only get all the hatches and extract all of them with PickfirstSelectionSet. I need to pick each hatch in turn, but I can’t think of a workflow for that :frowning:

Any assistance greatly appreciated!

Thanks,

Mark

CAD Hatch dwg outlines.dyn (16.0 KB)

#LinkDWG Core DYF by Koz Jono YEOH
#kozmosovia@hotmail.com
#Copyright(C) 1994-2018 KozMos Inc.
#Copyright(C) 2011-2018 Neila Heaven Networks
#Cioyright(c) 2017-2018 Tachyon Intelligent Design Institute

import clr
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

def _GetOrCreateAutoCAD(progid):
    try:
        from System.Runtime.InteropServices import Marshal
        return Marshal.GetActiveObject(progid)
    except:
        try:
            from System import Type, Activator
            t = Type.GetTypeFromProgID(progid)
            return Activator.CreateInstance(t)
        except: pass

def _ValidFile(filename):
    try:
        with open(filename) as f:
            return True
    except IOError:
        return False

UIDOC = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
DWG = UnwrapElement(IN[0])
VIS = IN[1]
RTN = [None]

if DWG != None:
	try:
		LNK=UIDOC.Document.GetElement(DWG.GetTypeId())
		PATH=ModelPathUtils.ConvertModelPathToUserVisiblePath(LNK.GetExternalFileReference().GetAbsolutePath())
		if _ValidFile(PATH):
			try:
				CAD=_GetOrCreateAutoCAD("Autocad.Application")
				CAD.Visible=VIS
				DOC=CAD.Documents.Open(PATH)
				DOC.SendCommand("(SSGET\"_x\"'((-4 . \"<OR\")(0 . \"*TEXT,*HATCH\")(-4 . \"<AND\")(0 . \"INSERT\")(66 . 1)(-4 . \"AND>\")(-4 . \"OR>\"))) ")
				DOC.SendCommand("SELECT (SSGET\"_p\")  ")
				DOC.SendCommand("HATCHGENERATEBOUNDARY ")
				SEL=DOC.PickfirstSelectionSet
				RRR=[]
				for obj in SEL:
					if obj.ObjectName == "AcDbHatch":
						RRR.append([obj, obj.Layer])
				RTN=RRR #doc
			except: pass
	except: pass

OUT  = RTN

Got a dwg you can share? Is using Civil3D 2020 (and the included Dynamo integration) an option?

Hey Jacob,

Sure…

test.rvt (1.3 MB) CAD Hatch dwg outlines.dyn (19.8 KB) test.dwg (41.8 KB)

If we can get something working somehow that would be an improvement!

More links I’m looking at:

https://through-the-interface.typepad.com/through_the_interface/2006/08/calling_command.html @keanw R10?! seriously?! :smiley:

So I got there eventually, the code is butt ugly, it would be great if anyone could help tidy it…

Cheers,

Mark

#LinkDWG Core DYF by Koz Jono YEOH
#kozmosovia@hotmail.com
#Copyright(C) 1994-2018 KozMos Inc.
#Copyright(C) 2011-2018 Neila Heaven Networks
#Cioyright(c) 2017-2018 Tachyon Intelligent Design Institute

import clr
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

def _GetOrCreateAutoCAD(progid):
    try:
        from System.Runtime.InteropServices import Marshal
        return Marshal.GetActiveObject(progid)
    except:
        try:
            from System import Type, Activator
            t = Type.GetTypeFromProgID(progid)
            return Activator.CreateInstance(t)
        except: pass

def _ValidFile(filename):
    try:
        with open(filename) as f:
            return True
    except IOError:
        return False

UIDOC = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
DWG = UnwrapElement(IN[0])
VIS = IN[1]
RTN = []

if DWG != None:
	LNK=UIDOC.Document.GetElement(DWG.GetTypeId())
	PATH=ModelPathUtils.ConvertModelPathToUserVisiblePath(LNK.GetExternalFileReference().GetAbsolutePath())
	if _ValidFile(PATH):
		RRR = []
		CAD=_GetOrCreateAutoCAD("Autocad.Application")
		CAD.Visible=VIS
		DOC=CAD.Documents.Open(PATH)

		#if i could get select previous to work after I've exploded and joined the regions I wouldn't need any of this next part
		
		#we will eventually make polylines from the regions, so we don't want any in there right now
		#to ensure we can delete polylines, we need at least one in the file... should use an if not but this seems faster not knowing the language!		
		DOC.SendCommand("_pline 0 0,1  ")	
		#lisp! select POLYLINES
		DOC.SendCommand("(ssget \"_X\" \'((0 . \"*POLYLINE\"))) ")	
		
		#delete any polylines in the file, because I can't find a way of selecting them after the join command... not ideal		
		#this selects the section set (SSGET) we just made
		DOC.SendCommand("SELECT (SSGET\"_p\")  ")		
		DOC.SendCommand("DELETE ")


		#lisp! select hatch and create search set
		DOC.SendCommand("(SSGET\"_x\"'((-4 . \"<OR\")(0 . \"HATCH\")(-4 . \"<AND\")(0 . \"INSERT\")(66 . 1)(-4 . \"AND>\")(-4 . \"OR>\"))) ")
		#this selects the section set (SSGET) we just made
		DOC.SendCommand("SELECT (SSGET\"_p\")  ")
		
		#make the outlines of the hatch
		#in python \" means python will not include the \, but it will include the ", without thinking that it's the termination of the quote.
		#find replace is handy for converting from lisp to the version in python!
		#\"p\" tells it to be a polyline
		DOC.SendCommand("(setq SSET (ssget))(setq CNT -1)(while (setq OBJ (ssname SSET (setq CNT (1+ CNT))))(setvar 'clayer (cdr (assoc 8 (entget OBJ))))(command \"-hatchedit\" OBJ \"b\" \"p\" \"y\"))(setvar \"cmdecho\" OLDCE) ")


		#select all polylines, which are now the new polylines.
		DOC.SendCommand("(ssget \"_X\" \'((0 . \"*POLYLINE\"))) ")	
		#this is a new section set (SSGET) we just made
		DOC.SendCommand("SELECT (SSGET\"_p\")  ")	
		
		#this gets the active selection		
		SEL=DOC.PickfirstSelectionSet
		for regionLine in SEL:
			RRR.append([regionLine.Layer, regionLine])
		RTN.append(RRR)	

OUT = RTN
5 Likes

This script sadly doesn’t work anymore in C3D 2022 because Dynamo stepped away from Iron Python. Is there still a way to make this script work?

You can still use IronPython via package. If installed you can change the PythonScript node engine version.
image
image

3 Likes

Bro, how can i use this code with CAD 2024 Environment,
because it seems that the function:
def _GetOrCreateAutoCAD(progid)
does not work with cad 2024

thanks in adnvance