Trying to get block insert lisp to separate insertion point and rotate.

Trying to get block insert lisp to separate insertion point and rotate.

Satoews
Advocate Advocate
2,649 Views
16 Replies
Message 1 of 17

Trying to get block insert lisp to separate insertion point and rotate.

Satoews
Advocate
Advocate

I have been playing around with this file for a bit and can't figure out how to:

  1. make the lisp rotate the block
  2. then select its insertion point

The reason being i want to use a line to make the angle but i don't want the block to be on top of the line. This is what i have at the moment.

 

(defun C:EE5()
(command "-INSERT""EE5" PAUSE "" "" PAUSE)
(command "copy" "L" "" "M" (GETVAR 'LASTPOINT))
)

 

Also I have about 30 of these small lisps repeated all the same except for the block name and the defun, is there any way to simplify that?

 

Thanks in advance, 

 

Shawn Toews

Shawn T
0 Likes
Accepted solutions (1)
2,650 Views
16 Replies
Replies (16)
Message 2 of 17

Jonathan3891
Advisor
Advisor

 

Try this out. Make sure to change the block name.

 

(defun C:test(/ A)
(command "-INSERT" "ANCHOR BOLT" PAUSE "" "" PAUSE)
(setq A (cdr (assoc 10 (entget (ssname (ssget "_X" '((2 . "ANCHOR BOLT"))) 0))))
      )
(command "COPY" "L" "" "M" A )
  )

 


Jonathan Norton
Blog | Linkedin
Message 3 of 17

Jonathan3891
Advisor
Advisor
To simplify you can have the lisp select the last block inserted or even select the block itself and it can get the insertion point.

Jonathan Norton
Blog | Linkedin
Message 4 of 17

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....

  1. make the lisp rotate the block
  2. then select its insertion point

The reason being i want to use a line to make the angle but i don't want the block to be on top of the line.  ....

 

Also I have about 30 of these small lisps repeated all the same except for the block name and the defun, is there any way to simplify that?

 

....

A Line entity specifically?  Or possibly a Polyline line segment, or an Mline, or an edge of something else?

 

Let's say it could be a straight piece or segment or edge of any entity type.  If you can manage to pick on it not at an end, so that Object Snap between NEArest and ENDpoint modes can determine an angle, you can do something like this, using a shared routine that will take a Block name as an argument:

 

(defun BlockOnEdge (blkname / pt ang)

  (setq

    pt (getpoint "\nPick on line/edge to define Block rotation: ")

    ang (angle (osnap pt "_nea") (osnap pt "_end"))

  ); setq

  (command

    "_.insert" blkname "_scale" 1 "_rotate" (angtos ang) pause

      ; sets scale/rotation as options before pause at end for insertion point

    "_.copy" "_last" "" "_multiple" "@"

  ); command

); defun

 

That lets you get the angle with one pick, instead of by way of a temporary-because-that-'s-not-where-you-really-want-it insertion point on the Line [or whatever] and another pick for the rotation.

 

That assumes a Block without Attributes, and doesn't yet account for possible running Osnap modes, etc.  It could be made to adjust the angle to the more-upright direction, if that's appropriate to your Blocks, and/or to check that you picked on something straight rather than curved, and some other things.  [It could even be made to let you pick on a curve, and use its direction at the pick point for the rotation, though that doesn't seem likely to be what you want.]

 

Then for all your different Blocks, make little command names using that shared routine:

 

(defun C:EE5 ()

  (BlockOnEdge "EES")

)

 

(defun C:ABC ()

  (BlockOnEdge "ABC")

)

 

(defun C:XYZ ()

  (BlockOnEdge "XYZ")

)

 

 

Kent Cooper, AIA
Message 5 of 17

Satoews
Advocate
Advocate

That is great except for I am getting blocks that are upside down. Any way to fix that? the blocks I am using are numbered width labels so they need to be upright. I really appricate the replys!

 

thanks!

 

Shawn Toews

Shawn T
0 Likes
Message 6 of 17

Satoews
Advocate
Advocate

I have been playing around with it a bit an came up with this in case the upside down text label can't be fixed.

 

(defun BlockOnEdge (blkname / pt ang)
  (setq
    pt1 (getpoint "\nPick on first point: ")
    pt2 (getpoint "\npick on second point: ")
  ); setq
  (command
    "_.insert" blkname "_scale" 1 "_rotate" (angtos(angle pt1 pt2)) pause
      ; sets scale/rotation as options before pause at end for insertion point
    "_.copy" "_last" "" "_multiple" "@"
  ); command
); defun
  
(defun C:E5 ()
  (BlockOnEdge "EE5")
)
 
(defun C:E10 ()
  (BlockOnEdge "EE10")
)
 
(defun C:E12 ()
  (BlockOnEdge "EE12")
)

What ya think? I'm still a bit fuzzy on what (blkname / pt ang) in the lisp dose but I am getting pretty much everything else in this lisp, thanks for the help everyone! Slowly learning the ropes with your help. 

Shawn T
0 Likes
Message 7 of 17

stevor
Collaborator
Collaborator

Re: "fuzzy on what (blkname / pt ang)"

That passes the name of the block,

stored in the variable 'blkname '

and the '/ pt ang' makes the variables

'pt' and 'ang' local variables, are

local to that function, 'BlockOnEdge.'

'Local' means that those 2 variables,

'pt and 'ang,  are defined only in that function,

and are not changed by use of the same

variable names elsewhere.

 

S
Message 8 of 17

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

... I am getting blocks that are upside down. Any way to fix that? the blocks ... need to be upright. ...


Certainly!  [Second sentence, longer paragraph in Post 4.]  No need to require two picks from the User to set the rotation.  One way is to add this line before the Insert command starts:

 

....

  ); setq

  (if (and (> ang (/ pi 2)) (<= ang (* pi 1.5))) (setq ang (+ ang pi)))

  (command

....

 

 

Kent Cooper, AIA
Message 9 of 17

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... I'm still a bit fuzzy on what (blkname / pt ang) in the lisp dose .... 


To expand on what stevor said about blkname:

 

Anything before the slash [/] in the parentheses following a function name is an argument, as distinguished from the things that come after the /, which are variables.  Think of it as a kind of variant on a variable, a 'placeholder' for a value that is going to be fed in when the function is used.

 

When you do:

 

  (BlockOnEdge "EES")

 

the "EES" is the argument, and wherever the blkname placeholder occurs in the function definition, that argument will be fed in.  So when it gets to:

  (command

    "_.insert" blkname "_scale" 1 ....

 

it will be supplied with the "EES" [or another Block name in the other command definitions] in place of the blkname argument/placeholder.  That's how one function definition can be used in any number of different command definitions -- each command calls that same function but supplies its own argument value.

 

Note the difference between:

(defun BlockOnEdge

 

without the C: before its function name, and:

 

(defun C:EE5

 

with the C: before its command name.  Command definitions with the C: can't have arguments before the slash; function definitions without it can, though they don't always need to.  In either type, if there are no arguments or localized variables, they still need their name to be followed by either [as I usually do it] empty parentheses or [as you will sometimes see it done] nil in their place.

 

When you use a function with one or more arguments in its definition, you must supply a value for each argument, within the parentheses calling the function, and if there's more than one, in the order in which their placeholders are listed in the function definition.  If you were to try:

 

(BlockOnEdge)

 

without supplying a value for the blkname argument, it would complain to you that you didn't supply enough information:

; error: too few arguments

 

Also, you type in a command name "plain" to use it, e.g. EES, but a function must be called inside parentheses, just like the difference between using an AutoCAD command and an AutoLisp function at the Command: prompt.

 

To use a custom-defined command name within another AutoLisp routine, you likewise call it in parentheses and with the C: prefix, e.g. (C:EES).  You can't use it in a (command) function, which only recognized AutoCAD's own command names.

Kent Cooper, AIA
Message 10 of 17

Satoews
Advocate
Advocate

Thank you so much for the explanation, I am learning a lot. After if figured out how the blocks were manipulated using the new code i ran into one more issue i'd like to fix and i can't seem to get the code there. This is also where i get stuck a lot of times where the code seems to imput into the prior command rather than doing a new command.

 

(defun BlockOnEdge (blkname / pt ang)
  (setq
    pt (getpoint "\nPick on line/edge to define Block rotation: ")
    ang (angle (osnap pt "_nea") (osnap pt "_end"))
    OSM	(getvar "osmode") 
  ); setq
  (if (and (> ang (/ pi 2)) (<= ang (* pi 1.5))) (setq ang (+ ang pi)))
 (setvar 'osmode 0)
  (command
    "_.insert" blkname "_scale" 1 "_rotate" (angtos ang) pause
      ; sets scale/rotation as options before pause at end for insertion point
    "_.copy" "_last" "" "_multiple" "@"
  )(setvar 'osmode (osm))
)

I am trying to make it so the snaps turn off while I am placing in the blocks but turns back on at the end of the lisp. So far it just keeps imputting my osm into the copy command.

 

thanks!

 

Shawn Toews

Shawn T
0 Likes
Message 11 of 17

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....

 

....
    "_.copy" "_last" "" "_multiple" "@"
  )(setvar 'osmode (osm))
)

I am trying to make it so the snaps turn off while I am placing in the blocks but turns back on at the end of the lisp. ....


This is the classic case of a command that can have an indeterminate number of User inputs before it's completed, and you don't want it to continue on to something such as resetting that System Variable until after the command is done.

 

You can have it wait for further input as long as the User wants to keep going, and continue only when they're finished, by monitorng the CMDACTIVE System Variable:

 

....
    "_.copy" "_last" "" "_multiple" "@"
  ); command
(while (> (getvar 'cmdactive) 0) (command pause))
; CMDACTIVE returns to 0 when done with command, so (>) returns nil,
; stopping (while) loop, and only then:

(setvar 'osmode (osm)) )

 

Kent Cooper, AIA
Message 12 of 17

Satoews
Advocate
Advocate

hmmm, when i enter out of the command it gives me error: bad function. when i escape out of the command (as i usually do) it gives me ; error: function cancelled. Also I put the osm into the local function, that correct?

 

(defun BlockOnEdge (blkname / pt ang osm)
  (setq
    pt (getpoint "\nPick on line/edge to define Block rotation: ")
    ang (angle (osnap pt "_nea") (osnap pt "_end"))
    OSM	(getvar "osmode") 
  ); setq
  (if (and (> ang (/ pi 2)) (<= ang (* pi 1.5))) (setq ang (+ ang pi)))
 (setvar 'osmode 0)
  (command
    "_.insert" blkname "_scale" 1 "_rotate" (angtos ang) pause
      ; sets scale/rotation as options before pause at end for insertion point
    "_.copy" "_last" "" "_multiple" "@"
  ); command
  (while (> (getvar 'cmdactive) 0) (command pause))
    ; CMDACTIVE returns to 0 when done with command, so (>) returns nil,
    ; stopping (while) loop, and only then:
  (setvar 'osmode (osm))
)

 Again thanks for all the help! 

Shawn T
0 Likes
Message 13 of 17

Kent1Cooper
Consultant
Consultant
Accepted solution

@Anonymous wrote:

hmmm, when i enter out of the command it gives me error: bad function. when i escape out of the command (as i usually do) it gives me ; error: function cancelled. Also I put the osm into the local function, that correct?

 

....
  (setvar 'osmode (osm))
)

....


Yes, listing osm as a localized variable is correct.  Sorry, I should have noticed this before:

 

  (setvar 'osmode osm)

 

[no parentheses around variable names -- that's what made it think (osm) was supposed to be a function, but of course it isn't, hence the bad-function error message]

 

If you ESCape to end it, it won't reset that, because it cancels the whole routine, rather than simply ending the Copy command.  So an *error* handler would be needed to ensure it does, unless you can always remember to use Enter/space to end it.  It can be handled like a localized variable, so that AutoCAD's standard one will go back into effect after the routine is done, and it can also suppress the function-cancelled message.  Here's a typical way of doing it:

 

(defun BlockOnEdge (blkname / *error* pt ang osm)
 (defun *error* (errmsg)
(if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break"))
(princ (strcat "\nError: " errmsg))
); if
(setvar 'osmode osm); reset
(princ)
); defun - *error*
(setq osm (getvar "osmode")
pt (getpoint "\nPick on line/edge to define Block rotation: ") ang (angle (osnap pt "_nea") (osnap pt "_end")) ); setq (if (and (> ang (/ pi 2)) (<= ang (* pi 1.5))) (setq ang (+ ang pi))) (setvar 'osmode 0) (command "_.insert" blkname "_scale" 1 "_rotate" (angtos ang) pause "_.copy" "_last" "" "_multiple" "@" ); command (while (> (getvar 'cmdactive) 0) (command pause)) (setvar 'osmode osm); reset
(princ) ); defun

[I put the 'osm' variable first in the setting of localized variables, so that even if the User cancels when it's asking to pick on a line/edge [the first time the User has a chance to kill it], the *error* handler won't itself trigger an error, for trying to reset OSMODE to a variable that doesn't exist, because it will already be there.]

EDIT:  Come to think of it [without trying it out], that osm variable may not be set if they cancel at that point, since the (setq) function hasn't closed.  It may be necessary to separate it from the others to ensure that it's set, no matter what the User does:

 

 (setq osm (getvar "osmode"))
(setq
pt (getpoint "\nPick on line/edge to define Block rotation: ") ang (angle (osnap pt "_nea") (osnap pt "_end")) ); setq

 

Kent Cooper, AIA
Message 14 of 17

Satoews
Advocate
Advocate

thank you for all your help, thats perfect. I also learned a heck of a lot from everyone involved with this post. 

 

thanks again!!

Shawn T
0 Likes
Message 15 of 17

Anonymous
Not applicable

I am trying  a similar routine however the lines are being created within the routine itself. Everytime i try and insert the block i am getting an error regarding the rotation of the block. i have tried creating various individual points relating the angled line but everytime it is coming up dud. i don't know if there is a specific command i need to enter instead of "getpoint" perhaps?

0 Likes
Message 16 of 17

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

I am trying  a similar routine however ... error ....


 

Post the code.

Kent Cooper, AIA
0 Likes
Message 17 of 17

Anonymous
Not applicable

Hi Kent,

 

Thanks for getting back to me. Please see the lisp file attached.

 

I've just seen how the lsp file downloads, i do apologise. The code in question is nearish the bottom of the file. under the  heading of draw the side view of the front base. The code is regarding the spotcooler block

0 Likes