Jump to content

Select object with the highest elevation


Stegee137

Recommended Posts

I have a drawing that contains 1000's of LWPOLYLINES (with elevation) and CIRCLES (with thickness). I use the following LISP routine that I found a while ago on another forum to find the highest elevation/thickness value within a selection. 

 

(defun c:Max (/ ss i a b lst)
  (if (setq ss (ssget))
    (progn (repeat (setq i (sslength ss))
             (vla-getboundingbox (vlax-ename->vla-object (ssname ss (setq i (1- i)))) 'a 'b)
             (setq lst (cons (caddr (vlax-safearray->list a))
                             (cons (caddr (vlax-safearray->list b)) lst)
                       )
             )
           )
           (alert (strcat "Maximum Elevation: "
                          (rtos (apply 'max lst))
                  )
           )
    )
  )
  (princ)
)

The LISP works well but what I would like to be able to do is select all lines and/or circles with the maximum elevation within my selection area. Do any of you guys know how I might be able to adapt the LISP above to do this?

 

Many thanks

Link to comment
Share on other sites

(defun c:MaxZ( / ss0 ls i Zmax)
  (setq ss0 (ssget (list (cons 0 "Lwpolyline"))) ls nil i -1)
  (repeat (sslength ss0)
    (setq ls (cons (ssname ss0 (setq i (1+ i))) ls)))
  (setq ls1 (vl-sort ls (function (lambda (a b) (> (cdr (assoc 38 (entget a))) (cdr (assoc 38 (entget b))))))))
  (setq Zmax (cdr (assoc 38 (entget (car ls1)))) ss (ssadd) i -1 fuzz 0.1)
  (while (equal Zmax (cdr (assoc 38 (entget (setq en (nth (setq i (1+ i)) ls1))))) fuzz)
    (ssadd en ss))
  )

This should place all the polylines at maximum Z in the selection set ss. You may wish to adjust the fuzz distance (I set it to 0.1), so the program will find all the polylines "around" the Zmax

Link to comment
Share on other sites

Many thanks fuccaro. This only works with polylines whereas my dataset contains polylines and circles. I want to be able to select the highest object which may be a polyline (elevation) or a circle (thickness) or both. Do you think that will be possible?

Link to comment
Share on other sites

Yes, it's possible. I will change the code to add the circle things. I was waiting to see if I am walking in the right direction. I will try to do it today.

Link to comment
Share on other sites

Much appreciated fuccaro. Yes, I think so. Basically I am assessing 1000's of lines and circles. My LISP tells me what the highest value is but I need to know where it is too hence why I would like everything with that Max Z value to be selected.

Link to comment
Share on other sites

(defun c:MaxZ( / )
  (setq ss0 (ssget (list (cons 0 "Lwpolyline,circle"))) ls nil i -1)
  (repeat (sslength ss0)
    (setq en (ssname ss0 (setq i (1+ i)))
	  cir (= "CIRCLE" (cdr (assoc 0 (setq el (entget en)))))
	  elev (if cir (car (reverse (assoc 10 el))) (cdr (assoc 38 el)))
	 ls (cons (cons en elev) ls))
    )
  (setq ls1 (vl-sort ls '(lambda (a b) (> (cdr a) (cdr b)))))
  (setq Zmax (cdar ls1) ss (ssadd) i -1 fuzz 0.1)
  (while (equal Zmax (cdr (nth (setq i (1+ i)) ls1)) fuzz)
    (ssadd (car (nth i ls1)) ss))
  (princ (strcat "Max z= " (rtos Zmax)))
  (princ)
  )

 

Link to comment
Share on other sites

Thank you. I have just tried this but it is returning a max z value of 0 for all circles. It works correctly for the polylines but doesn't seem to select the polyline with the highest value afterwards. Am I doing something wrong?

Link to comment
Share on other sites

Assuming that you are genuinely referring to the thickness property of a circle (i.e. DXF group 39), as opposed to the elevation of the centre, try the following:

(defun c:selhigh ( / e i l m r s x z )
    (if (setq s (ssget '((0 . "LWPOLYLINE,CIRCLE"))))
        (progn
            (repeat (setq i (sslength s))
                (setq i (1- i)
                      e (ssname s i)
                      x (entget e)
                )
                (if (= "CIRCLE" (cdr (assoc 0 x)))
                    (setq z (cond ((cdr (assoc 39 x)))(0)))
                    (setq z (cdr (assoc 38 x)))
                )
                (if (< m z) (setq m z))
                (setq l (cons (cons z e) l))
            )
            (setq r (ssadd))
            (foreach x l
                (if (equal (car x) m 1e-8)
                    (ssadd (cdr x) r)
                )
            )
            (sssetfirst nil r)
        )
    )
    (princ)
)

 

Link to comment
Share on other sites

Sorry Lee Mac, one thing I forgot to ask - in my original LISP it had an alert to tell me what the highest value is. Is it possible to add that to this LISP?

Link to comment
Share on other sites

15 minutes ago, Stegee137 said:

That is perfect Lee Mac! Does exactly what I wanted. Many thanks!!

 

Excellent - you're most welcome.

 

11 minutes ago, Stegee137 said:

Sorry Lee Mac, one thing I forgot to ask - in my original LISP it had an alert to tell me what the highest value is. Is it possible to add that to this LISP?

 

Certainly - the following will print the value to the command-line:

(defun c:selhigh ( / e i l m r s x z )
    (if (setq s (ssget '((0 . "LWPOLYLINE,CIRCLE"))))
        (progn
            (repeat (setq i (sslength s))
                (setq i (1- i)
                      e (ssname s i)
                      x (entget e)
                )
                (if (= "CIRCLE" (cdr (assoc 0 x)))
                    (setq z (cond ((cdr (assoc 39 x)))(0)))
                    (setq z (cdr (assoc 38 x)))
                )
                (if (< m z) (setq m z))
                (setq l (cons (cons z e) l))
            )
            (setq r (ssadd))
            (foreach x l
                (if (equal (car x) m 1e-8)
                    (ssadd (cdr x) r)
                )
            )
            (princ (strcat "Maximum elevation/thickness: " (rtos m)))
            (sssetfirst nil r)
        )
    )
    (princ)
)

Change (princ (strcat ... )) to (alert (strcat ... )) if you really want a modal dialog.

Edited by Lee Mac
Link to comment
Share on other sites

  • 3 years later...
On 3/26/2020 at 3:50 PM, Lee Mac said:

 

Excellent - you're most welcome.

 

 

Certainly - the following will print the value to the command-line:

(defun c:selhigh ( / e i l m r s x z )
    (if (setq s (ssget '((0 . "LWPOLYLINE,CIRCLE"))))
        (progn
            (repeat (setq i (sslength s))
                (setq i (1- i)
                      e (ssname s i)
                      x (entget e)
                )
                (if (= "CIRCLE" (cdr (assoc 0 x)))
                    (setq z (cond ((cdr (assoc 39 x)))(0)))
                    (setq z (cdr (assoc 38 x)))
                )
                (if (< m z) (setq m z))
                (setq l (cons (cons z e) l))
            )
            (setq r (ssadd))
            (foreach x l
                (if (equal (car x) m 1e-8)
                    (ssadd (cdr x) r)
                )
            )
            (princ (strcat "Maximum elevation/thickness: " (rtos m)))
            (sssetfirst nil r)
        )
    )
    (princ)
)

Change (princ (strcat ... )) to (alert (strcat ... )) if you really want a modal dialog.

@Lee Mac I know this is an old post, but can this be adopted for a selection of ACAD points?  I would like min and max values.  Thanks

Link to comment
Share on other sites

2 hours ago, GNolder said:

@Lee Mac I know this is an old post, but can this be adopted for a selection of ACAD points?  I would like min and max values.  Thanks

I know Lee will chime in at some point, but here's some quick mods you can make and it should work for elevations and Z values ( not thickness ).

;; Add POINT to the filter like so
(setq s (ssget '((0 . "LWPOLYLINE,CIRCLE,POINT"))))
;; Then change this
(if (= "CIRCLE" (cdr (assoc 0 x)))
  (setq	z (cond	((cdr (assoc 39 x)))
		(0)
	  )
  )
  (setq z (cdr (assoc 38 x)))
)
;; To this
(if (wcmatch (cdr (assoc 0 x)) "CIRCLE,POINT")
  (setq z (last (assoc 10 x)))
  (setq z (cdr (assoc 38 x)))
)

 

Link to comment
Share on other sites

On 5/2/2023 at 5:53 PM, Lee Mac said:

Thanks @ronjonp - I would have modified the code in exactly the same way.

 

On 5/2/2023 at 3:56 PM, ronjonp said:

I know Lee will chime in at some point, but here's some quick mods you can make and it should work for elevations and Z values ( not thickness ).

;; Add POINT to the filter like so
(setq s (ssget '((0 . "LWPOLYLINE,CIRCLE,POINT"))))
;; Then change this
(if (= "CIRCLE" (cdr (assoc 0 x)))
  (setq	z (cond	((cdr (assoc 39 x)))
		(0)
	  )
  )
  (setq z (cdr (assoc 38 x)))
)
;; To this
(if (wcmatch (cdr (assoc 0 x)) "CIRCLE,POINT")
  (setq z (last (assoc 10 x)))
  (setq z (cdr (assoc 38 x)))
)

 

 

Thanks! It works perfectly! I cannot however, figure out how to get it to also show and highlight the minimum value.

Link to comment
Share on other sites

13 minutes ago, GNolder said:

Thanks! It works perfectly! I cannot however, figure out how to get it to also show and highlight the minimum value.

 

The object(s) possessing the maximum value area added to a new selection set, which is then gripped/highlighted by the sssetfirst expression at the end of the program - such selection set should also then become the previous selection.

Link to comment
Share on other sites

19 minutes ago, Lee Mac said:

 

The object(s) possessing the maximum value area added to a new selection set, which is then gripped/highlighted by the sssetfirst expression at the end of the program - such selection set should also then become the previous selection.

Thanks for the quick response. I should have started with "I'm new into autolisp". I mostly understand your response. I just don't know how to find and add the lowest value to the set so the result is Max Z= xx.xx, Min Z=xx.xx

Link to comment
Share on other sites

Apologies - I misread your question - to implement both the minimum & maximum, try the following:

(defun c:sellowhigh ( / e i l m n r s z )
    (if (setq s (ssget '((0 . "POINT"))))
        (progn
            (setq n 1e308 m -1e308)
            (repeat (setq i (sslength s))
                (setq i (1- i)
                      e (ssname s i)
                      z (cadddr (assoc 10 (entget e)))
                )
                (if (< m z) (setq m z))
                (if (< z n) (setq n z))
                (setq l (cons (cons z e) l))
            )
            (setq r (ssadd))
            (foreach x l
                (if (or (equal (car x) m 1e-8) (equal (car x) n 1e-8))
                    (ssadd (cdr x) r)
                )
            )
            (princ (strcat "\nMin Z: " (rtos n) " | Max Z: " (rtos m)))
            (sssetfirst nil r)
        )
    )
    (princ)
)

 

Edited by Lee Mac
  • Thanks 1
Link to comment
Share on other sites

27 minutes ago, Lee Mac said:

Apologies - I misread your question - to implement both the minimum & maximum, try the following:

(defun c:sellowhigh ( / e i l m n r s z )
    (if (setq s (ssget '((0 . "POINT"))))
        (progn
            (setq n 1e308 m -1e308)
            (repeat (setq i (sslength s))
                (setq i (1- i)
                      e (ssname s i)
                      z (cadddr (assoc 10 (entget e)))
                )
                (if (< m z) (setq m z))
                (if (< z n) (setq n z))
                (setq l (cons (cons z e) l))
            )
            (setq r (ssadd))
            (foreach x l
                (if (or (equal (car x) m 1e-8) (equal (car x) n 1e-8))
                    (ssadd (cdr x) r)
                )
            )
            (princ (strcat "\nMin Z: " (rtos n) " | Max Z: " (rtos m)))
            (sssetfirst nil r)
        )
    )
    (princ)
)

 

 

@Lee Mac This is exactly what I asked for. Thank you! Can I add an option to filter the results by decimal places? Example 2dp, 3dp or 4dp

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...