Repeat an autoCAD command for selected objects

Repeat an autoCAD command for selected objects

Anonymous
Not applicable
4,043 Views
10 Replies
Message 1 of 11

Repeat an autoCAD command for selected objects

Anonymous
Not applicable

Does anyone have a lisp file or could make one to repeat an autoCAD command on a selection set. 

I use (setq ss1 (ssget '((0 . "IMAGE")))) to select all of my images. Then, I want to use 

(command "IMAGECLIP" "N" "S")

 

AutoCAD understands all of this together, but it will not repeat the image clip command on the entire selection set. It will only do it one time and then exit. I have the actual lisp routine below. I have tried to modify this to repeat, but I can not get it to work.

 

(defun c:ttt ()
   (command "IMAGECLIP"
              (princ
                  (setq ss1 (ssget '((0 . "IMAGE")))
                  )
              )       
               "N" "S"
   )
   (princ)
)

 

0 Likes
Accepted solutions (1)
4,044 Views
10 Replies
Replies (10)
Message 2 of 11

ВeekeeCZ
Consultant
Consultant
Accepted solution

Try this, but... it doesn't make a lot of sence to me... you still need to select a polyline as new boundary for each image, right? So I've added the ZOOM to current image which for you need to select new clip edge.

 

(defun c:ttt ( / ss i en)
  (if (setq ss (ssget '((0 . "IMAGE"))))
    (repeat (setq i (sslength ss))
      (setq en (ssname ss (setq i (1- i))))
      (command "_.ZOOM" "_Ob" en "")
      (command-s "_.IMAGECLIP" en "N" "S")))
   (princ)
)
Message 3 of 11

Anonymous
Not applicable

This pretty much did what I needed. I like the ZOOM feature, as well. I also took what you wrote and used it for deleting the clip. I was able to get it to delete all of the clipped images at once. See below for the LISP file. Eventually, I want to get it to where I can click all images and clip them to whatever polyline they are touching in go. Maybe I will have to create a second selection set and select the polylines and add that after the                  (command-s "_.IMAGECLIP" en "N" "S" ?). 

 

(defun c:D ( / ss i en)
(if (setq ss (ssget '((0 . "IMAGE"))))
(repeat (setq i (sslength ss))
(setq en (ssname ss (setq i (1- i))))
(command "_.IMAGECLIP" en "_D")))
(princ)
)

0 Likes
Message 4 of 11

ВeekeeCZ
Consultant
Consultant

@Anonymous wrote:

...Eventually, I want to get it to where I can click all images and clip them to whatever polyline they are touching in go. Maybe I will have to create a second selection set and select the polylines and add that after the ...


First, you need to analyze behavior of the IMAGECLIP command in context of what you have and need. Find what possible, where the command fails?! Rather post some sample file with couple of images and new clip-boundaries... (zip?)

 

BTW Its kind of complicated to get coordinates of IMAGE (eg. see HERE, unfortunately not complete) to select possible POLYLINE laying above to clip. And the IMAGECLIP command fails if you supply a boundary (one or more polylines) within selection-set which is/are laying totally outside the image.

 

Possibly the other way around would be easier - select all PL boundaries, check one by one if any IMAGEis laying above, and if there is one and only one, then clip it.

 

0 Likes
Message 5 of 11

ВeekeeCZ
Consultant
Consultant

@ВeekeeCZ wrote:

... Possibly the other way around would be easier - select all PL boundaries, check one by one if any IMAGEis laying above, and if there is one and only one, then clip it. ...

 


Well, I've tried that, but failed. You can try it too on your dwg

 

It fails when whole pl-boundary is inside of a image (= not clossing the image frame anyhow) - it won't reselect the image :(.

 

(vl-load-com)

(defun c:ttt ( / ss ssp ssg en i)

  (princ "\nImages and closed polylines required, ")
  (if (and (setq ss (ssget '((-4 . "<OR") (0 . "IMAGE") (-4 . "<AND") (0 . "LWPOLYLINE") (-4 . "&=") (70 . 1) (-4 . "AND>") (-4 . "OR>"))))
	   (setq ssp (ssget "_P" '((0 . "LWPOLYLINE"))))
	   (sssetfirst nil ss)
	   (setq ssg (ssget "_I" '((0 . "IMAGE"))))
	   )
    (progn
      (sssetfirst nil nil)
      
      (repeat (setq i (sslength ssg))
	(setq en (ssname ssg (setq i (1- i))))
	(command "_.IMAGECLIP" en "_D"))

      (command "_.ZOOM" "_Ob" ssp "")
      
      (repeat (setq i (sslength ssp))
	(setq en (ssname ssp (setq i (1- i))))
	(and (setq ss (ssget "_CP" (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= 10 (car x))) (entget en))) '((0 . "IMAGE"))))
	     (= (sslength ss) 1)
	     (command "_.IMAGECLIP" (ssname ss 0) "_N" "_S" en)))))
  (princ)
)
0 Likes
Message 6 of 11

Anonymous
Not applicable

I checked this and for the most it does work, but only when the circumstances are perfect. You're right if the entire boundary is inside of the image then it fails. It also fails if there is only one boundary for multiple images. 

 

Is it possible to create an (if) within a (setq).

Meaning, 

(if (setq en (ssname ssp (setq i (1- i))))
(or
(setq en (= 1 (sslength ssp)))

 

What is happening is it subtract that one polyline every time it clips. So, if I have 1 polyline then 1-1=0 and 0 means no more polylines to clip to.

 

Would I be better off re-writing the "clipit' LISP file?

0 Likes
Message 7 of 11

ВeekeeCZ
Consultant
Consultant

Sure you can use the if....

 

(if (= (sslength ssp) 1)
        
        (command "_.IMAGECLIP" (ssname ss 0) "_N" "_S" (ssname ssp 0))

        (repeat (setq i (sslength ssp))
          (setq en (ssname ssp (setq i (1- i))))
          (and (setq ss (ssget "_CP" (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= 10 (car x))) (entget en))) '((0 . "IMAGE"))))
               (= (sslength ss) 1)
               (command "_.IMAGECLIP" (ssname ss 0) "_N" "_S" en))))

 

0 Likes
Message 8 of 11

Anonymous
Not applicable

So, I have been writing a few different types for what we have discussed and I managed to make the following LISP work once and since have not made it work. I am attaching the file and a DWG with images to try it out if you want. I think this LISP needs an IF to mange the multiple polylines or a single polyline. 

 

I was thinking about how IMAGECLIP can not clip one image to multiple polylines, so I tried a copy command with it and made it clip to multiple polylines. 

 

I am really struggling with my novice skills and combining multiple successful LISP files.

0 Likes
Message 9 of 11

ВeekeeCZ
Consultant
Consultant

OK, so correct me if I am wrong

 

- you have a carpet texture image presented at dwg, placed somewhere aside, un-clipped (or to be de-clipped) ready to be copied and clipped to new frame. 

- the carpet image is a rectangle image 

 

- the image is laying in its final rotation which can only be vertical or horizontal

- image is at correct scale 

- target frame would be also always rectangle (or even a square?)

- if the target frame is larger than the image, then is combined from multiple copies of selected image (= texture would not be scaled)

= then the workflow requires to make a selection of a SINGLE image and MANY frames (or one frame of course).

 

- if you need to do this for multiple different carpets, you would repeat the selection, right?

 

0 Likes
Message 10 of 11

ВeekeeCZ
Consultant
Consultant

This code works for conditions mentioned above...

 

(vl-load-com)

(defun c:ImageClipMultiple ( /
			    *error* LM:boundingbox1 LM:boundingbox2
			    adoc ss Ien Pss Ipt Idx Idy n Ppt Pid Pdy x Iss y  i en enl Tss)
  
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break,end"))
      (princ (strcat "\nError: " errmsg)))
    (if cmd (setvar 'CMDECHO cmd))
    (vla-endundomark adoc)
    (princ))
  
  ;; http://www.lee-mac.com/boundingbox.html 
  ;; Bounding Box  -  Lee Mac
  ;; Returns the point list describing the rectangular frame bounding the supplied object
  ;; obj - [vla] VLA-Object
  
  (defun LM:boundingbox1 ( obj / a b lst )
    (if (and (vlax-method-applicable-p obj 'getboundingbox)
	     (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'a 'b))))
	     (setq lst (mapcar 'vlax-safearray->list (list a b)))
	     )
      (mapcar '(lambda ( a ) (mapcar '(lambda ( b ) ((eval b) lst)) a))
	      '((caar   cadar)
		(caadr  cadar)
		(caadr cadadr)
		(caar  cadadr)))))
  
  ;; http://www.lee-mac.com/boundingbox.html ; -- adjusted --
  ;; Returns (ll dx dy)
  ;; obj - [vla] VLA-Object
  
  (defun LM:boundingbox2 ( obj / a b lst )
    (if (and (vlax-method-applicable-p obj 'getboundingbox)
	     (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'a 'b))))
	     (setq lst (mapcar 'vlax-safearray->list (list a b)))
	     )
      (list (car lst)
	    (abs (- (caadr lst) (caar lst)))
	    (abs (- (cadadr lst) (cadar lst))))))
  
  ; -------------------------------------------------------------------------------------------------------------
  ; -------------------------------------------------------------------------------------------------------------

  (vla-endundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  (vla-startundomark adoc)
  
  (princ "\nSingle image and closed polyline(s) required, ")
    
  (if (and (setq ss (ssget '((-4 . "<OR") (0 . "IMAGE") (-4 . "<AND") (0 . "LWPOLYLINE") (-4 . "&=") (70 . 1) (-4 . "AND>") (-4 . "OR>"))))
	   (or (setq Ien (ssget "_P" '((0 . "IMAGE"))))
	       (prompt "\nError: No image selected. One image required be selected."))
	   (or (= 1 (sslength Ien))
	       (prompt "\nError: Too many images selected. Only one image can be selected."))
	   (setq Ien (ssname Ien 0))
	   
	   (sssetfirst nil ss)
	   (or (setq Pss (ssget "_I" '((0 . "LWPOLYLINE"))))
	       (prompt "\nError: No closed polyline selected. At least one required."))
	   
	   (setq cmd (getvar 'CMDECHO))
	   (setvar 'CMDECHO 0)
	   (vl-cmdf "_.IMAGECLIP" Ien "_D") 	; delete clip if needed
	   (not (command))			; make sure no command is active
	   
	   (setq Ipt (LM:boundingbox2 (vlax-ename->vla-object Ien)))    ; get list of lower-left point (insertion pnt), delta x (width) and delta y (height) of IMAGE
	   (setq Idx (cadr Ipt)						; put above into its variables
		 Idy (last Ipt)
		 Ipt (car Ipt))
	   )
    
    (repeat (setq n (sslength Pss))					; for each polyline
      
      (setq Pen (ssname Pss (setq n (1- n)))
	    Ppt (LM:boundingbox2 (vlax-ename->vla-object Pen))		; ; get list of lower-left point (insertion pnt), delta x (width) and delta y (height) of polyline
	    Pdx (cadr Ppt)
	    Pdy (last Ppt)
	    Ppt (car Ppt))
      
      (setq x 0
	    Iss (ssadd))
      
      (while (< x Pdx)
	(command "_.COPY" Ien "" "_none" Ipt "_none" (list (+ (car Ppt) x) (cadr Ppt)))		; copy image to X direction until width of n-times image is less than width of pl
	(ssadd (entlast) Iss)									; collect all new images into a selection-set
	(setq x (+ x Idx)))
      
      (setq y Idy)
      (command "_.SELECT" Iss "")
      
      (while (< y Pdy)
	(setq enl (entlast))
	(command "_.COPY" "_P" "" "_none" Ppt "_none" (list (car Ppt) (+ (cadr Ppt) y)))	; same as above to y direction
	(while (setq enl (entnext enl))
	  (ssadd enl Iss))
	(setq y (+ y Idy)))
      
      (repeat (setq i (sslength Iss))								; for all new instances of image
	(and (setq en  (ssname Iss (setq i (1- i))))
	     (setq Tss (ssget "_CP" (LM:boundingbox1 (vlax-ename->vla-object en)) '((0 . "LWPOLYLINE")))) 	; select all polylines using cross-polygon type of sel and point of its bounding box
	     (ssdel Pen Tss)											; if there is our polylines between selected polylines = meaning a pl-clip-boundary is INSIDE or CROSSING image bounding box, never outside
	     (command "_.IMAGECLIP" en "_N" "_S" Pen)))))							; then clipp it.
  (*error* "end")
  )
0 Likes
Message 11 of 11

Anonymous
Not applicable

So to answer these questions. A lot of that is correct. I will explain (or try to) in further detail.

I use the image of the carpet in multiple rooms and I use more than one of the same image in a single room. There is no perfect or same scenario for this.

Scenario 1: I have a ballroom floor plan that is 96'W x 120'L I take one image  and copy it or I take multiple different images and place them across the width and length to cover the entire area. Then I clip each image to that single polyline. 

Scenario 2: I have a ballroom and corridor floor plan. The ballroom and corridor touch and will be the same carpet, but the boundary box can not be the same (this is for estimating purposes). I take the same image and copy it on top of each other and copy the images to the correct bounding box.

Scenario 3: I have a guestroom and corridor floor plan. Both of these areas will use different carpet images. I place each image to its correct polyline, then select all images and polylines and clip it to the corresponding polyline.

 

Do these make sense?

 

This LISP works well on scenario 1 if the image is the same. it even works well with different images other than it copies the selected images and clips them, but does not clip the selected images.

This is also great for scenario 2. No problems with that, except it does not clip the selected image. Only the copy.

This could potentially work for scenario 3, but there would be a lot of deleting involved. So, it is a little counter productive.

 

I would like to say you have really helped me out beyond measures and I really appreciate the help. Reading your LISP files have also taught me a lot and allowed me to realize that autoLISP makes autoCAD virtually limitless.

 

You are in no way obligated to keep writing the files for this and again your help is greatly appriciated. 

 

0 Likes