Arrays
If you've programmed in VBA or other
languages, you're probably familiar with the concept of arrays. An array
is a named collection of variables of the same data type. Each array
element can be distinguished from other elements by one or more integer
indexes. For example, if the "sheetNames" array contains
three names, you can set and return the names in VBA as shown in the
following example :
sheetNames(0) = "Sheet1"
sheetNames(1) = "Sheet2"
sheetNames(2) = "Sheet3"
MsgBox sheetNames(1)
Would return a message :
"Sheet2"
Arrays allow you to group related variables in a way that makes it easier
for you to keep track of, access, and manipulate them all at once, while
still being able to access each variable individually. This helps you
create smaller and simpler routines in many situations, because you can
set up loops using index numbers to deal efficiently with any number of
cases.
When you create an array, its size is determined by the number of
dimensions it has and the by the upper and lower bounds for the index
numbers in each dimension. The "sheetNames" array in the
earlier example has one dimension and three elements; the lower bound is 0
and the upper bound is 2.
"That's fine Kenny, but how do we create an
Array in Visual Lisp?"
O.K. I hear you, there's no need to yell!
Enter this at the Console prompt :
_$ (vl-load-com)
_$ (setq sheet_type (vlax-make-safearray vlax-vbString '(0 . 2)))
#<safearray...>
_$ (vlax-safearray-fill sheet_type '("Sheet1" "Sheet2"
"Sheet3"))
#<safearray...>
Have a look at the "sheet_ type" variable in the Watch
window :
This tells us that the Array contains
strings, has one dimension and contains 3 elements. Let's convert it to an
AutoLisp List :
_$ (setq
alist (vlax-safearray->list sheet_type))
("Sheet1" "Sheet2"
"Sheet3")
Did a light just go off in your head? An Array is just a List in a
slightly different format. To create an Array, or safearray as they are
know in Visual Lisp, we use the "vlax-make-safearray"
function. To populate a safearray we use the "vlax-safearray-fill"
or the "vlax-safearray-put" functions.
The "vlax-make-safearray"
function requires a minimum of two arguments. The first argument
identifies the type of data that will be stored in the array.
One of the following constants must be specified for the data type :
vlax-vbInteger |
Integer |
vlax-vbLong |
Long Integer |
vlax-vbSingle |
Single-precision floating point
number |
vlax-vbDouble |
Double-precision floating point
number |
vlax-vbString |
String |
vlax-vbObject |
Object |
vlax-vbBoolean |
Boolean |
vlax-vbVariant |
Variant |
The remaining arguments to "vlax-make-safearray"
specify the upper and lower bounds of each dimension of the array. The
lower bound for an index can be zero or any positive or negative number.
Have another look at the function we called earlier :
_$ (setq sheet_type (vlax-make-safearray
vlax-vbString '(0 . 2)))
This function created a single-dimension
array consisting of three strings with a starting index of 0 (element 0,
element 1 and element 2).
Consider this :
_$ (setq pt1 (vlax-make-safearray
vlax-vbDouble '(1 . 3)))
The lower bound specified in this example
is one and the upper bound specified is three, so the array will hold
three doubles (element 1, element 2 and element 3).
The "vla-safearray-fill"
function requires two arguments: the variable containing the array you are
populating and a list of the values to be assigned to the array elements.
You must specify as many values as there are elements in the array or vla-safearray-fill"
results in an error.
The following code populates a single-dimension array of three doubles:
_$ (vlax-safearray-fill pt1 '(100 100 0))
To convert an array to an AutoLisp list,
you can use the (vlax-safearray->list) function. Try it out :
_$ (vlax-safearray->list pt1)
(100.0 100.0 0.0)
Let's create a Array with two dimensions,
each dimension with three elements:
_$ (setq two_dim (vlax-make-safearray
vlax-vbString '(0 . 1) '(1 . 3)))
#<safearray...>
_$ (vlax-safearray-fill two_dim '(("Sheet1" "Sheet2"
"Sheet3") ("a" "b" "c")))
#<safearray...>
_$ (vlax-safearray->list two_dim)
(("Sheet1" "Sheet2"
"Sheet3") ("a" "b" "c"))
This is just a list of lists.
The first list, '(0 .1) is the number of dimensions.
The second list, '(1 . 3) is the number of elements
And now a three dimensional Array with two elements
in each dimension:
_$ (setq three_dim (vlax-make-safearray
vlax-vbString '(0 . 2) '(1 . 2)))
#<safearray...>
_$ (vlax-safearray-fill three_dim '(("Sheet1"
"Sheet2") ("a" "b") ("d"
"e")))
#<safearray...>
_$ (vlax-safearray->list three_dim)
(("Sheet1" "Sheet2")
("a" "b") ("d" "e"))
Here we have a list of
three lists.
This time, the first list '(0 . 2) defines three dimensions and the
second '(1 . 2) defines 2 elements in each dimension.
One place you will be using "vlax-safearray-fill"
is when creating selection sets with filters. The syntax in ActiveX for
"Selecting All with Filters" is as follows "
object.Select Mode[, Point1][, Point2][,
Filter_Code][, Filter_Value]
Filter_Code must be an Integer array and
Filter_Value a Variant array.
In Visual Lisp, the coding would be written like this :
;create a 2 element
integer array for the DXF Codes.
(setq filter_code (vlax-make-safearray vlax-vbinteger '(0 . 1)))
;create a 2 element variant array for the values.
(setq filter_value (vlax-make-safearray vlax-vbvariant '(0 . 1)))
;DXF Codes for Objects and Layer : " 0"
for Object," 8" for Layer.
(vlax-safearray-fill filter_code '(0 8))
;Name of Object and Layer.
(vlax-safearray-fill filter_value '("CIRCLE" "2"))
;select ALL Circles on Layer 2.
(vla-select newsset acSelectionSetAll nil nil filter_code filter_value)
For more information on Selections Sets, pop along
to my "Selection Sets" tutorial page
and get yourself even more confused.
The "vlax-safearray-put-element"
function can be used to assign values to one or more elements of a
safearray. The number of arguments required by this function depends on
the number of dimensions in the array.
- The first argument always names the safearray to
which you are assigning a value.
- The next set of arguments identifies index values
pointing to the element to which you are assigning a value. For a
single-dimension array, specify one index value: for a two-dimension
array, specify two index values, and so on.
- The final argument is always the value to be
assigned to the safearray element.
Have a look at the following :
_$ (setq pt1 (vlax-make-safearray
vlax-vbDouble '(1 . 3)))
#<safearray...>
_$ (vlax-safearray-put-element pt1 1 100)
100
_$ (vlax-safearray-put-element pt1 2 100)
100
_$ (vlax-safearray-put-element pt1 3 75)
75
_$ (vlax-safearray->list pt1)
(100.0 100.0 75.0)
_$ (vlax-safearray-put-element pt1 1 50)
50
_$ (vlax-safearray->list pt1)
(50.0 100.0 75.0)
Now let's populate a two-dimension array of strings
:
_$ (setq two_dim (vlax-make-safearray
vlax-vbString '(0 . 1) '(1 . 3)))
#<safearray...>
_$ (vlax-safearray-put-element two_dim 0 1
"a")
"a"
_$ (vlax-safearray->list two_dim)
(("a" "" "")
("" "" ""))
_$ (vlax-safearray-put-element two_dim 0 2
"b")
"b"
_$ (vlax-safearray-put-element two_dim 0 3
"c")
"c"
_$ (vlax-safearray-put-element two_dim 1 1
"d")
"d"
_$ (vlax-safearray-put-element two_dim 1 2
"e")
"e"
_$ (vlax-safearray-put-element two_dim 1 3
"f")
"f"
_$ (vlax-safearray->list two_dim)
(("a" "b" "c")
("d" "e" "f"))
You can use "vlax-safearray-get-element"
to get the value of any element in any array. Here we'll use "vlax-safearray-get-element"
to retrieve the second element in the first dimension of the array:
_$ (vlax-safearray-get-element matrix 1 2)
"b"
(vlax-safearray-get-l-bound)
returns the lower boundary (starting index) of a dimension of an array :
Get the starting index value
of the second dimension of the array:
_$ (vlax-safearray-get-l-bound two_dim 2)
1
The second dimension starts with index 1.
Conversley, "vlax-safearray-get-u-bound"
returns the upper boundary (end index) of a dimension of an array
Get the end index value of the second dimension of the array:
_$ (vlax-safearray-get-u-bound two_dim 2)
3
The second dimension ends with index 3.
You can use "vlax-safearray-get-dim"
to get the number of dimensions in a safearray object :
Get the number of dimensions in "two_dim":
_$ (vlax-safearray-get-dim two_dim)
2
There are 2 dimensions in "two_dim".
Let's have a look at putting some of this to good
use :
(vl-load-com)
(defun
c:Line_VL ( / acApp acDoc mspace p1 p2 sp ep lineObj)
(setq
acApp (vlax-get-acad-object))
(setq
acDoc (vla-get-activedocument acApp))
(setq
mspace (vla-get-modelspace acDoc)
(setq
p1 (getpoint "\nFirst
Point : "))
(setq
p2 (getpoint p1 "\nSecond
Point : "))
(setq
sp (vlax-make-safearray vlax-vbdouble
'(0 . 2)))
(setq
ep (vlax-make-safearray vlax-vbdouble
'(0 . 2)))
(vlax-safearray-fill
sp p1)
(vlax-safearray-fill
ep p2)
(setq
lineObj (vla-addline mspace sp
ep))
(princ)
);defun
There is an easier way of writing this
routine :
(vl-load-com)
(defun c:Line_VL ( / acApp acDoc mspace p1 p2 lineObj)
(setq acApp (vlax-get-acad-object))
(setq acDoc (vla-get-activedocument acApp))
(setq mspace (vla-get-modelspace acDoc))
(setq p1 (getpoint "\nFirst Point : "))
(setq p2 (getpoint p1 "\nSecond Point : "))
(setq lineObj (vla-addline mspace (vlax-3d-point
p1) (vlax-3d-point p2)))
(princ)
);defun
For methods that require you to pass a
three-element array of doubles (typically to specify a point), you can use
the "vlax-3d-point" function.
Well, that's it with Arrays. I haven't covered
absolutely everything pertaining to Arrays, but you should now have enough
to get you started. I hope that you understood everything I was warbling
on about, and that I didn't confuse you too much!!!!
Adios for now, amigo........ |