Author Topic: [challenge] Bounding Box in UCS  (Read 7923 times)

0 Members and 1 Guest are viewing this topic.

chlh_jd

  • Guest
[challenge] Bounding Box in UCS
« on: February 15, 2011, 01:06:49 AM »
Hi All  :-)
To Get the bounding box in UCS , Here is your nice function which arg is a select set or an ename .

chlh_jd

  • Guest
Re: [challenge] Bounding Box in UCS
« Reply #1 on: February 15, 2011, 01:18:06 AM »
Here's my poor way .
Code: [Select]
;;;Function: Get BuondingBox
;;;arg : Select set or a Ename
;;;Support in UCS
;;;Written by Highflybird
;;;Edited by GSLS(SS), 2011-02-15
(defun ss-get-boundingbox (ss    /   getrcsmatrix        lst
  UcsFlag  matrix   i      ent      obj
  minPt    maxPt    minLs    maxLs    maxX
  maxY    minX     minY
 )
  (defun getrcsmatrix (lst org / m i j)
    (setq m ([0] 4 4)
 m (ch-lst 1.0 (list 3 3) m)
 i -1
    )
    (repeat 3
      (setq i (1+ i)
   m (ch-lst (nth i org) (list i 3) m)
   j -1
      )
      (repeat 3
(setq j (1+ j))
(setq m (ch-lst (nth i (nth j lst)) (list i j) m))
      )
    )
  )
  (setq UcsFlag (getvar "WORLDUCS"))
  (if (= UcsFlag 0)
    (setq UcsFlag T
 xdir  (getvar "UCSXDIR")
 ydir  (getvar "UCSYDIR")
 zdir  (CrossProduct xdir ydir)
 origin  (getvar "UCSORG")
 WcsOrg  (trans '(0 0 0) 0 1)
 matLst  (list xdir ydir zdir)
 matrix  (getrcsmatrix matLst origin) ;_change in lisp
    )
    (setq UcsFlag nil)
  )
  (if ss
    (progn
      (if (eq (type ss) 'ENAME)
(setq ss (ssadd ss (ssadd)))
      )
      (setq i 0)
      (setq minPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (setq maxPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (repeat (sslength ss)
(setq ent (ssname ss i)
     obj (vlax-ename->vla-object ent)
)
(and UcsFlag
    (vla-TransformBy obj (vlax-tmatrix ([uinv] matrix)))
)
(vla-GetBoundingBox obj 'minpt 'maxpt)
(setq minPt (vlax-safearray->list minPt)
     maxPt (vlax-safearray->list maxPt)
     minLs (cons minPt minLs)
     maxLs (cons maxPt maxLs)
)
(and UcsFlag (vla-TransformBy obj (vlax-tmatrix matrix)))
(setq i (1+ i))
      )
 ;_Is there better way to get the other coner points , if it's in 3D UCS ?
 ;_Perhaps it'n use 'trans' function ...
      (setq minX (apply 'min (mapcar 'car minLs)))
      (setq minY (apply 'min (mapcar 'cadr minLs)))
      (setq maxX (apply 'max (mapcar 'car maxLs)))
      (setq maxY (apply 'max (mapcar 'cadr maxLs)))
      (mapcar (function (lambda (x)
 (trans x 1 0)
)
     )
     (list (list minX minY 0);_if the Z-Axis coor is not 0 , and mixpt's value is not eq maxpt's ?
   (list maxX minY 0)
   (list maxX maxY 0)
   (list minX maxY 0)
     )
      )
    )
  )
)
;;; Crossproduct
(defun CrossProduct (v1 v2)
  (list (- (* (cadr v1) (caddr v2)) (* (caddr v1) (cadr v2)))
(- (* (caddr v1) (car v2)) (* (car v1) (caddr v2)))
(- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
  )  
)
;;;written by qj-chen
;;;Edited by GSLS(SS)
(defun ch-lst (new i lst / j len fst mid)
  (if (/= (type i) 'list)
    (cond
      ((minusp i)
       lst
      )
      ((> i (setq len (length lst)))
       lst
      )
      ((> i (/ len 2))
       (reverse (ch-lst new (1- (- len i)) (reverse lst)))
      )
      (t
       (append
(progn
  (setq fst nil)
  (repeat (rem i 4)
    (setq fst (cons (car lst) fst)
  lst (cdr lst)
    )
  )
  (repeat (/ i 4)
    (setq fst (cons (cadddr lst)
    (cons (caddr lst)
  (cons
    (cadr lst)
    (cons
      (car lst)
      fst
    )
  )
    )
      )
  lst (cddddr lst)
    )
  )
  (reverse fst)
)
(list new)
(cdr lst)
       )
      )
    )
    (progn
      (setq j (cadr i)
   i (car i)
      )
      (if j
(progn
 (setq mid (nth i lst))
 (setq mid (ch-lst new j mid))
 (ch-lst mid i lst)
)
(ch-lst new i lst)
      )
    )
  )
)
Use Gile's invers maxrix func
Code: [Select]
;;;transpose
(defun [trp] (a) 
  (apply 'mapcar (cons 'list a))
)
;;; gile-cofact (gile)
;;; returns the gile-cofactor associated to ij item of a matrix
;;;
;;; arguments
;;; i = row index (first row = 1)
;;; j = column index (first column = 1)
;;; m = a matrix
;;;(gile-cofact 1 2 a)
(defun gile-cofact (i j m)
  (* ([mo]
       (remove-nth (list (1- i) (1- j)) m)
     )
     (expt -1 (+ i j))
  )
)
;;; gile-determ (gile)
;;; returns the determinant of a matrix
;;; argument : a matrix
(defun [mo] (m)
  (if (null (caddr m));_原语句(= (length m) 2);_(null (caddr m))
    (- (* (caar m) (cadadr m)) (* (caadr m) (cadar m)))
    ((lambda (r n)
       (apply
'+
(mapcar
   (function (lambda (x)
       (* x
  (gile-cofact
    1
    (setq n (1+ n))
    m
  )
       )
     )
   )
   r
)
       )
     )
      (car m)
      0
    )
  )
)
;;; gile-adj-mat (gile)
;;; returns the adjugate matrix
;;;
;;; argument : a matrix
;;;(gile-adj-mat a)
(defun gile-adj-mat (m / i)
  (setq i 0)
  ([trp] (mapcar
      (function (lambda (v / j)
  (setq i (1+ i)
j 0
  )
  (mapcar
    (function (lambda (x)
(gile-cofact
  i
  (setq j (1+ j))
  m
)
      )
    )
    v
  )
)
      )
      m
    )
  )
)
;;; gile-inv-mat (gile)
;;; inverse a matrix
;;;
;;; argument : a matrix
;;;(gile-inv-mat m)
(defun [uinv] (m / d)
  (if (/= 0 (setq d ([mo] m)))
    (mapcar
      (function (lambda (v)
  (mapcar
    (function (lambda (x)
(* (/ 1 d) x)
      )
    )
    v
  )
)
      )
      (gile-adj-mat m)
    )
  )
)
« Last Edit: February 15, 2011, 01:26:57 AM by chlh_jd »

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: [challenge] Bounding Box in UCS
« Reply #2 on: February 15, 2011, 02:50:20 AM »
Hi,

Here's my way.
Using for a single entity (ename or vla-object): (gc:UcsBoundingBox ent 'minpt 'maxpt)
Using for a selection set: (gc:SelSetUcsBBox ss 'minpt 'maxpt)

Code: [Select]
;; gc:TMatrixFromTo
;; Returns the 4X4 transformation matrix from a coordinate system to an other one
;;
;; Arguments
;; from to: same arguments as for the 'trans' function

(defun gc:TMatrixFromTo (from to)
  (append
    (mapcar
      (function
(lambda (v o)
  (append (trans v from to T) (list o))
)
      )
      (list '(1. 0. 0.) '(0. 1. 0.) '(0. 0. 1.))
      (trans '(0. 0. 0.) to from)
    )
    (list '(0. 0. 0. 1.))
  )
)

;; gc:UcsBoundingBox
;; Returns the UCS coordinates of the object bounding box about current UCS
;;
;; Arguments
;; obj: an entity (ENAME or VLA-OBJCET)
;; _OutputMinPtSym: a quoted symbol (output)
;; _OutputMaxPtSym: a quoted symbol (output)

(defun gc:UcsBoundingBox (obj _OutputMinPtSym _OutputMaxPtSym)
  (vl-load-com)
  (and (= (type obj) 'ENAME)
       (setq obj (vlax-ename->vla-object obj))
  )
  (vla-TransformBy obj (vlax-tmatrix (gc:TMatrixFromTo 1 0)))
  (vla-GetBoundingBox obj _OutputMinPtSym _OutputMaxPtSym)
  (vla-TransformBy obj (vlax-tmatrix (gc:TMatrixFromTo 0 1)))
  (set _OutputMinPtSym (vlax-safearray->list (eval _OutputMinPtSym)))
  (set _OutputMaxPtSym (vlax-safearray->list (eval _OutputMaxPtSym)))
)

;; gc:SelSetUcsBBox
;; Returns the UCS coordinates of the object bounding box about current UCS
;;
;; Arguments
;; ss: a selection set
;; _OutputMinPtSym: a quoted symbol (output)
;; _OutputMaxPtSym: a quoted symbol (output)

(defun gc:SelSetUcsBBox (ss _OutputMinPtSym _OutputMaxPtSym / n l1 l2)
  (repeat (setq n (sslength ss))
    (gc:UcsBoundingBox (ssname ss (setq n (1- n))) _OutputMinPtSym _OutputMaxPtSym)
    (setq l1 (cons (eval _OutputMinPtSym) l1)
  l2 (cons (eval _OutputMaxPtSym) l2)
    )
  )
  (set _OutputMinPtSym (apply 'mapcar (cons 'min l1)))
  (set _OutputMaxPtSym (apply 'mapcar (cons 'max l2)))
)

chlh_jd,
To inverse any matrices, rather than using the cofactor method which is slow (due to recursive calls), you should use this one which implements the Gauss-Jordan elimination method.
« Last Edit: February 15, 2011, 05:15:11 AM by gile »
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: [challenge] Bounding Box in UCS
« Reply #3 on: February 15, 2011, 09:07:04 AM »
Nice work Gile  :-)

I think your functions return the WCS points though, not UCS as per your description.  ;-)

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: [challenge] Bounding Box in UCS
« Reply #4 on: February 15, 2011, 10:16:01 AM »
Nice work Gile  :-)

