Announcements

The Autodesk Community Forums has a new look. Read more about what's changed on the Community Announcements board.

AutoLISP to offset closed polyline, hatch, and delete the second polyline [C3D]

Anonymous

AutoLISP to offset closed polyline, hatch, and delete the second polyline [C3D]

Anonymous
Not applicable

Hi. In our firm, we often created partial hatches within buildings (represented by closed polylines). The process is as follows:
1. We select a closed polyline that was previously drawn and that represents the outline of a building.

2. We offset the polyline 2 units inside, creating a scaled version of the original polyline within the first. 

3. We hatch the area within the two polylines with a specific hatch pattern, scale, layer and color.

4. We delete the smaller, inside polyline, leaving the original building outline and the new hatch within.

I'm looking to automate this process in some way. I had some marginal success with the Action Recorder, but it wasn't consistent if the building outline was angled, and I had to always use the rightmost edge of the building. I'm sure AutoLISP can automate this sequence, but I'm a complete beginner.

Can anybody spoonfeed me a script that does what I'm looking for? Thanks a whole ton.

Reply
8,742 Views
106 Replies
Replies (106)

kmohs
Contributor
Contributor
Is it possible to define the polyline offset by a factor of dimscale?
And I suppose the hatch scale too?
(setq hsc (* 0.5 (getvar "DIMSCALE")))
0 Likes

john.uhden
Mentor
Mentor

@kmohs 

I don't know if I've posted this before, but it works even with open polylines (you pick the side).

It handles most all the required variables including viewtwist, except I don't see how I handled the scale (spacing).

But if it works for you, then fine.  About the only thing it doesn't do is set the desired layer./color.

