Need AutoLISP to Insert Block Based on Area of Polyline..?

Need AutoLISP to Insert Block Based on Area of Polyline..?

Anonymous
Not applicable
3,674 Views
25 Replies
Message 1 of 26

Need AutoLISP to Insert Block Based on Area of Polyline..?

Anonymous
Not applicable

Hello All,

 

I work with structural foundation plans and need to insert certain blocks depending on what the area of each foundation is. For example, if the footing is 49 square feet, I center a 3-probe block on that foundation. Ultimately, I would love a lisp that would run through the closed polylines, find the centroid of each foundation, and then insert a block centered on the foundation. I have attached a Lisp I found online but need the conditional block insert based on the area. Any feedback is highly appreciated.

 

 

0 Likes
3,675 Views
25 Replies
Replies (25)
Message 21 of 26

Kent1Cooper
Consultant
Consultant

The code you posted still has the third Enter [yellow-highlighted] for the default 0 rotation, and the rotation code you want is part of the "commented-out" end of the code line.

 

Kent1Cooper_0-1615572684355.png

 

That "" should be removed, and the red-circled part moved down to a new line

Kent Cooper, AIA
0 Likes
Message 22 of 26

CBHANAN
Participant
Participant

That did the trick. All sorted out! Thank you again for all the help over the history of this.

0 Likes
Message 23 of 26

Lindsay-CAD
Contributor
Contributor

Kent

I have a similar situation. I receive drawings from Tiltwerks output and all objects are lines, circles or polylines. I have to insert blocks over the polylines on certain layers that are based on the area of the polyline. I have a routine to do this individually, IE tell the routine to find all Polylines with an area of 40 and then insert a block at the midpoint of the top line. I am trying to work out how to make this look for 26 different areas and insert the appropriate block. I was thinking I could make a list of the 26 sizes and the associated block name, (40 box-x). check the list to see if the area of the object is in the list and insert the block associated with (40 is the area, Box-X is the block to insert)

 

This is the code I use to do the above