I think your functions return the WCS points though, not UCS as per your description.  ;-)

Did you try them ?
Assuming command (or vl-cmdf) always works with UCS points, you can test with this:

Code: [Select]
(defun c:test (/ ss minpt maxpt)
  (if (setq ss (ssget))
    (progn
      (gc:SelSetUcsBBox ss 'minpt 'maxpt)
      (vl-cmdf
(if (equal (caddr minpt) (caddr maxpt) 1e-6)
  "_.rectangle"
  "_.box"
)
"_non"
minpt
"_non"
maxpt
      )
    )
  )
  (princ)
)
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: [challenge] Bounding Box in UCS
« Reply #5 on: February 15, 2011, 01:56:56 PM »
I did try them, but by entmake'ing an LWPolyline, and the results from my tests weren't always consistent (but its probably due to a badly written test function, written too quickly).

I thought also that getBoundingBox returned points in WCS...  :?

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: [challenge] Bounding Box in UCS
« Reply #6 on: February 15, 2011, 02:37:41 PM »
I thought also that getBoundingBox returned points in WCS...  :?

Yes, GetBoundingBox always returns points in WCS and the box is aligned to WCS axis.

So, to get a bounding box aligned to UCS axis and in UCS, before invoking the GetBoundingBox method, the entity is transformed from UCS to WCS with vla-TransformBy method.

