p7q Posted 7 hours ago Posted 7 hours ago Hi everyone, I'm working with a large AutoLISP routine that sets the Z elevation of all objects to 0 — similar to a custom Z0 command. It handles a wide range of entity types including: LINEs, ARCs, CIRCLEs, POLYLINEs (both 2D and 3D), LWPOLYLINEs, SPLINEs, HATCHes, TEXT, MTEXT, DIMENSIONs, INSERTs (blocks), including nested block content, and REGION entities. What it does: For each entity, I check its Z elevation and flatten it: For regular entities, I modify their coordinate group codes (10, 11, etc.) using entmod, or use vla-put-elevation where applicable. For INSERTs, I dive into their nested entities and apply the same logic. For REGIONs, I currently copy and explode them temporarily, analyze the resulting geometry to determine the average Z, then move the original REGION to Z=0. My problem: The command works fine, but performance is a major issue, especially on complex or large drawings. What are the best ways to optimize performance for a routine like this? Is there a better way to flatten REGIONs without exploding them? Specifically, is there a way (maybe via a filter or a helper LISP) to select only entities whose Z coordinate is not zero? That would allow me to skip processing objects that are already flat and significantly improve performance. Thanks a lot in advance for any suggestions! Quote
Steven P Posted 6 hours ago Posted 6 hours ago Here is a quick example, (ssget (list '(-4 . "<OR") '(-4 . "*,*,<>") (list 10 0.0 0.0 0.0) '(-4 . "*,*,<>") (list 11 0.0 0.0 0.0) '(-4 . "OR>") )) Should select the more simple entities not at 0 elevation - not sure it will work for 3d polylines for example, but should be OK for lines, circles, arcs and so on and apply similar to others? Quote
Steven P Posted 6 hours ago Posted 6 hours ago I guess the flatten command has some limitations for you (I've never been 100% with trusting flatten) Quote
p7q Posted 5 hours ago Author Posted 5 hours ago 5 minutes ago, Steven P said: I guess the flatten command has some limitations for you (I've never been 100% with trusting flatten) yes flatten is not working sometimes block, pline, dimension. So ı need this lisp. 8 minutes ago, Steven P said: Here is a quick example, (ssget (list '(-4 . "<OR") '(-4 . "*,*,<>") (list 10 0.0 0.0 0.0) '(-4 . "*,*,<>") (list 11 0.0 0.0 0.0) '(-4 . "OR>") )) Should select the more simple entities not at 0 elevation - not sure it will work for 3d polylines for example, but should be OK for lines, circles, arcs and so on and apply similar to others? this lips so limited. for exaple there are multiple 10 dxf data in POLYLINE. I need something more comprehensive Quote
mhupp Posted 4 hours ago Posted 4 hours ago Can't really tell you how to optimize code you didn't post, but when people first get into lisp the rely heavily on command because its follows what you would type into the command line. It become apparent in a loop processing 1000's of entity's that its quite inefficient. rather then using entmod or some other way to update model. If flatten doesn' work also try the command Change > elevation > 0 1 1 Quote
Steven P Posted 4 hours ago Posted 4 hours ago 1 hour ago, p7q said: this lips so limited. for exaple there are multiple 10 dxf data in POLYLINE. I need something more comprehensive That would get most of the simpler entities such as lines, text, circles and so on. LWPolylines you can add another "or": '(-4 . "<>") (cons 38 0.0) and so on building up the selection set filter that way: (ssget (list '(-4 . "<OR") '(-4 . "*,*,<>") (list 10 0.0 0.0 0.0) '(-4 . "*,*,<>") (list 11 0.0 0.0 0.0) '(-4 . "<>") (cons 38 0) '(-4 . "OR>") )) For 3d polylines, for example, so long as the first point (first dxf code 10 in the entity description) isn't at zero elevation it should also grab them too. However if this only removes lines, LWPolylines, circles, arcs, texts, ellipses... it should reduce the amount of processing. Depends how you are doing it but the blocks might be your slow point. Quote
p7q Posted 3 hours ago Author Posted 3 hours ago 45 minutes ago, mhupp said: Can't really tell you how to optimize code you didn't post, but when people first get into lisp the rely heavily on command because its follows what you would type into the command line. It become apparent in a loop processing 1000's of entity's that its quite inefficient. rather then using entmod or some other way to update model. If flatten doesn' work also try the command Change > elevation > 0 I trid Change > elevation > 0 but not working. I can't share the full code, but for REGION entities, I'm currently using a method that copies and explodes them to get the Z values, then moves the original REGION to Z=0. I know it's not efficient, but it works. ((equal entType "REGION") (vl-catch-all-apply (function (lambda () (setq zList '()) (setq before (ssget "_X")) (command "regen") (command "_.copy") (command obj) (command "") (command '(0 0 0) '(0 0 0)) (setq newent (entlast)) (command "_.explode" newent) (setq after (ssget "_X")) (setq newents '()) (setq j 0) (while (< j (sslength after)) (setq ent (ssname after j)) (if (not (ssmemb ent before)) (setq newents (cons ent newents)) ) (setq j (1+ j)) ) (foreach e newents (setq entdata (entget e)) (cond ((= (cdr (assoc 0 entdata)) "LINE") (setq z1 (nth 2 (cdr (assoc 10 entdata)))) (setq z2 (nth 2 (cdr (assoc 11 entdata)))) (setq zList (cons z1 zList)) (setq zList (cons z2 zList)) ) ((member (cdr (assoc 0 entdata)) '("ARC" "CIRCLE" "ELLIPSE") ) (setq z1 (nth 2 (cdr (assoc 10 entdata)))) (setq zList (cons z1 zList)) ) ) ) (setq ztotal 0) (if (< 0 (length zList)) (progn (foreach z zList (setq ztotal (+ ztotal z))) (setq zmid (/ ztotal (length zList))) (command "_.MOVE" obj "" '(0 0 0) (list 0.0 0.0 (* zmid -1)) ) ) ) (foreach e newents (entdel e)) ) ) ) ) And also is there a way to use ssget to select only entities that have non-zero Z values? Quote
Steven P Posted 3 hours ago Posted 3 hours ago (edited) Depends what you are using for obj, if it is an entity name this is a bit quicker: (command "_.copy") (command obj) (command "") (command '(0 0 0) '(0 0 0)) (setq newent (entlast)) (command "_.explode" newent) becomes (command "_.Explode" (setq NewEnt (entmakex (entget obj)) ) ) where obj might be from (car (entsel)) or (ssname MySS number) Might want to look at the number of loops in the snippet you posted Edited 3 hours ago by Steven P 1 Quote
Steven P Posted 2 hours ago Posted 2 hours ago (edited) Just to amuse myself, here is a snippet that will flatten simple entities, not sure if that helps you along the way - you can use what code works for 3d polylines, hatches, regions and blocks - might be a bit quicker Command: NewFlatten (defun FlattenLines ( / MySS MyEnt acount ed) ;;Does lines, circles, arcs, ellipses, texts, LWPolylines (setq MySS (ssget "_X" (list '(-4 . "<OR") '(-4 . "*,*,<>") (list 10 0.0 0.0 0.0) '(-4 . "*,*,<>") (list 11 0.0 0.0 0.0) '(-4 . "<>") (cons 38 0) '(-4 . "OR>") ))) ; end list, ssget, setq (setq acount 0) (while (< acount (sslength MySS)) (setq MyEnt (ssname MySS acount)) (setq ed (entget MyEnt)) (if (equal (assoc 0 ed) (cons 0 "LWPOLYLINE")) (progn (entmod (setq ed (subst (cons 38 0) (assoc 38 ed) ed) )) ;; Elevation to 0 ) ; end progn (progn (entmod (setq ed (subst (cons 10 (mapcar '* '(1 1 0) (cdr (assoc 10 ed)))) (assoc 10 ed) ed)) ) (entmod (setq ed (subst (cons 11 (mapcar '* '(1 1 0) (cdr (assoc 11 ed)))) (assoc 11 ed) ed)) ) ) ; end progn ) ; end if (setq acount (+ acount 1)) ) ; end while ) (defun c:NewFlatten ( / ) (FlattenLines) ;; flatten simple entities ) ; end defun Edited 1 hour ago by Steven P 1 Quote
mhupp Posted 1 hour ago Posted 1 hour ago (edited) Change elevation only works if all points are on the same Z elevation. this might be why also flatten isn't working for you. Two things you can do to speed up. Combine all the commands into one call like you did below Command has some type of "lag" but for example lets just call it 100ms this would remove 500ms for each loop. Not to mention all the command line spam. (setvar cmdecho 0) when you sent LastEnt anything created or modified is "behind" LastEnt in the drawing and can be added to a selection set with a simple loop. rather then selecting everything in the drawing and checking against the before selection set to find the new items. (setq zList '()) ;(setq before (ssget "_X")) ;not needed anymore (command "regen" "_.copy" obj "" '(0 0 0) '(0 0 0)) (setq LastEnt (entlast)) ;set right before you create/modify objects. you want to either add to a selection (command "_.explode" newent) (while (setq LastEnt (entnext LastEnt)) ;after entities are created this will add them to a selection set. (ssadd EntLst newents) ) (foreach e newents Edited 1 hour ago by mhupp 1 Quote
Steven P Posted 1 hour ago Posted 1 hour ago Thanks MHUPP - that was a thought I'd add for the OP tomorrow, can copy and paste from here rather than try to remember where I last used last ent. 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.