(defun C:HatchBldg ( / *error* Doc vars vals ans od e ent etyp Obj1 p Obj2 start end coords)
  ;; From OffsetWithEnds by John Uhden, (06-04-18)
  ;; v1.0 (11-02-2020) revised for polylines only for LDC to speed up
  ;; creating existing building hatching.
  ;; v1.1 (01-25-21) improved to set hatch properties and try to set rotation better.
  ;; v1.2 (09-02-21) added control of offsetgaptype (0) for sharp corners

  (gc)
  (vl-load-com)
  (princ "\nHatchBldg v1.2 (c)2020-2021, John F. Uhden")(princ)
  (or *acad* (setq *acad* (vlax-get-acad-object)))
  (setq Doc     (vla-get-ActiveDocument *acad*))
  (setq vars '("cmdecho" "hpname" "hpscale" "hpseparate" "hpassoc" "hpdouble" "offsetgaptype"))
  (setq vals (mapcar 'getvar vars))
  (defun *error* (Error)
    (mapcar 'setvar vars vals)
    (if e (redraw e 4))
    (vla-endundomark Doc)
    (cond
      ((not Error))
      ((wcmatch (strcase Error) "*QUIT*,*CANCEL*")
        ;(vl-exit-with-error "\r                                              ")
      )
      (1
        (princ (strcat "\n*ERROR*: " Error))
        ;(vl-exit-with-error (strcat "\r*ERROR*: " Error))
      )
    )
    (princ)
  )
  (vla-endundomark Doc)
  (vla-startundomark Doc)
  (mapcar 'setvar vars '(0 "_USER" 1.0 1 0 0 0))
  (command "_.UCS" "_World")
  (setvar "hporigin" (reverse (cdr (reverse (getvar "viewctr")))))
  (command "_.EXPERT" (getvar "EXPERT")) ;; dummy command
  (defun @2d (p)(list (car p)(cadr p)))
  (and
    (setq od (getvar "offsetdist"))
    (not (initget 4))
    (if (setq ans (getdist (strcat "\nOffset distance <" (rtos od) ">: ")))
      (setvar "offsetdist" (setq od ans))
      1
    )
    (or (entmake) 1)
    (setvar "errno" 0)
    (while (/= (getvar "errno") 52)
      (if e (redraw e 4))
      (and
        (setq e (car (entsel "Select object to offset: ")))
        (setq Obj1 (vlax-ename->vla-object e))
        (setq ent (entget e))
        (setq etyp (cdr (assoc 0 ent)))
        (or
          (= etyp "LWPOLYLINE")
          (prompt (strcat "\nObject selected is a(n) " etyp "."))
        )
        (setq closed (vlax-get obj1 'closed))
        (or (redraw e 3) 1)
        (setq p (getpoint "\nSide to offset: "))
        (vl-cmdf "_.offset" od e p "")
        (setq obj2 (vlax-ename->vla-object (entlast)))
        (if (= closed 0)
          (progn
            (setq start (@2d (vlax-curve-getstartpoint Obj1)))
            (setq end (@2d (vlax-curve-getendpoint Obj1)))
            (setq coords (vlax-get Obj2 'Coordinates))
            (vlax-put Obj2 'Coordinates (append start coords end))
            1
          )
          1
        )
        (vl-cmdf "_.-hatch" "_S" (ssadd (vlax-vla-object->ename Obj1) (ssadd (vlax-vla-object->ename Obj2))) "" "")
        (or (/= (getvar "hpang") 0.0)(vlax-put (vlax-ename->vla-object (entlast)) 'PatternAngle (- (* pi 1.25)(getvar "Viewtwist"))) 1)
        (vla-delete Obj2)
      )
    )
  )
  (*error* nil)
)
(defun c:HB ()(c:HatchBldg))

 

John F. Uhden

0 Likes

kmohs
Contributor
Contributor

Thanks John!

I was able to set the scale and spacing based on dimscale, and I switched to ANSI31.
In regards to hpang, can that be set to be 45d from the line selected for the offset?

0 Likes

john.uhden
Mentor
Mentor

@kmohs 

That's a great idea.  You have to pick some part of the footprint anyway, and most buildings have 90° corners.

I'll attack it at work tomorrow or the next day.  I'm always having to adjust the angle in properties until it looks good enough.  It's time to make it better.

John F. Uhden

0 Likes

Sea-Haven
Mentor
Mentor

Open pline I use select left end and always offset to right of pline.

 

If closed pline can ignore second pick by checking CCW CW so using vla-offset with a + value will go in - out. So select near left end does not really matter.

 

 

0 Likes

john.uhden
Mentor
Mentor

@Sea-Haven wrote "... using vla-offset with a + value will go in - out"

That ain't necessarily so.  We've been through this so many times.

It's not in vs. out.  + is to the right and - is to the left.

Since we probably don't know which direction a polyline is drawn (CW vs. CCW), the solution is to pick the side, just like the real OFFSET command.

John F. Uhden

0 Likes

Kent1Cooper
Consultant
Consultant

@kmohs wrote:

.... I switched to ANSI31.

In regards to hpang, can that be set to be 45d from the line selected for the offset?


Is your intent to use ANSI31 [which already makes lines at 45° to the HPANG setting's direction] and set the angle to 45° so that the Hatch lines will be perpendicular to the selected edge?  Or do you want the Hatch lines at 45° relative to the selected edge?

 

I would forget about using ANSI31, and use the User-specified option.  That way, you can set the angle directly, rather than "correcting for" the native 45° angle of ANSI31's definition.  And you can set the line spacing directly, in drawing units, rather than calculate something based on what the spacing happens to be in ANSI31's definition [1/8" in the Imperial-variety definition, 3.175 units in ISO].

Kent Cooper, AIA
0 Likes

john.uhden
Mentor
Mentor

@Kent1Cooper 

He is absolutely smart to use ANSI31.  At a rotation of 0°, it is naturally at 45° to the X and Y axes.

But since our building footprints are at any bleeping angle, all he has to do is pick one side (which he has to do anyway) and I adjust the HPANG based on the 1stDeriv... perfect every time.

I've just been too busy with work work to get to fixing it.

I guess maybe I shouldn't worry about finishing the Final As-Built Survey just because the owner has already illegally moved into his $5M bayfront home. 😰

John F. Uhden

0 Likes

Kent1Cooper
Consultant
Consultant

@john.uhden wrote:

He is absolutely smart to use ANSI31.  At a rotation of 0°, it is naturally at 45° to the X and Y axes. ....


That's why I asked the question in reply to their:

  "In regards to hpang, can that be set to be 45d...?"

Setting HPANG to 45° will turn ANSI31's diagonals to orthogonal, or perpendicular to an edge if HPANG is set to 45° relative to that edge.  I suspect maybe that is not what they really want.

Kent Cooper, AIA
0 Likes

kmohs
Contributor
Contributor
You're correct in that the hatch should be _user, and set at 45° relative to the selected edge.
0 Likes

john.uhden
Mentor
Mentor

@Kent1Cooper 

You are correct.

All he knows (that's not fair) is that he wants the hatch to end up at 45° to the building.

Using ANSI31 makes it easier for me.  I will improve the code because there are benefits in it for me as well.

I'm just interrupted by this %$@#&*! work I have to get done.

John F. Uhden

0 Likes

Sea-Haven
Mentor
Mentor

An open pline pick left end then do a check is it left or right drawn, you need though to take into account say 4 plines representing a box, you need at times to pick the opposite end to imply a left end, you get used to it. Just something I have used for years. Think upside down.

0 Likes

john.uhden
Mentor
Mentor

Alan,

You have obviously been consuming too much Great Northern.  🤢

John F. Uhden

john.uhden
Mentor
Mentor

@kmohs 

I think you will find this more to your liking...

(defun C:HatchBldg ( / *error* Doc vars vals ans od e ent etyp Obj1 p Obj2 start end coords scale pick ang)
  ;; From OffsetWithEnds by John Uhden, (06-04-18)
  ;; v1.0 (11-02-2020) revised for polylines only for LDC to speed up
  ;; creating existing building hatching.
  ;; v1.1 (01-25-21) improved to set hatch properties and try to set rotation better.
  ;; v1.2 (09-02-21) added control of offsetgaptype (0) for sharp corners
  ;; v1.3 (06-02-22) changed to pattern ANSI31; adjusted HPANG by direction of building segment;
  ;;      set hatch scale according to CANNOSCALE.

  (gc)
  (vl-load-com)
  (princ "\nHatchBldg v1.3 (c)2020-2022, John F. Uhden")(princ)
  (or *acad* (setq *acad* (vlax-get-acad-object)))
  (setq Doc     (vla-get-ActiveDocument *acad*))
  (setq vars '("cmdecho" "hpname" "hpang" "hpscale" "hpseparate" "hpassoc" "hpdouble" "offsetgaptype"))
  (setq vals (mapcar 'getvar vars))
  (defun *error* (Error)
    (mapcar 'setvar vars vals)
    (if e (redraw e 4))
    (vla-endundomark Doc)
    (cond
      ((not Error))
      ((wcmatch (strcase Error) "*QUIT*,*CANCEL*")
        ;(vl-exit-with-error "\r                                              ")
      )
      (1
        (princ (strcat "\n*ERROR*: " Error))
        ;(vl-exit-with-error (strcat "\r*ERROR*: " Error))
      )
    )
    (princ)
  )
  (vla-endundomark Doc)
  (vla-startundomark Doc)
  (setq scale (/ 0.5 (getvar "cannoscalevalue")))
  (mapcar 'setvar vars (list 0 "ANSI31" 0.0 scale 1 0 0 0))
  (command "_.UCS" "_World")
  (setvar "hporigin" (reverse (cdr (reverse (getvar "viewctr")))))
  (command "_.EXPERT" (getvar "EXPERT")) ;; dummy command
  (defun @2d (p)(list (car p)(cadr p)))
  (and
    (setq od (getvar "offsetdist"))
    (not (initget 4))
    (if (setq ans (getdist (strcat "\nOffset distance <" (rtos od) ">: ")))
      (setvar "offsetdist" (setq od ans))
      1
    )
    (or (entmake) 1)
    (setvar "errno" 0)
    (while (/= (getvar "errno") 52)
      (if e (redraw e 4))
      (and
        (setq pick (entsel "Select object to offset: "))
        (setq e (car pick) p (cadr pick))
        (setq Obj1 (vlax-ename->vla-object e))
        (setq ent (entget e))
        (setq etyp (cdr (assoc 0 ent)))
        (or
          (= etyp "LWPOLYLINE")
          (prompt (strcat "\nObject selected is a(n) " etyp "."))
        )
        (setq p (vlax-curve-getclosestpointto Obj1 p))
        (setq ang (vlax-curve-getfirstderiv Obj1 (vlax-curve-getparamatpoint Obj1 p)))
        (setq ang (+ (* 0.5 pi) (angle '(0 0) ang)))
        (setq closed (vlax-get obj1 'closed))
        (or (redraw e 3) 1)
        (setq p (getpoint "\nSide to offset: "))
        (vl-cmdf "_.offset" od e p "")
        (setq obj2 (vlax-ename->vla-object (entlast)))
        (if (= closed 0)
          (progn
            (setq start (@2d (vlax-curve-getstartpoint Obj1)))
            (setq end (@2d (vlax-curve-getendpoint Obj1)))
            (setq coords (vlax-get Obj2 'Coordinates))
            (vlax-put Obj2 'Coordinates (append start coords end))
            1
          )
          1
        )
        (vl-cmdf "_.-hatch" "_S" (ssadd (vlax-vla-object->ename Obj1) (ssadd (vlax-vla-object->ename Obj2))) "" "")
        (or (vlax-put (vlax-ename->vla-object (entlast)) 'PatternAngle ang)) 1)
        (vla-delete Obj2)
      )
    )
  )
  (*error* nil)
)
(defun c:HB ()(c:HatchBldg))

John F. Uhden

0 Likes

Kent1Cooper
Consultant
Consultant

@kmohs wrote:
You're correct in that the hatch should be _user, and set at 45° relative to the selected edge.

Here's an adjustment of my earlier routine to do that.  The 0.75-unit line spacing seemed a reasonable one for a 2-unit perimeter Hatch-band width, but you can change that to suit.  Also note the need to give it the right Layer name.  Lightly tested.

(defun C:OI2H ; = Offset Inward by 2 drawing units, and Hatch
  (/ *error* doc ss ent obj oarea pickpt pl2)
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break"))
      (princ (strcat "\nError: " errmsg))
    ); if
    (vla-endundomark doc)
    (princ)
  ); defun - *error*
  (vla-startundomark (setq doc (vla-get-activedocument (vlax-get-acad-object))))
  (prompt "\nBuilding outline to Offset Inward and Hatch: ")
  (if (setq ss (ssget "_:S+." '((0 . "LWPOLYLINE") (-4 . "&") (70 . 1)))); one, closed only
    (progn ; then
      (setq
        obj (vlax-ename->vla-object (setq ent (ssname ss 0)))
        oarea (vla-get-Area obj)
        pickpt (vlax-curve-getClosestPointTo obj (last (last (last (ssnamex ss)))))
      ); setq
      (vla-offset obj 2)
      (if (> (vla-get-Area (vlax-ename->vla-object (entlast))) oarea)
        (progn ; then -- went wrong way
          (entdel (entlast))
          (vla-offset obj -2)
        ); progn
      ); if [went wrong way -- no else; do nothing if it went right way]
      (command
        "_.hatch" "USER"
          (cvunit
            (+ 
              (angle '(0 0 0) (vlax-curve-getFirstDeriv obj (vlax-curve-getParamAtPoint obj pickpt)))
              (/ pi 4)
            ); +
            "radian" "degree"
          ); cvunit
          0.75 "_no" ent (setq pl2 (entlast)) "" "" ; <-- EDIT 0.75 as preferred
        "_.chprop" "_last" "" "_layer" "YourLayerName" "" ; <-- EDIT Layer name
        "_.erase" pl2 ""
      )
    ); progn -- then
  ); if
  (vla-endundomark doc)
  (princ)
); defun -- C:OI2H
(vl-load-com)
(prompt "\nType OI2H to Offset Inward by 2 drawing units and Hatch.")

 

Kent Cooper, AIA
0 Likes

john.uhden
Mentor
Mentor

Oops (maybe)...

I did my testing by picking the apparent vertical side of my building, which makes the hatch come out like:

/ / / / / / /

But if I pick the apparent horizontal side of the building, then it comes out like:

\ \ \ \ \ \ \

So, if you are more inclined to pick a horizontal side, then...

;; change
(setq ang (+ (* 0.5 pi) (angle '(0 0) ang)))
;; to
(setq ang (angle '(0 0) ang))

 

John F. Uhden

0 Likes

Sea-Haven
Mentor
Mentor

John and Kent, just a out there having a play with linetype using "/" then its always in direction of line. This is close maybe change angle a bit. R=? Not sure can remove the dot.

 

 

*BLD,bld ----------/----------/----------/----------
A,0.0,-1.5,["/",STANDARD,S=1.8,R=0.0,X=-.9,Y=-.9]

 

 

SeaHaven_0-1654216471489.png

 

0 Likes

john.uhden
Mentor
Mentor

@Sea-Haven 

It's kinda funky at the corners, like sorta reminding me of earth hatch, and curves are fascinating, but that's pretty clever.

I was looking for another character that might be more obliqued, but no go.

It is sad that AutoCAD doesn't literally obey the text style definition to include the obliquing angle.

I tried using R=-15.0 which rotated them closer to 45°, but they lost their synch with the dots.

Do you have to have the dots?

John F. Uhden

0 Likes

Sea-Haven
Mentor
Mentor

Hi John the line type documentation refers to dots as the value 0.0, it may possible to do a gap without dots I only played for a few minutes, some one else may have an idea. When you do text in linetype it tries to draw a line then the text. A rule is must start finish with a line.

 

Not sure what using a shx will do. Will play again.

 

This is better

*BLD,bld ----------/----------/----------/----------
A,0.00001,-1.5,[" / ",STANDARD,S=1.8,R=0.0,X=-.9,Y=-.9]

0 Likes

Kent1Cooper
Consultant
Consultant

You have much more control if you use the TXT.shx font, and the "pipe" character  |  which in that font is exactly the specified text height in length, and vertical so you can be exact about the rotation, and you can get the dots buried.  [The dots in the image "show" only at certain zoom levels, but except at the corners they are, in fact, buried in the text elements.]

 

*BLD,bld / / / / / / /
A,0,["|",TXT,S=1.41421356,X=-.5,Y=-.5,R=-45],-1.5

Kent1Cooper_1-1654340725019.png

The linetype scale is the width of the "hatched" band -- no guesswork or weird calculations needed to know how far to Offset the building footprint to where the path of the band needs to be.  Change the -1.5 for a different density.

 

It uses the midline for the path, which is why the dots show at the corners, because when I define it to use one edge (the building outline so dots would be buried in that), it can do this kind of thing:

Kent1Cooper_0-1654340400616.png

 

Kent Cooper, AIA
0 Likes