Sir Lord Mr. Mac Nugget Posted April 20, 2021 Posted April 20, 2021 Hi! I’ve been struggling with a macro/lisp to rotate a block from the insertion point, a fixed angle and keeping it selected. The purpose of this is to assign the command/lisp to a keyboard shortcut so when a block is selected (either prompted by the command or if it was already selected) it rotates, from the insertion point, a fixed value stored in USERR3, and keeps the block selected (so pressing the shortcut again will rotate it again, and so on) Similar to what space does in Revit, if it helps… In the past, I’ve tried multiple macros that did not work (usually because they asked for the base point the first time, or it did not work when the block was already selected). For instance: *^C^C_rotate;\;ins;@;90; And, when worked, the block was deselected at the end. So, after multiple lisp attempts with rotate command (it deselects at the end, or asks for base point), I’ve concluded that, what would work best for me would be a lisp (or a macro if it still possible!) that changed the rotation property of a block, incrementing it by a value stored in USERR3, rather than using rotate command. Fist, I’ve created a function to assign the angle to a user variable: (defun c:PAng ( / ang) ;define variables (initget 6) (setq ang (getreal "\nAngle: ")) (setvar "USERR3" (* pi (/ ang 180))) ;Convert to radians (princ) (Why the ending princ!? nothing has to be printed.... the code is ado(a)pted) And well…. That’s “really” all. I have tried to adapt several lisps, but ended in disaster (and minor fires…), tinkered with "vl-catch-all-apply 'vla-put-rotation" with minimal success, tried to understand the practical difference of entsel o ssget, why it keeps asking for selection when it already made, cried a little, and learned that lisp works in radians… but not much. And here I am! Hoping for some enlighten, or the divine intervention of one CADTutor. Any advice? (a piece or a lot) Thank you very much! Quote
mhupp Posted April 21, 2021 Posted April 21, 2021 (edited) 15 hours ago, Sir Lord Mr. Mac Nugget said: And, when worked, the block was deselected at the end. I'll take the simple route if you still have that lisp just add the following to the end of the lisp before the (princ) change SS to what ever it uses set the selection set. (sssetfirst nil ss) Quote (Why the ending princ!? if you don't us it then the lisp will output "nil" to the command line. example here Quote or it did not work when the block was already selected Check the lisp the first "command" that needs to happen is setting the selection set (ssget) This would work with something already selected before running the command (defun C:OO (/ ss) (setvar 'cmdecho 0) (if (setq ss (ssget)) .... ) This wouldn't work because the Undo Begin command was used before setting the selection set. (defun C:OO (/ ss) (setvar 'cmdecho 0) (command "_.undo" "be") (if (setq ss (ssget)) .... ) setting system varables isn't a command persay. and im sure someone will bring more light to this. Edited April 21, 2021 by mhupp Quote
ronjonp Posted April 21, 2021 Posted April 21, 2021 Maybe something like this? (defun c:foo (/ o s) (or *fooang* (setq *fooang* 45)) (if (and (setq *fooang* (cond ((getangle (strcat "\nEnter rotation angle:<" (rtos *fooang* 2 0) "> "))) (*fooang*) ) ) (setq s (ssget ":L" '((0 . "INSERT")))) ) (while (getpoint "\nKeep picking points to rotate: ") (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ *fooang* (vla-get-rotation o))) ) ) ) (princ) ) Quote
BIGAL Posted April 21, 2021 Posted April 21, 2021 (edited) Should the angle be in radians for put-rotation (vla-get-rotation (vlax-ename->vla-object (car (entsel "pick")))) 0.785398163397448 Properties = 45 Edited April 21, 2021 by BIGAL Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 (edited) 1 hour ago, BIGAL said: Should the angle be in radians for put-rotation (vla-get-rotation (vlax-ename->vla-object (car (entsel "pick")))) 0.785398163397448 Properties = 45 Good catch. Edited April 22, 2021 by ronjonp Quote
BIGAL Posted April 22, 2021 Posted April 22, 2021 Change 1 line works now could have used DTR but keep simple. (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (* pi (/ *fooang* 180.0)) (vla-get-rotation o))) Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 2 minutes ago, BIGAL said: Change 1 line works now could have used DTR but keep simple. (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (* pi (/ *fooang* 180.0)) (vla-get-rotation o))) The code works fine .. I was referring to the default entry. What you propose would be incorrect ( getangle ) returns radians. (defun c:foo (/ o s) (or *fooang* (setq *fooang* (angtof "45"))) (if (and (setq *fooang* (cond ((getangle (strcat "\nEnter rotation angle:<" (rtos (* (/ *fooang* pi) 180.0) 2 0) "> ") ) ) (*fooang*) ) ) (setq s (ssget ":L" '((0 . "INSERT")))) ) (while (getpoint "\nKeep picking points to rotate: ") (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ *fooang* (vla-get-rotation o))) ) ) ) (princ) ) Quote
BIGAL Posted April 22, 2021 Posted April 22, 2021 Sorry missed the angtof just skipped and read as 45 a real, not a string. (angtof "45") Quote
Sir Lord Mr. Mac Nugget Posted April 22, 2021 Author Posted April 22, 2021 (edited) Whoa! I thought that I would get an email when a moderator accepted my post, and didn’t look it up. So many thanks everyone! @Ronjonp. It works almost as intended! The issue for me is that it asks to keep picking points, and when its done, the blocks gets deselected. The idea for me was something like: I have an angle stored in USERR3, and the lisp linked to SHIFT+R I select a block. I press SHIFT+R, and, without asking anything to me, the block turns “USERR3” degrees clockwise around the insertion point, the lisp ends and the block is still selected. If I’d press SHIFT+R again, I turn another “USERR3” degrees clockwise, end again and keep the block selected. Make it 4 times and you are at the beginning. In my mind it was something like this: And tinkering with your code, i got here! (o boy... so excited!) ;---------Angle to USSERR3--------- (defun c:PAng ( / ang) ;Define variables (initget 6) (setq ang (getreal "\nAngle: ")) (setvar "USERR3" (* pi (/ ang 180)) ;Convert to radians ;(princ "\nAngle: " ang) (princ) ) ;---------Rotate USERR3's angle--------- (defun c:foo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) ;for multiple objects? Clever! (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (getvar "USERR3") (vla-get-rotation o))) ) ) (sssetfirst nil s) ;Keep stuff selected (where are my grips?) (princ) ) Which, surprisingly, does all of the intended! IT'S ALIVE! (dramatic thunder effect in the background) The only issue (absolutely minor) is that grips turn invisible until I do anything else (but everything is still selected even I can't see it). Is it any way to fix this? Thank you so much guys for the help! It's been quite a time since I wanted to do this, and it's rather embarrassing that in the end, it was actually 2 proper lines of code.... Edited April 22, 2021 by Sir Lord Mr. Mac Nugget emphasize how thankful I am Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 (edited) 2 hours ago, Sir Lord Mr. Mac Nugget said: Whoa! I thought that I would get an email when a moderator accepted my post, and didn’t look it up. So many thanks everyone! @Ronjonp. It works almost as intended! The issue for me is that it asks to keep picking points, and when its done, the blocks gets deselected. The idea for me was something like: I have an angle stored in USERR3, and the lisp linked to SHIFT+R I select a block. I press SHIFT+R, and, without asking anything to me, the block turns “USERR3” degrees clockwise around the insertion point, the lisp ends and the block is still selected. If I’d press SHIFT+R again, I turn another “USERR3” degrees clockwise, end again and keep the block selected. Make it 4 times and you are at the beginning. In my mind it was something like this: And tinkering with your code, i got here! (o boy... so excited!) ;---------Angle to USSERR3--------- (defun c:PAng ( / ang) ;Define variables (initget 6) (setq ang (getreal "\nAngle: ")) (setvar "USERR3" (* pi (/ ang 180)) ;Convert to radians ;(princ "\nAngle: " ang) (princ) ) ;---------Rotate USERR3's angle--------- (defun c:foo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) ;for multiple objects? Clever! (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (getvar "USERR3") (vla-get-rotation o))) ) ) (sssetfirst nil s) ;Keep stuff selected (where are my grips?) (princ) ) Which, surprisingly, does all of the intended! IT'S ALIVE! (dramatic thunder effect in the background) The only issue (absolutely minor) is that grips turn invisible until I do anything else (but everything is still selected even I can't see it). Is it any way to fix this? Thank you so much guys for the help! It's been quite a time since I wanted to do this, and it's rather embarrassing that in the end, it was actually 2 proper lines of code.... Glad you got it working ... question, why are you set on using the "USERR3" variable? My code above sets a '*fooang* global variable which will hold your value within that session. Here's an example that should keep the selection highlighted. (defun c:foo (/ o s) (or *fooang* (setq *fooang* (angtof "45"))) (cond ((and (setq *fooang* (cond ((getangle (strcat "\nEnter rotation angle:<" (rtos (* (/ *fooang* pi) 180.0) 2 0) "> ") ) ) (*fooang*) ) ) (setq s (ssget ":L" '((0 . "INSERT")))) ) ;; (while (getpoint "\nKeep picking points to rotate: ") (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ *fooang* (vla-get-rotation o))) ) ;; ) ;; Highlight selection set (sssetfirst nil s) ;; Regen might be 'heavy' on complex drawings (vla-regen (vla-get-activedocument (vlax-get-acad-object)) 0) ) ) (princ) ) Edited April 22, 2021 by ronjonp Quote
mhupp Posted April 22, 2021 Posted April 22, 2021 (edited) 26 minutes ago, ronjonp said: why are you set on using the "USERR3" variable? My code above sets a '*fooang* global variable which will hold you value within that session. You can bring a horse to water but you can't make them drink. Plus they might have that variable tied to other lisps. Edited April 22, 2021 by mhupp Quote
Sir Lord Mr. Mac Nugget Posted April 22, 2021 Author Posted April 22, 2021 (edited) 1 hour ago, ronjonp said: question, why are you set on using the "USERR3" variable? That is a great question! An the answer is as sad as "It's the only way I knew (at that time)" (I now realize *fooang* was a new global variable, I thought it was a lisp internal one) As you could witness my skill set with lisp is extremely poor, but keep trying! For example (And before I test the new code), I got greedy with my new superpower, and added a function to rotate in the opposite direction (basically subtract the new angle rather than add, because my variable could not be negative for the initget 6, which again, didn't knew why it was there...). like this: (duplicating functions) ;---------Rotate USERR3's angle--------- (defun c:foo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) ;for multiple objects? Clever! (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (getvar "USERR3") (vla-get-rotation o))) ) ) (sssetfirst nil s) ;Keep stuff selected? (not seems to be working) (princ) ) ;---------counter-Rotate USERR3's angle--------- (defun c:cfoo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (- (vla-get-rotation o) (getvar "USERR3"))) ;Important to change order! ) ) (sssetfirst nil s) ;Keep stuff selected? (not seems to be working) (princ) ) The immediate thought (after realizing the subtraction order matters) has been: Will it be worth it to combine it in one unique LISP? I could make a new variable, assign "+" or "-" to it, and put it in the last formula, then the macro would be "^C^C_foo;+;" or "^C^C_foo;-;". Is there any advantage on this? And then I realized that I don't know how to make several of this steps.... So, now is a good time I guess: Is worth grouping functions like these? Has it any impact in the performance or something similar? In your example have the variable acquisition and the rotation in the same function. I'd personally prefer it in the same function, but also personally don't know how to do it... How do I make the symbol on (+ A B) tied to a variable? Is there any easier way to change direction? For the USERR3 variable, I assume that 90% of the time the function will be used to rotate 90º, and, as long as I don't want to be asked the angle every time but also want to have the option to make it 45º once in a while, I decided to store it in a variable (I set a value one time, and never ask me. If I want to change, I can change it). Now, knowing that is possible to declare new global one I will adopt your proposition (less chances of anything interfering). Which I'm assuming is why you use asterisks...? like *fancy_variable_name*? 1 hour ago, mhupp said: You can bring a horse to water but you can't make them drink. In my case would be more like "You can bring a horse to water, but as it doesn't know what water is for, now is drinking earth and looking very confused" The new code: such rotation, much wow 1 hour ago, ronjonp said: (defun c:foo (/ o s) (or *fooang* (setq *fooang* (angtof "45"))) (cond ((and (setq *fooang* (cond ((getangle (strcat "\nEnter rotation angle:<" (rtos (* (/ *fooang* pi) 180.0) 2 0) "> ") ) ) (*fooang*) ) ) (setq s (ssget ":L" '((0 . "INSERT")))) ) ;; (while (getpoint "\nKeep picking points to rotate: ") (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ *fooang* (vla-get-rotation o))) ) ;; ) ;; Highlight selection set (sssetfirst nil s) ;; Regen might be 'heavy' on complex drawings (vla-regen (vla-get-activedocument (vlax-get-acad-object)) 0) ) ) (princ) ) This works great! And in both directions!!! But it asks me the angle every time. In your "awesome-gif-I-also-wanna" you can rotate several times after putting 25 for example. I can't manage to do it. What I can do, is make a macro: ^C^C_foo;90; ^C^C_foo;-90; tied to the shortcuts. I won't be able to change the angle, but the 10% of the times I need another angle, I can use the foo function and not be such a lazy ass... Other than that, works like charm! (pressing multiple times SHIFT+R and CTRL+R): How great is that!? Look it spin! You guys rock, thank you so much for decreasing my noobnes level! (plus now I know how to make screen-gifs... what a day!) Edited April 22, 2021 by Sir Lord Mr. Mac Nugget Quote
Sir Lord Mr. Mac Nugget Posted April 22, 2021 Author Posted April 22, 2021 Okey, my lazy and greedy mind is now asking... Could it be possible to do it while dragging a grip? Like this: Sorry to give such work!!! Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 (edited) 3 hours ago, Sir Lord Mr. Mac Nugget said: That is a great question! An the answer is as sad as "It's the only way I knew (at that time)" (I now realize *fooang* was a new global variable, I thought it was a lisp internal one) As you could witness my skill set with lisp is extremely poor, but keep trying! For example (And before I test the new code), I got greedy with my new superpower, and added a function to rotate in the opposite direction (basically subtract the new angle rather than add, because my variable could not be negative for the initget 6, which again, didn't knew why it was there...). like this: (duplicating functions) ;---------Rotate USERR3's angle--------- (defun c:foo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) ;for multiple objects? Clever! (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (getvar "USERR3") (vla-get-rotation o))) ) ) (sssetfirst nil s) ;Keep stuff selected? (not seems to be working) (princ) ) ;---------counter-Rotate USERR3's angle--------- (defun c:cfoo (/ o s) (if (setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (- (vla-get-rotation o) (getvar "USERR3"))) ;Important to change order! ) ) (sssetfirst nil s) ;Keep stuff selected? (not seems to be working) (princ) ) The immediate thought (after realizing the subtraction order matters) has been: Will it be worth it to combine it in one unique LISP? I could make a new variable, assign "+" or "-" to it, and put it in the last formula, then the macro would be "^C^C_foo;+;" or "^C^C_foo;-;". Is there any advantage on this? And then I realized that I don't know how to make several of this steps.... So, now is a good time I guess: Is worth grouping functions like these? Has it any impact in the performance or something similar? In your example have the variable acquisition and the rotation in the same function. I'd personally prefer it in the same function, but also personally don't know how to do it... How do I make the symbol on (+ A B) tied to a variable? Is there any easier way to change direction? For the USERR3 variable, I assume that 90% of the time the function will be used to rotate 90º, and, as long as I don't want to be asked the angle every time but also want to have the option to make it 45º once in a while, I decided to store it in a variable (I set a value one time, and never ask me. If I want to change, I can change it). Now, knowing that is possible to declare new global one I will adopt your proposition (less chances of anything interfering). Which I'm assuming is why you use asterisks...? like *fancy_variable_name*? In my case would be more like "You can bring a horse to water, but as it doesn't know what water is for, now is drinking earth and looking very confused" The new code: such rotation, much wow This works great! And in both directions!!! But it asks me the angle every time. In your "awesome-gif-I-also-wanna" you can rotate several times after putting 25 for example. I can't manage to do it. What I can do, is make a macro: ^C^C_foo;90; ^C^C_foo;-90; tied to the shortcuts. I won't be able to change the angle, but the 10% of the times I need another angle, I can use the foo function and not be such a lazy ass... Other than that, works like charm! (pressing multiple times SHIFT+R and CTRL+R): How great is that!? Look it spin! You guys rock, thank you so much for decreasing my noobnes level! (plus now I know how to make screen-gifs... what a day!) Glad you're picking this up .. see if this makes sense to you: (defun _myrotator (a / o s) ; ( a / <- is an angle argument to feed the function (cond ((setq s (ssget ":L" '((0 . "INSERT")))) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (* pi (/ a 180.0)) (vla-get-rotation o)) ) ) (sssetfirst nil s) ;; Regen might be 'heavy' on complex drawings ;; (vla-regen (vla-get-activedocument (vlax-get-acad-object)) 0) ) ) (princ) ) ;; Can be manipulated like so defining 4 different functions with 4 different angles (defun c:r1 nil (_myrotator 90)) (defun c:r2 nil (_myrotator -90)) (defun c:r3 nil (_myrotator 45)) (defun c:r4 nil (_myrotator -45)) Edited April 22, 2021 by ronjonp Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 1 hour ago, Sir Lord Mr. Mac Nugget said: Okey, my lazy and greedy mind is now asking... Could it be possible to do it while dragging a grip? Like this: Sorry to give such work!!! If you call the above functions transparently use ' it can be done like so although not sure what is accomplishes 1 Quote
Sir Lord Mr. Mac Nugget Posted April 22, 2021 Author Posted April 22, 2021 (edited) Boooom! Works perfectly! I had to change to radians de 4 functions, and I'm afraid I have more noob questions: (defun c:r1 nil (_myrotator (/ pi 2))) (defun c:r2 nil (_myrotator (* (/ pi 2) -1))) (defun c:r3 nil (_myrotator (/ pi 4)) (defun c:r4 nil (_myrotator (* (/ pi 4) -1))) If I wrote: (defun c:r2 nil (_myrotator -(/ pi 2))) Doesn't work (hence my -1 multiplication....). Any proper way to change to negative? @ronjonp, you were right with the regen being heavy, commented it away. Being able to rotate it while dragging kind of eliminates the need for the grip upon placing (which seems to appear anyway!). And it has a bonus feat: if you ESC away before placing the object, It resets the rotation. 2x1! You earned heaven today, so many thanks! Edited April 22, 2021 by Sir Lord Mr. Mac Nugget Quote
ronjonp Posted April 22, 2021 Posted April 22, 2021 8 minutes ago, Sir Lord Mr. Mac Nugget said: Boooom! Works perfectly! I had to change to radians de 4 functions, and I'm afraid I have more noob questions: (defun c:r1 nil (_myrotator (/ pi 2))) (defun c:r2 nil (_myrotator (* (/ pi 2) -1))) (defun c:r3 nil (_myrotator (/ pi 4)) (defun c:r4 nil (_myrotator (* (/ pi 4) -1))) If I wrote: (defun c:r2 nil (_myrotator -(/ pi 2))) Doesn't work (hence my -1 multiplication....). Any proper way to change to negative? @ronjonp, you were right with the regen being heavy, commented it away. Being able to rotate it while dragging kind of eliminates the need for the grip upon placing (which seems to appear anyway!). And it has a bonus feat: if you ESC away before placing the object, It resets the rotation. 2x1! You earned heaven today, so many thanks! I updated the function above so you can feed it degrees rather than radians. (+ (* pi (/ a 180.0)) (vla-get-rotation o)) As for the negative number you were close: (defun c:r2 nil (_myrotator (- (/ pi 2)))) 1 Quote
mhupp Posted April 23, 2021 Posted April 23, 2021 Stupid question what are you using to make the gifs? Also another route to go rather then typing r1, r2, r3, r4 is to adapt this macro to your needs. this would bundle all the commands into one so you could use any of them without having to exit. like if you over rotated rather then going round the horn hit another key to rotate it back. or getting to 225 is just hit 90 twice and then 45 once rather then the 45 command 5 times. https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/nudge/m-p/1044057/highlight/true#M150891 ;; key 1 = Rotate 90 ((= key 49) (_myrotator (/ pi 2))) ) ;; key 2 = Rotate -90 ((= key 50) (_myrotator (- (/ pi 2)))) ) and so on Quote
ronjonp Posted April 23, 2021 Posted April 23, 2021 5 hours ago, mhupp said: Stupid question what are you using to make the gifs? Also another route to go rather then typing r1, r2, r3, r4 is to adapt this macro to your needs. this would bundle all the commands into one so you could use any of them without having to exit. like if you over rotated rather then going round the horn hit another key to rotate it back. or getting to 225 is just hit 90 twice and then 45 once rather then the 45 command 5 times. https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/nudge/m-p/1044057/highlight/true#M150891 ;; key 1 = Rotate 90 ((= key 49) (_myrotator (/ pi 2))) ) ;; key 2 = Rotate -90 ((= key 50) (_myrotator (- (/ pi 2)))) ) and so on I use SnagIt for screen captures \ animated gifs .. as far as grread options here's a quick example: (defun c:foo (/ a b gr k m o s) (setq m "\rA=-90 S=90 D=-45 F=45 SPACEBAR TO EXIT!") (cond ((setq s (ssget ":L" '((0 . "INSERT")))) (princ m) (while (and (not b) (setq gr (grread))) ;; (princ gr) (if (and (= 2 (car gr)) (setq a (cond ((= "A" (setq k (strcase (chr (cadr gr))))) -90) ((= "S" k) 90) ((= "D" k) -45) ((= "F" k) 45) ;; Exit on spacebar ((wcmatch k " ") (setq b 0)) (0) ) ) ) (foreach e (vl-remove-if 'listp (mapcar 'cadr (ssnamex s))) (vla-put-rotation (setq o (vlax-ename->vla-object e)) (+ (* pi (/ a 180.0)) (vla-get-rotation o)) ) ) ) ) ) ) (princ) ) 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.