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

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

Anonymous
Not applicable
3,677 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,678 Views
25 Replies
Replies (25)
Message 2 of 26

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... 

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. ....


If I may assume that your footings are all rectangular/square [as they always are in my experience], that looks a little more complicated than necessary [for instance, you don't need to create two temporary things that then need to be deleted when it's done -- there are simpler ways to find the midpoint of a rectangular Polyline than through a Region's centroid].  I would go about it something like this way [untested -- I didn't create various Blocks, etc.]:

 

(defun C:APF (/ ftgss ftgobj ftgarea); = Add Pile blocks to Footings
  (prompt "\nTo add piling Blocks to foundations,")
  (if (setq ftgss (ssget "_X" '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1))))
    ; closed 4-vertex Polylines only
    (repeat (setq n (sslength ftgss)); then
      (setq ftgobj (vlax-ename->vla-object (ssname ftgss (setq n (1- n)))))
      (vla-getboundingbox ftgobj 'minpt 'maxpt)
      (setq ftgarea (/ (vla-get-area ftgobj) 144)); area in square feet
      (command "_.insert"
        (cond ; Block name
          ((> ftgarea 64) "Your4PileBlockName"); anything over 8' square
          ((> ftgarea 36) "Your3PileBlockName"); over 6' square up to 8'
          ((> ftgarea 9) "Your2PileBlockName"); over 3' square up to 6'
          ("Your1PileBlockName"); anything no larger than 3' square
        ); cond
        "_none" (mapcar '/ (mapcar '+ (vlax-safearray->list minpt) (vlax-safearray->list maxpt)) '(2 2 2)); midpoint
        "" "" "" ; default scales of 1, rotation of 0
      ); command
    ); repeat [then]
    (prompt "\nNo 4-sided closed Polyline(s) selected."); else
  ); if
  (princ)
); defun
(vl-load-com)

 

Edit the bluish parts for your actual Block names, and the red parts for your actual break-point size categories [add more categories if needed].  It could also do other things, such as put them on a specified Layer, etc.

 

If they might not always be rectangular, something involving a centroid might be appropriate for finding the insertion point, but the (cond) function selecting the Block name based on the area would still apply.

 

I also assume you are using Architectural Units [a drawing unit = an inch], and that you always want the Blocks at scales of 1 and rotation of 0, and that they don't have Attributes -- adjust accordingly for any incorrect assumptions.

Kent Cooper, AIA
0 Likes
Message 3 of 26

Anonymous
Not applicable

Kent,

 This is spot on what I was looking for! THANK YOU! Your assumptions were correct and this saves me hours of work.

0 Likes
Message 4 of 26

Anonymous
Not applicable

@Kent1Cooper wrote:

@Anonymous wrote:

.... 

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. ....


If I may assume that your footings are all rectangular/square [as they always are in my experience], that looks a little more complicated than necessary [for instance, you don't need to create two temporary things that then need to be deleted when it's done -- there are simpler ways to find the midpoint of a rectangular Polyline than through a Region's centroid].  I would go about it something like this way [untested -- I didn't create various Blocks, etc.]:

 

(defun C:APF (/ ftgss ftgobj ftgarea); = Add Pile blocks to Footings
  (prompt "\nTo add piling Blocks to foundations,")
  (if (setq ftgss (ssget "_X" '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1))))
    ; closed 4-vertex Polylines only
    (repeat (setq n (sslength ftgss)); then
      (setq ftgobj (vlax-ename->vla-object (ssname ftgss (setq n (1- n)))))
      (vla-getboundingbox ftgobj 'minpt 'maxpt)
      (setq ftgarea (/ (vla-get-area ftgobj) 144)); area in square feet
      (command "_.insert"
        (cond ; Block name
          ((> ftgarea 64) "Your4PileBlockName"); anything over 8' square
          ((> ftgarea 36) "Your3PileBlockName"); over 6' square up to 8'
          ((> ftgarea 9) "Your2PileBlockName"); over 3' square up to 6'
          ("Your1PileBlockName"); anything no larger than 3' square
        ); cond
        "_none" (mapcar '/ (mapcar '+ (vlax-safearray->list minpt) (vlax-safearray->list maxpt)) '(2 2 2)); midpoint
        "" "" "" ; default scales of 1, rotation of 0
      ); command
    ); repeat [then]
    (prompt "\nNo 4-sided closed Polyline(s) selected."); else
  ); if
  (princ)
); defun
(vl-load-com)

 

Edit the bluish parts for your actual Block names, and the red parts for your actual break-point size categories [add more categories if needed].  It could also do other things, such as put them on a specified Layer, etc.

 

If they might not always be rectangular, something involving a centroid might be appropriate for finding the insertion point, but the (cond) function selecting the Block name based on the area would still apply.

 

I also assume you are using Architectural Units [a drawing unit = an inch], and that you always want the Blocks at scales of 1 and rotation of 0, and that they don't have Attributes -- adjust accordingly for any incorrect assumptions.


Good morning Kent,

I have been using the Lisp you helped me out with. I am wondering if it can be tweaked to match the rotation of the footing it is be dropped into? Many thanks in advance for any input.

 

-CBHanan

0 Likes
Message 5 of 26

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:
.... I am wondering if it can be tweaked to match the rotation of the footing it is be dropped into? Many thanks in advance for any input.

 ....


Yes, if I may again make some assumptions.  If the footing Polyline is square or rectangular [all edges either parallel or perpendicular to each other], and if it doesn't matter which of the two perpendicular directions is used for the rotation angle of the piling Block [because you can't see in looking at a Polyline which corner is the start and in which direction it was drawn], try changing this part:

 

....

        "" "" "" ; default scales of 1, rotation of 0
....

 

to this

 

....

        "" "" ; default scales of 1 [only two Enters]

        (* (/ (angle (vlax-curve-getStartPoint ftgobj) (vlax-curve-getPointAtParam ftgobj 1)) pi) 180); rotation [converted to degrees]
....

 

or even just this:

 

....

        "" "" ; default scales of 1 [only two Enters]

        "_none" (vlax-curve-getPointAtParam ftgobj 0.5); rotation [midpoint of first segment]
....

 

Someone may point out that both are subject to the possibility that the parameter values of a Polyline can rarely get out of whack, so that the vertices are not at whole-number parameter values.  But it takes weird circumstances to get that to happen, and I've never had a problem with it.  If you find it's a problem, it could be done using the vertex locations out of the Polyline's entity data instead of VLA parameters, which would mean adding a variable to get the entity data list for the Polyline.  I used the approaches above because there's already a variable holding something that parameters can be drawn from.

Kent Cooper, AIA
0 Likes
Message 6 of 26

ahuygen
Participant
Participant

hi. could you build something similar. I need a lisp that inserts at the cog of polylines with far more vertexes.

Purpose would be roomtags.

thankyou

Alex

0 Likes
Message 7 of 26

Kent1Cooper
Consultant
Consultant

@ahuygen wrote:

.... I need a lisp that inserts at the cog of polylines with far more vertexes.  Purpose would be roomtags.

 

....

Search this Forum [and the broader Community, and other websites] for things like "label areas" and "text in polyline" and similar wordings, and I think you'll find numerous threads about just this kind of thing.  If you don't, start a new one -- your request is different enough from the Subject of this thread that if you get a good solution, someone else with the same need may not be able to find it here.

Kent Cooper, AIA
0 Likes
Message 8 of 26

OM805
Enthusiast
Enthusiast

Hello...

 

Quick question, is it possible to include all closed polylines (not just four sided polylines)? Also, explode blocks after insert.

 

 

Regards,

OM

0 Likes
Message 9 of 26

Kent1Cooper
Consultant
Consultant

@OM805 wrote:

.... is it possible to include all closed polylines (not just four sided polylines)? Also, explode blocks after insert. ....


Try this [untested]:

(defun C:APF (/ ftgss ftgobj ftgarea); = Add Pile blocks to Footings
  (prompt "\nTo add piling Blocks to foundations,")
  (if (setq ftgss (ssget "_X" '((0 . "LWPOLYLINE") (-4 . "&") (70 . 1)))); took out the limit to 4 vertices
    ; closed Polylines only
    (repeat (setq n (sslength ftgss)); then
      (setq ftgobj (vlax-ename->vla-object (ssname ftgss (setq n (1- n)))))
      (vla-getboundingbox ftgobj 'minpt 'maxpt)
      (setq ftgarea (/ (vla-get-area ftgobj) 144)); area in square feet
      (command "_.insert"

        (strcat "*"  ; asterisk prefix Inserts already exploded
          (cond ; Block name
            ((> ftgarea 64) "Your4PileBlockName"); anything over 8' square
            ((> ftgarea 36) "Your3PileBlockName"); over 6' square up to 8'
            ((> ftgarea 9) "Your2PileBlockName"); over 3' square up to 6'
            ("Your1PileBlockName"); anything no larger than 3' square
          ); cond

        ); strcat
        "_none" (mapcar '/ (mapcar '+ (vlax-safearray->list minpt) (vlax-safearray->list maxpt)) '(2 2 2)); midpoint
        "" "" ; default scale of 1, rotation of 0 ; took out one "" [for pre-exploded, asks for only one scale]
      ); command
    ); repeat [then]
    (prompt "\nNo closed Polyline(s) selected."); else ; took out mention of 4-sided
  ); if
  (princ)
); defun
(vl-load-com)

Kent Cooper, AIA
Message 10 of 26

Sea-Haven
Mentor
Mentor

Nice code Kent when shape is not rectang more than 4 points mid of bounding box may place text outside the pline shape.  Thinking about a "L" I dont think there is a quick solution for odd shapes. Just a side comment, different method I use for 4 sides, use 2 diag pts add together, divide 2, using mapcar.

 

Two other solutions using points is area, and centroid, Mathematical solutions, but get area is much easier.

0 Likes
Message 11 of 26

Kent1Cooper
Consultant
Consultant

@Sea-Haven wrote:

....  Thinking about a "L" I dont think there is a quick solution for odd shapes. Just a side comment, different method I use for 4 sides, use 2 diag pts add together, divide 2, using mapcar.

....


No, there's no quick solution for odd shapes, but I think there may be some threads in this Forum about finding a place that "in the middle" in a way but forced to be actually inside, for just this kind of purpose [probably area labeling].  I'll let others Search for that if they need such a thing.

My version finds the middle of a quadrilateral in exactly that way -- my "2 diag pts" are opposite corners of the bounding box, whereas I assume you're talking about 2 opposite vertex locations.  Those locations are the same as mine for an orthogonal rectangle [spread footings are usually like that], and the end result would be the same for a rectangle at any rotation, or for any parallelogram, but the end result would vary with other quadrilateral shapes, such as a kite or trapezoid.  And for those, the result would be different for one pair of opposite vertices than for the other pair.

 

Kent Cooper, AIA
0 Likes
Message 12 of 26

OM805
Enthusiast
Enthusiast

Kent,

 

Thanks for the LISP code edit.  In short, it does the job and works. Much appreciated...

 

 

Regards,

 

OM

0 Likes
Message 13 of 26

OM805
Enthusiast
Enthusiast

Kent,

 

Currently, the code inserts the block into all present polylines (turned off or not). Possible, to have it either select objects or select based on a layer name? Either or would work...  I did try to apply your lisp tip Select Object by Layer without success.

 

Regards,

 

OM

0 Likes
Message 14 of 26

Kent1Cooper
Consultant
Consultant

It's all in this line [from the first version -- similar adjustments if you mean later code]:

  (if (setq ftgss (ssget "_X" '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1))))

 

If you want to select yourself, rather than having it find all of them, remove the "_X":

  (if (setq ftgss (ssget '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1))))

If you want it to find all of them on a particular Layer, keep that but add a Layer filter:

  (if (setq ftgss (ssget "_X" '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1) (8 . "YourLayerName"))))

If you want to select yourself, but have it only "find" those on a particular Layer, do both:

  (if (setq ftgss (ssget '((0 . "LWPOLYLINE") (90 . 4) (-4 . "&") (70 . 1) (8 . "YourLayerName"))))

Kent Cooper, AIA
Message 15 of 26

OM805
Enthusiast
Enthusiast

Kent,

 

Noted, edited and tested with success... Thanks for the valuable help.  Like always, much appreciated...

 

OM

0 Likes
Message 16 of 26

CBHANAN
Participant
Participant

Hello again Kent! Hope all is well. Been a few years since you helped me out with this issue and I've since received new computers etc. thus losing the lisps I had. I have recreated what you gave me but have been unable to get the rotation portion of the lisp to work. In reference to:

 

the piling Block [because you can't see in looking at a Polyline which corner is the start and in which direction it was drawn], try changing this part:

 

....

        "" "" "" ; default scales of 1, rotation of 0
....

 

to this

 

....

        "" "" ; default scales of 1 [only two Enters]

        (* (/ (angle (vlax-curve-getStartPoint ftgobj) (vlax-curve-getPointAtParam ftgobj 1)) pi) 180); rotation [converted to degrees]
....

 

or even just this:

 

....

        "" "" ; default scales of 1 [only two Enters]

        "_none" (vlax-curve-getPointAtParam ftgobj 0.5); rotation [midpoint of first segment]
....

 

How does this need to appear exactly in the lips code? I've cut/pasted it in all combinations but the block still inserts a rotation of 0 even though the poly lines are at an angle. Any insight from you is appreciated.

 

Thank you

0 Likes
Message 17 of 26

Kent1Cooper
Consultant
Consultant

@CBHANAN wrote:

.... the block still inserts a rotation of 0 even though the poly lines are at an angle. Any insight from you is appreciated.


The first thing that comes to mind is that maybe the Polylines start with two coincident vertices and a zero-length first segment.  That would make your (angle) function take the angle between two instances of the same location, which always returns 0.  Or your midpoint of the first segment would be at the same location as the start point [though that could result in a non-zero rotation, depending on the orientation].  Is that a possibility?

 

Or, could the Blocks be defined for uniform scaling, in which case it won't as for both X and Y scale factors?  If so, I would expect some error message from feeding in the angle when it's finished with the command.

Kent Cooper, AIA
0 Likes
Message 18 of 26

CBHANAN
Participant
Participant

Kent,

Please see attached screen shot and sample file to see if it helps communicate idea across.

LISP SHOT.png

0 Likes
Message 19 of 26

Kent1Cooper
Consultant
Consultant

So it's not a coincident-vertices problem.  What does the command-line history show when you run it?

Kent Cooper, AIA
0 Likes
Message 20 of 26

CBHANAN
Participant
Participant

Please see ee attached with screenshot with lisp

SCRNSHT LISP.png

0 Likes