Move or copy objects in the X or Y direction with a specific distance.

Move or copy objects in the X or Y direction with a specific distance.

ancrayzy
Advocate Advocate
1,693 Views
15 Replies
Message 1 of 16

Move or copy objects in the X or Y direction with a specific distance.

ancrayzy
Advocate
Advocate

I found this Lisp at www.cadtutor.net
https://www.cadtutor.net/forum/topic/66001-move-objects-specific-distance/

 

(defun c:up50 (/ ss)
  (if (setq ss (ssget "_:L-I"))
    (command "_.MOVE" ss "" "_non" '(0. 0.) "_non" '(0. 5000.))
  )
  (princ)
)

 

 

Is there any way to upgrade this lisp with the following features:

Step 1. Type the command: move/copy in X or Y direction
For example:
- Move in X direction: Move_X
- Move in Y direction: Move_Y
- Copy in X direction: Copy_X
- Copy in Y direction: Copy_Y

Step 2. Type the distance to move/copy (mm) and enter or enter to skip with default distance is 1000mm).

Step 3. Select objects -> enter to execute.

Step 4. When repeat the command, the distance entered in step 2 will be replaced the default distance (1000mm) for the next steps.

0 Likes
Accepted solutions (3)
1,694 Views
15 Replies
Replies (15)
Message 2 of 16

Sea-Haven
Mentor
Mentor

Try this written like 30 years ago.

 

(defun C:CHX ()
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (setq x 0)
  (princ "\nalters object in X direction")
  (setq ht (getstring "\n What is amount of change: "))
  (setq newht (strcat ht ",0"))
  (while (= x 0)
    (setq newobj (entsel "\nPoint to object: "))
    (if (/= newobj nil)
    (progn
    (command "move" newobj "" "0,0" newht)
    ))
  (if (= newobj nil)(setq x 1))
  )
)
;
(defun C:CHY ()
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (setq x 0)
  (princ "alters object in Y direction")
  (setq ht (getstring "\n What is amount of change: "))
  (setq newht (strcat  "0," ht))
  (while (= x 0)
  (SETQ NEWobj (entsel "\nPoint to object: "))
  (if (/= newobj nil)
  (progn
  (command "move" newobj "" "0,0" newht)
  ))
  (if (= newobj nil)(setq x 1))
  )
  )
Message 3 of 16

ancrayzy
Advocate
Advocate

Thanks Sea-Haven,
Is there a way to modify this lisp so that the "Point to object" section becomes "Select objects" (Drag to select multiple objects at the same time). And add copy function instead of just move.

0 Likes
Message 4 of 16

ancrayzy
Advocate
Advocate

Thank for your code @Sea-Haven.

I use AI to modify your code to create the lisp which I need and share it with anyone who needs it as below.

But if anyone has any other and more optimal ideas, please still share them with us

 

;;;; https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/move-or-copy-objects-in-the-x-or-y-direction-with-a-specific/td-p/12690641