(defun C:boxrp (/ ss n pl)
 
  (if (setq ss (ssget "_X" '((0 . "LWPOLYLINE") (8 . "STRUCT") (70 . 1)))) ;Select all polylines on layer struct
    (progn
      (repeat (setq n (sslength ss))
        (setq pl (ssname ss (setq n (1- n))))
        (if (= (vla-get-Area (vlax-ename->vla-object pl)) 126) ;126 is the area of the Plt-P6 plate
          (ssdel pl ss)
(progn 
(vla-getboundingbox (vlax-ename->vla-object pl) 'minpt 'maxpt) 
(setq LL (vlax-safearray->list minpt) ;lower left point
            UR (vlax-safearray->list maxpt) ;upper right point
            ;midbot (list (/ (+ (car LL) (car uR)) 2) (cadr LL))
      midtop (list (/ (+ (car ll) (car uR)) 2) (cadr UR))
)
(setvar "clayer" "Struct")
;(command "insert" "Plt-P6" midbot "" "" "")
(command "insert" "Plt-p6" midtop "" "" "")
);progn
       ); if
      ); repeat
      (sssetfirst nil ss)
    ); progn
  ); if
); defun
 
Thanks
RobH
0 Likes
Message 24 of 26

Kent1Cooper
Consultant
Consultant

I'm not sure I understand the procedure -- it looks like if its area is 126, you remove it from the selection, but only if it's not do you add the Block appropriate to an area of 126.  If it's been "working," I expect it's from the fact that real number values can calculate just slightly differently from what you expect, and the (=) function is not being satisfied because it needs true equality, but the area of a Polyline is actually something like 126.000000000000318.  A better idea is to use (equal) with a fuzz factor.

 

But yes, you can do it with an association list.  The Block names would need to be in quotes:
(40 "box-x")

So make a list of pairs:

(setq theList '((40 "box-x") (50 "box-y") (60 "box-z")))

The tricky part is to overcome that real-number problem, meaning you need to convert the area value to be sure it's a true integer for use in finding its Block name.  Something like this should do:

(setq theArea (atoi (rtos (vla-get-Area (vlax-ename->vla-object pl)) 2 0)))

The (rtos) will round to the nearest whole number, which could be up or down [safer than (fix), which always rounds down], and the (atoi) will make that an integer.  Then you can use:

(cadr (assoc theArea theList))

to pull the appropriate Block name.

 

Build in some way of handling the case where the area is not covered in the association list.

 

There could be variant approaches -- for example, you could use the (rtos) result directly as a string, instead of forcing it back to an integer, for the first elements in the list:

(setq theList '(("40" "box-x") ("50" "box-y") ("60" "box-z")))

Kent Cooper, AIA
0 Likes
Message 25 of 26

Lindsay-CAD
Contributor
Contributor
Thank you for such a quick reply
The lisp routine works great if I only look for the one area. It runs and insert the PLT-P6 block at the midpoint of the top line of each polyline on layer "struct"
What I am hoping to do is have it look for the 25 other possible sizes of polylines and insert the appropriate block at midpoint of the top line.
I could copy the code 25 times and put in all the block names. But I was thinking I could do it easier if it was looking for the info from a list.
I am not an accomplished programmer in lisp. I search for the web for things that do what I want or are close and then try to make them work.
This current routine is parts of 2 I found and a little of me.
The drawing I am working on now has 300 to 400 polylines that need block inserted over them.
The drawing also has circles of varying diameters that also have block inserted at their center points. In that routine I just have the code in it for the 3 different diameters. Works great and fast, seconds versus hours
When it come to (IF (AND (OR, I feel like I'm in the deep end of the pool
Thanks
RobH

0 Likes
Message 26 of 26

Kent1Cooper
Consultant
Consultant

I'm thinking something like this [UNTESTED] might work:

(defun C:boxrp (/ AreaBlkList ss n pl plarea LL UR midtop nogo)
  (setq AreaBlkList '((40 "box-x") (50 "box-y") (60 "box-z")));;; <---EDIT
  (if (setq ss (ssget "_X" '((0 . "LWPOLYLINE") (8 . "STRUCT") (-4 . "&") (70 . 1))))
    ;all closed polylines on layer STRUCT, with or without linetype generation enabled
    (progn ; then
      (command "_.layer" "_set" "STRUCT" ""); [once, instead of with every one]
      (repeat (setq n (sslength ss)); then
        (setq
          pl (ssname ss (setq n (1- n)))
          plarea (atoi (rtos (vla-get-Area (vlax-ename->vla-object pl)) 2 0))
            ; as integer, forced up or down to nearest whole number
        ); setq
        (if (assoc plarea AreaBlkList); it's a size in the list
          (progn ; then
            (vla-getboundingbox (vlax-ename->vla-object pl) 'minpt 'maxpt) 
            (setq
              LL (vlax-safearray->list minpt) ;lower left point
              UR (vlax-safearray->list maxpt) ;upper right point
              midtop (list (/ (+ (car LL) (car UR)) 2) (cadr UR))
            ); setq
            (command "_.insert" (cadr (assoc plarea AreaBlkList)) midtop "" "" "")
          ); progn [then]
          (ssadd pl (cond (nogo) ((setq nogo (ssadd))))); else
            ; selection set of those with area(s) not in list
            ; [nogo variable created only at first such instance]
        ); if [size in list]
      ); repeat
      (command "_.layerp"); set back [reason for (command) above, not (setvar)]
      (if nogo
        (progn ; then
          (sssetfirst nil nogo); select/grip/highlight those of unlisted areas
          (alert "Polylines of unlisted area selected."); to do with what you want
        ); progn
      ); if [nogo]
    ); progn
  ); if [found any on that Layer]
  (prin1)
); defun

Line 2 is where you would build your longer list of pairings of areas with Block names.

 

I tweaked some things from your code for various reasons -- see comments.

 

Here's a question:  What constitutes not being in the list of areas?  As written [assuming it works], it would put something with an area of, for example, 39.6 into the (40 "box-x") category.  But is that too far from the right area for that?  Should it not necessarily just round everything to the nearest whole number, but only if within a certain tolerance of a whole-number area, or even a whole multiple of something [for example, 10]?

Kent Cooper, AIA
0 Likes