; ARRAY.LSP Copyright 1990,91 Tony Tanzillo All Rights Reserved.
;
; Functions for implementing multi-dimensional arrays in AutoLISP.
;
; Functions included:
;
; (make-array) Initializes an N-dimensional array
; (aref) Retreives elements from an array.
; (aset) Modifies elements in an array.
; (matrix-to-vector) Matrix-to-vector address translator.
; (mtov) Auxiliary function for (matrix-to-vector)
;
;
;
; -------------------------------------------------------------------------
; (make-array )
;
; Initialize an N-dimensional array.
;
; is a list of N elements which is the size of each
; dimenson of the array, and N is the number of dimensions.
;
; Example:
;
; To create a 3-dimensional array of 6 x 8 x 12 elements
; and assign the symbol MYARRAY to it:
;
; (setq myarray (make-array '(6 8 12)))
(defun make-array (dims / array i)
(cons (setq dims (cond ( (listp dims) dims)
(t (list dims))))
(repeat (setq i (apply '* dims))
(setq array (cons (list (setq i (1- i))) array)))))
; --------------------------------------------------------------------------
; (aset )
;
; SET Array Field - Array element modifier function.
;
; Assigns to the element specified by of the
; array assigned to .
;
; is a QUOTED symbol which is assigned to the array.
;
; is a list whose elements are the address indices of the
; array element which is to be assigned to.
;
; is the new value to be assigned to the specified element.
;
; Example:
;
; To assign "hello" to element [3,5,7] of the 6 x 8 x 12 array
; created above:
;
; (aset 'myarray '(3 5 7) "hello")
(defun aset (sym addr val / v ar)
(set sym
(cons (car (setq ar (eval sym)))
(subst (cons (setq v (matrix-to-vector (car ar) addr)) val)
(assoc v (cdr ar))
(cdr ar)))))
; --------------------------------------------------------------------------
; (aref )
;
; Array accessor function - retrieves specified element of an array.
;
; is the array to be accessed (must be a list created by
; the make-array function)
;
; is a list of N elements which contains the subscript
; address of the element to be retrieved.
;
; Example:
;
; To retrieve the value assigned to element [3,5,7] of the array
; created in the above example:
;
; (aref myarray '(3 5 7))
(defun aref (array address)
(cdr (nth (1+ (matrix-to-vector (car array)
(cond ( (listp address) address)
(t (list address))))) array)))
; --------------------------------------------------------------------------
; (matrix-to-vector )
;
; Calculates the vector offset of an N-dimensional array address
; where the array index base is 1 (first element of each dimension).
;
; Note: The left-most dimension of the array is the most-significant.
;
; Example:
;
; To find the vector offset of element [3,4] in a two-dimensional
; array whose dimensions are 8 x 12:
;
; (matrix-to-vector '(8 12) '(3 4))
;
(defun matrix-to-vector (dims address)
(mtov dims (mapcar '1- address))
)
; --------------------------------------------------------------------------
; (mtov )
;
; Auxiliary function for (matrix-to-vector):
;
; Translates matrix address to vector address (base 1).
(defun mtov (dims addr)
(cond ( (cdr addr)
(+ (apply '* (cons (car addr) (cdr dims)))
(mtov (cdr dims) (cdr addr))))
(t (car addr))))
; ARRAY.LSP - A working example.
; ------------------------------------------------------------------------
;
; The following code demonstrates the use of arrays by first loading the
; vertices of a polygon mesh into a 2-dimensional array whose dimensions
; are the same as the mesh, accessing and modifying elements in the array
; and then stuffing the array coordinates back into the mesh vertices of
; the polyline.
; First, get the polyline entity name, and data:
(setq e (car (entsel "\nSelect mesh: ")))
(setq edata (entget e))
; Get the M and N mesh dimensions:
(setq msize (cdr (assoc 71 edata))
nsize (cdr (assoc 72 edata))
)
; Initialize the array to the size of the mesh:
(setq vertices (make-array (list msize nsize)))
; Initialize the m subscript to 0:
(setq m 0)
; Enter processing loops, and read each vertex coordinate into its
; corresponding location in the array:
(repeat msize
(setq m (1+ m) n 0) ; increment M subscript, reset N to 0
(repeat nsize
(setq n (1+ n)) ; increment N subscript
(aset 'vertices
(list m n)
(cdr (assoc 10 (entget (setq e (entnext e)))))
)
)
)
; Retrieve mesh vertex 3,3:
(aref vertices (list 3 3))
; Modify vertex 4,6 in the array:
(aset 'vertices (list 4 6) '(2.0 4.0 8.0))
; Update the polygon mesh vertices with the modified points stored
; in the array we created and manipulated above:
(setq m 0)
(setq v (setq e )) ; entity name of polyline header entity.
(repeat msize
(setq m (1+ m) n 0)
(repeat nsize
(setq n (1+ n))
(setq vertex-data (entget (setq v (entnext v)))
new-point (aref vertices (list m n)))
(entmod (subst (cons 10 new-point)
(assoc 10 vertex-data)
vertex-data
)
)
)
)
(entupd e)
; ------------------------------------------------------------------
;
; ARRAY.LSP - How does it work?
;
; The array functions included in ARRAY.LSP were designed to support
; arrays of any size or number of dimensions. If you can visualize a
; 5-dimensional array, then God bless you. For the most part you will
; probably never need to make use of such a beast.
;
; The linear offset or position of any element in an N-dimensional array
; can be found by multiplying each element in the index/address by the
; least-significant overall dimension of the array for each but the most
; significant component of the dimension.
;
; In all programming languages, arrays are stored as simple vectors (a
; vector is a one-dimensional array, or a simple list). When an element
; in a multi-dimensional array is referenced, the compenents of the
; address (e.g, column X, row Y) are first converted into the equivalent
; offset into the vector in which the array is internally represented in,
; and the member element is fetched. In order to compute the location of
; an element in the vector, the size of the multi-dimensional array and
; the array indices or suscript must be operated on.
;
; Here is a simple example of a 2-dimensional array of 6 x 4 elements, in
; row/column format. The value of each array element is the address of an
; equilvalent one-dimensional vector offset, which is the same value that
; the matrix address must first be converted into in order to locate that
; element's position in the one-dimensional vector.
;
; column -> 1 2 3 4 5 6
; +-----------------------------
;row -> 1 | 1 2 3 4 5 6
; |
; 2 | 7 8 9 10 11 12
; |
; 3 | 13 14 15 16 17 18
; |
; 4 | 19 20 21 22 23 24
;
; So, to find the vector address of a given row and column location in a
; two-dimensional array, you first multiply the total number of columns by
; the row component of the desired element's address minus 1.
;
; And in the above example, if we wanted to find the vector offset of the
; element in column 4, row 3, we multiply the total number of columns (6)
; by the specified row in the address (3) minus 1, or (6 * 2) = 12.
;
; Then, just add to this, the column address of the desired element (4),
; and we have (6 * 2) + 4 = 16, which means that element 4,3 in the above
; matrix translates to the 16th element in the one-dimensional vector in
; which the 6 x 4 array is stored interally.
;
; -------------------------------------------------------------------------
;
; Notes on Arrays and LISP: The above, could easily be done using nothing
; but LISTS in AutoLISP, and it could be done more effeciently at that, but
; when we need to randomly access and modify elements in complex structures,
; it is sometimes more effecient to store structures in forms that allow us
; to easily reference and modify elements knowing only their position in the
; structure. For this purpose, and for the benefit of programmers who are
; used to using arrays in other languages, I've made ARRAY.LSP available to
; the public.
;
; Tony T.
;
; ########################## eof array.lsp #############################