The returned points are the WCS corrdinates of the transformed entity bounding box, they're equal to the UCS coordinates of the bounding box about UCS axis of the non-tranformed entity.
Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 12914
  • London, England
Re: [challenge] Bounding Box in UCS
« Reply #7 on: February 15, 2011, 02:52:00 PM »
Ah! I see - thanks Gile - and once again: nice work  :-)

chlh_jd

  • Guest
Re: [challenge] Bounding Box in UCS
« Reply #8 on: February 15, 2011, 10:58:23 PM »
Quote
Code: [Select]
gc:TMatrixFromTo
Excellent Gile !  :-)
I just think it can be given a control arg like as T or NIL ,and then it returns the boundingbox when the cont-arg is T in UCS or NIL in WCS.
Quote
Code: [Select]
(set _OutputMinPtSym (apply 'mapcar (cons 'min l1)))
Very Nice return method !
« Last Edit: February 15, 2011, 11:12:49 PM by chlh_jd »

chlh_jd

  • Guest
Re: [challenge] Bounding Box in UCS
« Reply #9 on: February 15, 2011, 11:19:00 PM »
Hi ,
Here's New : :-)
Code: [Select]
;;;Function: Get BuondingBox
;;;arg :
;;;      ss -- Select set or a Ename
;;;   onseg -- T or NIL , if T then returns the box in UCS , if NIL in WCS
;;;Support in UCS
;;;Written by Highflybird
;;;Edited by GSLS(SS), 2011-02-16
(defun ss-get-boundingbox (ss  onseg / Wmat   Umat   i
  ent  obj minPt maxPt  minLs  maxLs
  maxX  maxY minX minY pts
 )
  (if ss
    (progn
      (if (eq (type ss) 'ENAME)
(setq ss (ssadd ss (ssadd)))
      )
      (if (and onseg (= (getvar "WORLDUCS") 0))
(setq Wmat (gc:TMatrixFromTo 1 0)
     Umat (gc:TMatrixFromTo 0 1)
);_Use gile's nice function
      )
      (setq i 0)
      (setq minPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (setq maxPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (repeat (sslength ss)
(setq ent (ssname ss i)
     obj (vlax-ename->vla-object ent)
)
(if Wmat
 (vla-TransformBy obj (vlax-tmatrix Wmat))
)
(vla-GetBoundingBox obj 'minpt 'maxpt)
(setq minPt (vlax-safearray->list minPt)
     maxPt (vlax-safearray->list maxPt)
     minLs (cons minPt minLs)
     maxLs (cons maxPt maxLs)
)
(if Umat
 (vla-TransformBy obj (vlax-tmatrix Umat))
)
(setq i (1+ i))
      )
 ;_Is there better way to get the other coner points , if it's in 3D UCS ?
 ;_Perhaps it'n use 'trans' function ...
      (setq minX (apply 'min (mapcar 'car minLs)))
      (setq minY (apply 'min (mapcar 'cadr minLs)))
      (setq maxX (apply 'max (mapcar 'car maxLs)))
      (setq maxY (apply 'max (mapcar 'cadr maxLs)))
      (setq pts (list (list minX minY 0)
     (list maxX minY 0)
     (list maxX maxY 0)
     (list minX maxY 0)
)
      )
      (if Wmat
(mapcar (function (lambda (x)
   (trans x 1 0)
 )
)
pts
)
pts
      )
    )
  )
)
(defun c:test (/
    ss
   )
  ;(svos)
  (if (setq ss (ssget))
    (draw-pl (list (ss-get-boundingbox ss NIL)));_test in UCS return the wcs box
  )
  ;(clos)  
  (princ)
)
(defun draw-pl (lst)
  (entmake
    (append
      '((0 . "LWPOLYLINE")
(100 . "AcDbEntity")
(100 . "AcDbPolyline")
       )
      (list (cons 90 (length (car lst))))
      (mapcar (function (lambda (x) (cons 10 x))) (car lst))
      (list (cons 70 1))
      (cdr lst)
    )
  )
)
« Last Edit: February 16, 2011, 09:31:31 AM by chlh_jd »