(defun C:CHY ( / sn ht newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (princ "alters object in Y direction")
  (setq ht (getstring "\n What is the amount of change: "))
  (setq newht (strcat "0," ht))
  (while (setq newobj (ssget '((0 . "*")))) ; Select objects
    (command "copy" newobj "" "0,0" newht) ; Copy objects
  )
  (setvar 'osmode sn)
  (princ)
)

(defun C:CHX ( / sn ht newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (princ "\nalters object in X direction")
  (setq ht (getstring "\n What is the amount of change: "))
  (setq newht (strcat ht ",0"))
  (while (setq newobj (ssget '((0 . "*")))) ; Select objects
    (command "copy" newobj "" "0,0" newht) ; Copy objects
  )
  (setvar 'osmode sn)
  (princ)
)

(defun C:MHY ( / sn ht newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (princ "alters object in Y direction")
  (setq ht (getstring "\n What is the amount of change: "))
  (setq newht (strcat "0," ht))
  (while (setq newobj (ssget '((0 . "*")))) ; Select objects
    (command "move" newobj "" "0,0" newht) ; Move objects
  )
  (setvar 'osmode sn)
  (princ)
)

(defun C:MHX ( / sn ht newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (princ "\nalters object in X direction")
  (setq ht (getstring "\n What is the amount of change: "))
  (setq newht (strcat ht ",0"))
  (while (setq newobj (ssget '((0 . "*")))) ; Select objects
    (command "move" newobj "" "0,0" newht) ; Move objects
  )
  (setvar 'osmode sn)
  (princ)
)

 

0 Likes
Message 5 of 16

paullimapa
Mentor
Mentor

Seems like you're still missing this step in your code:

Step 4. When repeat the command, the distance entered in step 2 will be replaced the default distance (1000mm) for the next steps.

Also I noticed AI chose to use this line of code for ssget:

(ssget '((0 . "*")))

Since you're not filtering out any objects but you want to select all kinds of objects, there's no need to indicate a wildcard but instead you can just use this:

(ssget)

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
Message 6 of 16

TomBeauford
Advisor
Advisor

With ORTHO on use either MOVE or COPY with the cursor locked in whatever X or Y direction you want and enter the distance. Whatever distance you enter will be the default the next time so if you're using the same distance just hit enter.

64bit AutoCAD Map & Civil 3D 2023
Architecture Engineering & Construction Collection
2023
Windows 10 Dell i7-12850HX 2.1 Ghz 12GB NVIDIA RTX A3000 12GB Graphics Adapter
Message 7 of 16

ancrayzy
Advocate
Advocate

Your are right@paullimapa ,

It's okay to solve my problem for now. But it would be great if this lisp was added section at Step 4

(When repeat the command, the distance entered in step 2 will be replaced the default distance (1000mm) for the next steps).

0 Likes
Message 8 of 16

paullimapa
Mentor
Mentor
Accepted solution

Setup a global variable and include this in the statement to enter the new change value...

Here's the changed code on one of the routines...you should be able to implement on the others:

(defun C:CHY ( / sn ht newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (command "osnap" "near")
  (princ "alters object in Y direction")
;  (setq ht (getstring "\n What is the amount of change: "))
;  (setq newht (strcat "0," ht))
  (if(not *ht*)(setq *ht* 1000)) ; setup global variable
  (setq ht (getdist (strcat"\nWhat is the amount of change <" (rtos *ht* 2 0) ">: "))) ; getdist can enter & point distance on screen
  (if(not ht)(setq ht *ht*)(setq ht (fix ht) *ht* ht)) ; 0 decimal precision
  (setq newht (strcat "0," (itoa ht))) ; convert integer to string
  (while (setq newobj (ssget)) ; Select objects
    (command "copy" newobj "" "0,0" newht) ; Copy objects
  )
  (setvar 'osmode sn)
  (princ)
)

 


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
Message 9 of 16

ancrayzy
Advocate
Advocate

It's perfect, thanks you Mr @paullimapa 

0 Likes
Message 10 of 16

paullimapa
Mentor
Mentor

glad to have helped...cheers!!!


Paul Li
IT Specialist
@The Office
Apps & Publications | Video Demos
Message 11 of 16

Sea-Haven
Mentor
Mentor

 My take on task with updated input dcl entry.

 

 

(defun C:CHY ( / sn  newobj)
  (SETVAR "CMDECHO" 0)
  (setq sn (getvar "osmode"))
  (setvar 'osmode 512)
  (if (not AH:getvalsm)(load "Multi Getvals.lsp"))
  (if (not *ht*)(setq *ht* 1000.0))
  (setq *ht* (atof (car (AH:getvalsm (list "Enter value " "Y dist " 7 6 (rtos *ht* 2 1))))))
(princ "\nPress Enter after selecting objects ")
    (while (setq newobj (ssget))
    (command "copy" newobj "" "0,0" (list 0 *ht*))
(princ "\nSelect objects or press Enter to exit ")
    )
  (setvar 'osmode sn)
  (princ)
)

 

 

SeaHaven_0-1712639718363.png

 

Message 12 of 16

ancrayzy
Advocate
Advocate

Thank you @Sea-Haven 

I saved your code as CHY.lsp

I successfully loaded lisp CHY.lsp

But when loading the Multi GETVALS.lsp file, it gives the following error as below:

Command: CHY ; error: LOAD failed: "Multi Getvals.lsp"
APPLOAD Multi GETVALS.lsp successfully loaded.
Command: ; error: extra right paren on input

 

0 Likes
Message 13 of 16

Sea-Haven
Mentor
Mentor
Accepted solution

Ok I have a few copies of the program and may have pasted an incorrect one try this one. I sometimes edit to suit a particular requirement.

 

 

Message 14 of 16

ancrayzy
Advocate
Advocate
It works perfectly, thank you so much !
0 Likes
Message 15 of 16

Kent1Cooper
Consultant
Consultant
Accepted solution

Here's a way to do it in which:

1.  A single default distance is available in all commands -- if you want to go left by a distance you just went right, so the default is positive X, you don't need to re-enter the same distance with a preceding minus sign, but can just use the leftward command and the same default distance.

2.  You don't even need to know that X values are in the left-right direction and Y in the up-down directions, nor which way is positive and which negative in each direction -- it uses [abbreviations for] Up/Down/Left/Right as directions you want to Move or Copy things.

3.  They work with pre-selection [noun-verb mode] if there is one; otherwise they ask you to select objects.

4.  The "heavy lifting" is spelled out only once, instead of most of it repeatedly within multiple command definitions.  The different commands just feed a couple of arguments to the one sub-routine.

5.  [I don't see any reason it should be restricted to whole-number values -- these accept decimals, fractions, feet-and-inches.]

 

(defun MorCO (MorC dir / dirs ss) ; = Move or Copy Orthogonally
  (initget 2); no zero
  (setq
    dirs '((0.5 "up") (1.5 "down") (1 "left") (0 "right")); directions as multiples of pi
    *MorCdisp* ; global variable [Move or Copy displacement, in drawing units]
    (cond
      ( (getdist
          (strcat
            "\nDistance to " MorC " object(s) " (cadr (assoc dir dirs)) " <"
            (rtos (cond (*MorCdisp*) (100))); in current mode/precision <--EDIT desired initial default
            ">: "
          ); strcat
        ); getdist
      ); User-entry condition
      (*MorCdisp*); prior value if present, on Enter
      (100); default on Enter at first use <--EDIT desired initial default
    ); cond
  ); setq
  (cond
    ((setq ss (ssget "_:L-I")); pre-selection of object(s) not on locked Layer(s)
      (sssetfirst nil); un-select [now in ss variable]
    ); pre-selection condition
    ((setq ss (ssget "_:L"))); no pre-selection -- ask User
  ); cond
  (command (strcat "_." MorC) ss "" "_displacement" (polar '(0 0) (* pi dir) *MorCdisp*))
  (prin1)
)

(defun C:MMU () (MorCO "Move" 0.5)); = Move Up

(defun C:MMD () (MorCO "Move" 1.5)); = Move Down

(defun C:MML () (MorCO "Move" 1)); = Move Left

(defun C:MMR () (MorCO "Move" 0)); = Move Right

(defun C:CCU () (MorCO "Copy" 0.5)); = Copy Up

(defun C:CCD () (MorCO "Copy" 1.5)); = Copy Down

(defun C:CCL () (MorCO "Copy" 1)); = Copy Left

(defun C:CCR () (MorCO "Copy" 0)); = Copy Right

 

I used command names with double M's or C's before the directional letters, because ML is already AutoCAD's default command alias for MLINE, and I use CL and CR for other things.  But you can use whatever command names make sense for you.

Kent Cooper, AIA
Message 16 of 16

ancrayzy
Advocate
Advocate

Thank you for your very detailed explanation.

I tried your new lisp above. It does not keep the last distance entered previously corresponding to each command but uses the last distance entered by the user enter as previous code you shared which use with Multi GETVALS.lsp

0 Likes