cmwade77

  • Swamp Rat
  • Posts: 1443
Re: [challenge] Bounding Box in UCS
« Reply #10 on: August 02, 2011, 05:09:09 PM »
Hi ,
Here's New : :-)
Code: [Select]
;;;Function: Get BuondingBox
;;;arg :
;;;      ss -- Select set or a Ename
;;;   onseg -- T or NIL , if T then returns the box in UCS , if NIL in WCS
;;;Support in UCS
;;;Written by Highflybird
;;;Edited by GSLS(SS), 2011-02-16
(defun ss-get-boundingbox (ss   onseg / Wmat   Umat   i
   ent   obj minPt maxPt  minLs  maxLs
   maxX   maxY minX minY pts
  )
  (if ss
    (progn
      (if (eq (type ss) 'ENAME)
(setq ss (ssadd ss (ssadd)))
      )
      (if (and onseg (= (getvar "WORLDUCS") 0))
(setq Wmat (gc:TMatrixFromTo 1 0)
      Umat (gc:TMatrixFromTo 0 1)
);_Use gile's nice function
      )
      (setq i 0)
      (setq minPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (setq maxPt (vlax-make-safearray vlax-vbdouble '(0 . 2)))
      (repeat (sslength ss)
(setq ent (ssname ss i)
      obj (vlax-ename->vla-object ent)
)
(if Wmat
  (vla-TransformBy obj (vlax-tmatrix Wmat))
)
(vla-GetBoundingBox obj 'minpt 'maxpt)
(setq minPt (vlax-safearray->list minPt)
      maxPt (vlax-safearray->list maxPt)
      minLs (cons minPt minLs)
      maxLs (cons maxPt maxLs)
)
(if Umat
  (vla-TransformBy obj (vlax-tmatrix Umat))
)
(setq i (1+ i))
      )
 ;_Is there better way to get the other coner points , if it's in 3D UCS ?
 ;_Perhaps it'n use 'trans' function ...
      (setq minX (apply 'min (mapcar 'car minLs)))
      (setq minY (apply 'min (mapcar 'cadr minLs)))
      (setq maxX (apply 'max (mapcar 'car maxLs)))
      (setq maxY (apply 'max (mapcar 'cadr maxLs)))
      (setq pts (list (list minX minY 0)
      (list maxX minY 0)
      (list maxX maxY 0)
      (list minX maxY 0)
)
      )
      (if Wmat
(mapcar (function (lambda (x)
    (trans x 1 0)
  )
)
pts
)
pts
      )
    )
  )
)
(defun c:test (/
     ss
    )
  ;(svos)
  (if (setq ss (ssget))
    (draw-pl (list (ss-get-boundingbox ss NIL)));_test in UCS return the wcs box
  )
  ;(clos) 
  (princ)
)
(defun draw-pl (lst)
  (entmake
    (append
      '((0 . "LWPOLYLINE")
(100 . "AcDbEntity")
(100 . "AcDbPolyline")
       )
      (list (cons 90 (length (car lst))))
      (mapcar (function (lambda (x) (cons 10 x))) (car lst))
      (list (cons 70 1))
      (cdr lst)
    )
  )
)
With this, I get the following error:
; error: bad function: #<safearray...>

chlh_jd

  • Guest
Re: [challenge] Bounding Box in UCS
« Reply #11 on: August 03, 2011, 03:04:59 AM »
Hi cmwade77 , Which  ACAD  version  you used ?
can you post the error dwg ?

cmwade77

  • Swamp Rat
  • Posts: 1443
Re: [challenge] Bounding Box in UCS
« Reply #12 on: August 03, 2011, 11:28:55 AM »
This is in 2012. but now it's not giving me that error on the same drawing, must have been something I had done in that session of AutoCAD before is my guess. Sorry about that.

chlh_jd

  • Guest
Re: [challenge] Bounding Box in UCS
« Reply #13 on: August 04, 2011, 02:36:04 AM »
This is in 2012. but now it's not giving me that error on the same drawing, must have been something I had done in that session of AutoCAD before is my guess. Sorry about that.
It test OK in 2010