Static values in a custom program are helpful in executing a set of code statements consistently each time the program is run. However, using static values only prevents the user from providing input during execution. Your users might need to specify the location of the corner of a mounting plate, an insertion point for a block reference, or which objects to modify. The AutoCAD® Object library provides a variety of functions that allow you to request input at the Command prompt or with controls in a user form. I cover working with user forms in Chapter 11, “Creating and Displaying User Forms.”
Some values obtained from a user can be directly assigned to an object without any changes, whereas other values might need to be manipulated first. The AutoCAD Object library contains functions that can be used to manipulate coordinate and angular values. I discussed converting values from one data type to another in Chapter 2, “Understanding Visual Basic for Applications.”
Getting input from a user will be helpful in creating dynamic and flexible programs, but so will the manipulation of the current view. The programs you write can pan and change the zoom factor or area that is visible in the drawing window. In addition to panning and zooming, you can work with named views, tiled viewports, and visual styles. In this chapter, I explain how to request input from the user at the Command prompt, calculate geometric values, and manipulate the current view in model space.
There are times when you will want users to provide a value instead of simply deciding which values a program should use each time it is executed. The AutoCAD Object library contains functions that can be used to request input from the user. The values returned by the user can then be validated using test conditions before the values are passed as arguments to a function. I explained how to use test conditions with comparison and logical grouping operators in Chapter 2.
In addition to getting input from the user, a custom program can provide textual feedback to the user, letting the user know the current state of a program or when an error occurs. Textual feedback can be provided at the Command prompt or in a message box. Whether getting input from the user or providing textual messages at the Command prompt, you will need to work with the AcadUtility
object. The AcadUtility
object can be accessed from the Utility
property of an AcadDocument
or ThisDrawing
object.
The following code statements get the AcadUtility
object of the ThisDrawing
object:
Dim oUtil as AcadUtility
Set oUtil = ThisDrawing.Utility
With the functions of the AcadUtility
object, you can request input from the user at the Command prompt. Input requested can be any of the following:
Before requesting input from the user, you will want to define a prompt. A prompt is a short text message that provides the user with an idea of the input expected and whether any options are available. I discuss recommended etiquette for creating a prompt in the sidebar “Guidelines for Prompts.”
Numbers play an important role in creating and modifying objects in a drawing, whether it is the radius of a circle, part of a coordinate value, or the number of rows in a rectangular array. VBA supports two types of numbers: integers and doubles (or reals). Integers are whole numbers without a decimal value, and doubles are numbers that support a decimal value. You can use the GetInteger
and GetReal
functions to request a numeric value from the Command prompt. The number entered by the user is the value returned by the function, but if the user presses the spacebar or Enter without providing a value, an error is generated. When an incorrect value is provided, the function re-prompts the user to try again.
The following shows the syntax of the GetInteger
and GetReal
functions:
retVal = object.GetInteger([msg])
retVal = object.GetReal([msg])
Their arguments are as follows:
retVal
The retVal
argument represents the integer or double value returned.object
The object
argument represents the AcadUtility
object.msg
The msg
argument is an optional string that defines the prompt message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.The following are examples of the GetInteger
and GetReal
functions, and the values that are returned:
nRetVal = oUtil.GetInteger(vblf & "Enter number of line segments: ")
oUtil.Prompt vbLf & "Value=" & CStr(nRetVal) & vbLf
Enter number of line segments: Type 3.5 and press Enter
Requires an integer value.
Enter number of line segments: Type 3 and press Enter
3
dRetVal = oUtil.GetReal(vblf & "Enter angle of rotation: ")
oUtil.Prompt vbLf & "Value=" & CStr(dRetVal) & vbLf
Enter number of line segments: Type 22.5 and press Enter
22.5
The GetPoint
function allows the user to specify a point in the drawing area based on an optional base point. When an optional base point is provided, a rubber-band line is drawn from the base point to the current position of the cursor. Figure 5.1 shows the rubber-band line effect used when getting a point based on the optional base point. A variant containing an array of three doubles, representing a point, is returned by the GetPoint
function if the user successfully specifies a point in the drawing area. If the user presses the spacebar or Enter without specifying a point, an error is generated.
In addition to the GetPoint
function, the GetCorner
function can be used to request a point. There are differences between the GetPoint
and GetCorner
functions:
GetCorner
function requires a base point.GetPoint
function draws a rubber-band line from a base point to the cursor, whereas the GetCorner
function draws a rectangle from the base point to the cursor, as shown in Figure 5.2.The following shows the syntax of the GetPoint
and GetCorner
functions:
retVal = object.GetPoint([basePoint], [msg])
retVal = object.GetCorner(basePoint, [msg])
Their arguments are as follows:
retVal
The retVal
argument represents the variant value returned by the function. This variant is an array of three doubles representing the point specified.object
The object
argument represents the AcadUtility
object.basePoint
The basePoint
argument specifies the base point from which a rubber-band line or rectangle is drawn to the current position of the cursor. This argument value must be an array of three doubles and is optional for the GetPoint
function.msg
The msg
argument is an optional string that defines the prompt message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.The following are examples of the GetPoint
and GetCorner
functions:
Dim vPt As Variant
vPt = oUtil.GetPoint(, vbLf & "Specify first corner: ")
oUtil.Prompt vbLf & "X=" & CStr(vPt(0)) & _
" Y=" & CStr(vPt(1)) & _
" Z=" & CStr(vPt(2)) & vbLf
Dim vCornerPt As Variant
vCornerPt = oUtil.GetCorner(vPt, vbLf & "Specify opposite corner: ")
oUtil.Prompt vbLf & "X=" & CStr(vCornerPt(0)) & _
" Y=" & CStr(vCornerPt(1)) & _
" Z=" & CStr(vCornerPt(2)) & vbLf
Here is an example of values entered at the prompts displayed for the previous example code statements and the values returned:
Specify first corner: 0,0
X=0 Y=0 Z=0
Specify opposite corner: @5,5
X=5 Y=5 Z=0
Although the GetReal
function can be used to request a value that might represent a distance or angular value, the AutoCAD Object library contains several functions that are better suited for acquiring distance or angular values. (I explain how to get angular values in the next section.) The GetDistance
function can be used to get a distance between two points. The distance between the two points is returned as a double value. Optionally, the user can type a double value instead of specifying two points. If the user presses the spacebar or Enter without providing a value, an error is generated.
The following shows the syntax of the GetDistance
function:
retVal = object.GetDistance([basePoint], [msg])
Its arguments are as follows:
retVal
The retVal
argument represents the double that is the result of the function calculating the distance between the two points specified.object
The object
argument represents the AcadUtility
object.basePoint
The basePoint
argument is an optional argument that determines if a rubber-band line is drawn from the current position of the cursor to the coordinate value specified by the basePoint
argument. This argument value must be an array of three doubles. If a base point isn't provided, the user must specify two points instead of one.msg
The msg
argument is an optional string that defines the prompt message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.The following are examples of the GetDistance
function and the values that are returned:
Dim dRetVal as Double
dRetVal = oUtil.GetDistance(, vblf & "Enter or specify a width: ")
oUtil.Prompt vbLf & "Distance=" & CStr(dRetVal) & vbLf
Enter or specify a width: Pick a point in the drawing area, enter a coordinate value,
or enter a distance
Specify second point: If a point was specified, pick or enter a second point
Distance=6.25
Dim vPt As Variant, dRetVal As Double
vPt = oUtil.GetPoint(, vbLf & "Specify first point: ")
dRetVal = oUtil.GetDistance(vPt, vbLf & "Specify second point: ")
oUtil.Prompt vbLf & "Distance=" & CStr(dRetVal) & vbLf
Specify first point: Pick a point in the drawing area
Specify second point: Pick a point in the drawing area
Distance=7.0
A double value can be converted to a string that reflects the formatting of a supported linear distance with the RealToString
function. The RealToString
function accepts a double value of the distance to format as a string, a constant value from the AcUnits
enumerator to specify the linear format to apply, and an integer that indicates the precision in which the double should be formatted.
It is also possible to convert a string that is formatted as a supported linear distance to a double value with the DistanceToReal
function. The DistanceToReal
function accepts a string value and a constant value from the AcUnits
enumerator that indicates the linear formatting of the string. For more information about the RealToString
and DistanceToReal
functions, see the AutoCAD Help system.
The GetAngle
and GetOrientation
functions are used to obtain the angular difference between a vector defined by two points and the positive X-axis. The angular difference is expressed in radians, not decimal degrees or other angular measurement, and is returned as a double. If the user presses the spacebar or Enter without providing a value, an error is generated. The angular value returned by both functions is affected by the current value of the angdir
system variable, which defines the direction in which positive angles are measured: counterclockwise or clockwise.
The GetOrientation
function is also affected by the angbase
system variables. The angular value returned by GetOrientation
is calculated by adding the value specified by the user and that of the angbase
system variable. For example, changing angbase
to 45 and entering a value of 0 for the GetOrientation
function returns a value of 0.785398, which is the current value of angbase
. 0.785398 is the radians equivalent of 45 decimal degrees.
The following shows the syntax of the GetAngle
and GetOrientation
functions:
retVal = object.GetAngle([basePoint], [msg])
retVal = object.GetOrientation([basePoint], [msg])
The arguments of the two functions are the same as those of the GetDistance
function explained in the previous section. The following are examples of the GetAngle
function, and the values that are returned:
Dim dRetVal as Double
dRetVal = oUtil.GetAngle(, vblf & "Enter or specify an angle: ")
oUtil.Prompt vbLf & "Angle=" & CStr(dRetVal) & vbLf
Enter or specify an angle: Pick a point in the drawing area,
enter a coordinate value, or enter an angle
Specify second point: If a point was specified, pick or enter a second point
Angle= 0.785398
Dim vPt As Variant, dRetVal As Double
vPt = oUtil.GetPoint(, vbLf & "Specify first point: ")
dRetVal = oUtil.GetAngle(vPt, vbLf & "Specify second point: ")
oUtil.Prompt vbLf & "Angle=" & CStr(dRetVal) & vbLf
Specify first point: Pick a point in the drawing area
Specify second point: Pick a point in the drawing area
Angle=3.14159
Although AutoCAD uses and stores values in radians, users often think in decimal degrees. Listing 5.1 is a set of custom functions that can be used to convert radians to decimal degrees and decimal degrees to radians.
A double that represents an angular value can be converted to a string that reflects the formatting of a supported angular measurement with the AngleToString
function. The AngleToString
function accepts a double value of the angle to format as a string, a constant value from the AcAngleUnits
enumerator to specify the angular format to apply, and an integer that sets the precision in which the string should be formatted.
You can also convert a string that is formatted with a supported angular measurement to a double value with the AngleToReal
function. The AngleToReal
function accepts a string value and a constant value from the AcAngleUnits
enumerator to specify the angular formatting of the string. For more information about the AngleToString
and AngleToReal
functions, see the AutoCAD Help system.
String values are used to represent the prompts that should be displayed when requesting input, a block name, or path, and even the text to be added to an annotation object. You can use the GetString
function to request a string value at the Command prompt and control whether spaces are allowed in the string returned. The entered string is returned by the function, but if the user presses Enter without providing a value, an empty string (""
) is returned.
The following shows the syntax of the GetString
function:
retVal = object.GetString(allow_spaces, [msg])
Its arguments are as follows:
retVal
The retVal
argument represents the string that is returned by the function.object
The object
argument represents the AcadUtility
object.allow_spaces
The allow_spaces
argument determines whether the spacebar acts like the Enter key or if it allows the entering of a space character. By default, pressing the spacebar is the same as pressing Enter. Provide a value of True
to allow the user to enter a space character, or use False
to not allow spaces in the text entered. A conditional expression that evaluates to True
or False
can also be used.msg
The msg
argument is an optional string that defines the prompt message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.The following is an example of the GetString
function and the value that is returned:
Dim sRetVal As String
sRetVal = oUtil.GetString(True, vbLf & "Enter your name: ")
oUtil.Prompt vbLf & "Value=" & sRetVal & vbLf
Type your first and last (or family) name, then press Enter
"Lee Ambrosius"
The behavior of the Getxxx
functions can be modified with the InitializeUserInput
method of the AcadUtility
object. When you want to enable one or more of the alternate behaviors of a Getxxx
function, you include the InitializeUserInput
method before the Getxxx
function. In addition to controlling the alternate behaviors of the Getxxx
functions, InitializeUserInput
can be used to set up keyword usage for a function.
The following shows the syntax of the InitializeUserInput
method:
object.InitializeUserInput(flags, [keywords_list])
The flags
argument represents a bit-coded value that controls the type of input a Getxxx
function can accept. The flags
argument can contain one or more of the bits described in Table 5.1. Additional bits are available and described in the AutoCAD Help system; search on the keywords “InitializeUserInput method.”
Table 5.1 Bit codes available for the InitializeUserInput
method
Bit code | Description |
1 | User is not allowed to press Enter without first providing a value. Not supported for use with the GetString function. |
2 | Zero can't be entered when requesting a numeric value. |
4 | A negative value can't be entered when requesting a numeric value. |
32 | Rubber-band lines and rectangular boxes are shown as dashed instead of the default setting as solid. |
64 | Coordinate input is restricted to 2D points. |
128 | Arbitrary input is allowed; text values can be entered when using any of the Getxxx functions. |
The keywords_list
argument represents the keywords that the next Getxxx
function can support. The keywords must be placed in a string and each keyword separated by a space. The letters you want a user to be able to enter without typing the full keyword must be in uppercase, and I recommend that they be consecutive; all other letters in a keyword must be lowercase. The keywords_list
argument is optional. Examples of keyword lists are "Blue Green Red"
and "Azul Verde Rojo_Blue Green Red"
. The second example represents a keyword list that supports both localized and global languages; here the localized language is Spanish and the global language is typically English.
The global language value is used when an underscore is placed in front of a letter combination at the Command prompt. For example, typing A for the Azul option when the Spanish-language version of your program is loaded would work just fine but would fail if the English version was loaded. Entering _B instead would work with either the Spanish or English version of the program.
When a user enters a value that represents a keyword, an error is generated. Use the On Error Resume Next
statement to keep the VBA environment from displaying an error message. After the Getxxx
function is executed, check the value of the Err
object to determine if the user entered a keyword, pressed Enter without providing a value, or pressed Esc. If a keyword is entered, the name of the keyword can be obtained with the GetInput
function. The GetInput
function doesn't accept any arguments and returns a string that represents the keyword the user choose.
The following is an example of the InitializeUserInput
method that forces the user to provide a numeric value or enter a keyword option of Diameter with the GetDistance
function. The If
statement is used to determine if an error occurred and, if so, which error. Was the error caused by entering the keyword or by pressing Esc? The GetInput
function is used to return the keyword value.
On Error Resume Next
' Disables pressing Enter without first
' entering a number or Diameter keyword
oUtil.InitializeUserInput 1, "Diameter"
Dim vRetVal As Variant
vRetVal = oUtil.GetDistance(, vbLf & "Specify radius or [Diameter]: ")
' Check to see if the user entered a value or option
If Err.Number = -2145320928 Then
oUtil.Prompt vbLf & "Option=" & oUtil.GetInput & vbLf
ElseIf Err.Number = -2147352567 Then
oUtil.Prompt vbLf & "User pressed Esc" & vbLf
Else
oUtil.Prompt vbLf & "Distance=" & CStr(vRetVal) & vbLf
End If
Here are examples of values entered at the prompt displayed for the previous example code statement and the values returned:
Specify radius or [Diameter]: Type D and press Enter
Option=Diameter
Specify radius or [Diameter]: Type 7.5 and press Enter
Distance=7.5
The following is an example of the InitializeUserInput
method that restricts the user's input to positive and nonzero values:
On Error Resume Next
' Disables pressing Enter without first entering a number,
' and limits input to positive and nonzero values
oUtil.InitializeUserInput 7
Dim vRetVal As Variant
vRetVal = oUtil.GetInteger(vbLf & "Enter a number: ")
' Check to see if the user entered a value
If Not Err Then
oUtil.Prompt vbLf & "Value=" & CStr(vRetVal) & vbLf
End If
Here are examples of values entered at the prompt displayed for the previous example code statement, and the values returned:
Enter a number: Type -1 and press Enter
Value must be positive and nonzero.
Enter a number: Type 4 and press Enter
4
In addition to using keywords with the Getxxx
functions, you can use the GetKeyword
function to prompt the user for just keyword values. The GetKeyword
function accepts input only in the form of a keyword value unless arbitrary input is enabled with the 128 bit-code of the InitializeUserInput
method; in that case, the function can accept any string input. The GetKeyword
function can return only a string value—it can't return numbers or arrays representing coordinate values. The InitializeUserInput
method must be used to set up the keywords that the GetKeyword
function can accept.
The following shows the syntax of the GetKeyword
function:
retVal = object.GetKeyword([msg])
The msg
argument represents the textual message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.
The following is an example of the GetKeyword
function and the value that is returned:
On Error Resume Next
' Sets up the keywords for the GetKeyword function
oUtil.InitializeUserInput 0, "Color LTYpe LWeight LTScale"
Dim vRetVal As Variant
vRetVal = oUtil.GetKeyword( _
vbLf & "Enter option [Color/LTYpe/LWeight/LTScale] <Color>: ")
' Check to see if the user specified an option
If Err.Number = -2145320928 Then
oUtil.Prompt vbLf & "Option=" & oUtil.GetInput & vbLf
ElseIf Err.Number = -2147352567 Then
oUtil.Prompt vbLf & "User pressed Esc" & vbLf
Else
If vRetVal = "" Then
oUtil.Prompt vbLf & "Enter pressed w/o an option" & vbLf
Else
oUtil.Prompt vbLf & "Value=" & vRetVal & vbLf
End If
End If
Here are examples of values entered at the prompt displayed for the previous example code statement, and the values returned:
Enter option [Color/LTYpe/LWeight/LTScale] <Color>: Type C and press Enter
Option=Color
Enter option [Color/LTYpe/LWeight/LTScale] <Color>: Type L and press Enter
Ambiguous response, please clarify…
LTYpe or LWeight or LTScale? Type LW and press Enter
Option=LWeight
Although a program can simply request information from users and go on its way, it is best to acknowledge users and provide them with some feedback. Now this doesn't mean you need to make small talk with the person on the other side of the screen; it also doesn't mean you should share your life story. Based on the tasks your program might perform, you may want to provide information to the user when a macro does one of the following:
fillet
or style
command.In the “Requesting Input at the Command Prompt” section earlier, you learned how to display a message when requesting input from the user with one of the Getxxx
functions. Messages can also be displayed at the Command prompt with the Prompt
method of the AcadUtility
object.
The following shows the syntax of the Prompt
method:
object.Prompt(msg)
The msg
argument represents the textual message to display at the Command prompt. As part of the textual message, you can use the constant vbLf
to force the message on a new line, vbTab
to add a Tab character, and """
to represent a quotation mark character. The vbBack
constant, which emulates a press of the Backspace key, can also be useful in removing the Command:
text from the Command prompt, thereby giving you a completely clean Command prompt. Use nine vbBack
constants in a row to remove Command:
. For a full list of supported constants that can be used in strings, search on the “Miscellaneous Constants” topic in the Microsoft VBA Help system. In the VBA Editor, click Help Microsoft Visual Basic For Applications Help.
The following are examples of the Prompt
method and the values that are returned:
Dim oUtil As AcadUtility
Set oUtil = ThisDrawing.Utility
oUtil.Prompt vbLf & "Current OSMODE value: " & _
CStr(ThisDrawing.GetVariable("OSMODE")) & vbLf
Current OSMODE value: 4133
oUtil.Prompt vbLf & "Drawing Name: "
oUtil.Prompt CStr(ThisDrawing.GetVariable("DWGNAME")) & vbLf
Drawing Name: Drawing1.dwg
A message at the Command prompt is a common way of displaying information to the user when you don't want to interrupt the user's workflow. However, you can also display information in a message box (which the user must acknowledge before the program continues).
The MsgBox
function of the VBA programming language can display a simple message box with a custom message and only an OK button. Message boxes can also contain a standard icon and button configuration that contains more than just an OK button. The MsgBox
function returns a value that you can use to determine which button the user clicked. You can learn about the icons and button configurations that the MsgBox
function supports in the Microsoft VBA Help system. In the VBA Editor, click Help Microsoft Visual Basic For Applications Help.
The following is an example of displaying a message with the MsgBox
function and how to determine which button the user pressed. Figure 5.3 shows the first message box that is displayed when the example code is executed.
Dim nRetVal As Integer
nRetVal = MsgBox("Do you want to continue?", _
vbYesNoCancel + vbQuestion, "Continue")
Select Case nRetVal
Case vbYes
MsgBox "Yes was clicked"
Case vbNo
MsgBox "No was clicked"
Case vbCancel
MsgBox "Cancel was clicked"
End Select
The AutoCAD Object library enables you to step through all of the objects in a drawing or allow the user to interactively select objects in the drawing area. I explained how to get an object from model space without user input in Chapter 4, “Creating and Modifying Drawing Objects.” Using the selection techniques supported by the AutoCAD Object library, the user can be prompted to select a single object or a selection set can be created and the user allowed to select multiple objects.
The user can be prompted to select a single object in the drawing area with the GetEntity
method of the AcadUtility
object. The GetEntity
method returns two values: the selected object and the center point of the pick box when the object was selected. If no object is selected, an error is generated that must be handled to continue execution.
The following shows the syntax of the GetEntity
method:
object.GetEntity(selectedObject, pickPoint, [msg])
Its arguments are as follows:
object
The object
argument represents the AcadUtility
object.selectedObject
The selectedObject
argument represents the variable that will be assigned the object that the user selected. The value assigned to the variable is of the Object data type.pickPoint
The pickPoint
argument represents the variable that will be assigned the center point of the pick box when the object was selected. The value assigned to the variable is an array of three doubles.msg
The msg
argument is an optional string that defines the prompt message to display at the Command prompt. The msg
argument is optional, but I recommend always providing one.The following is an example of the GetEntity
method. The example prompts the user for an object and displays a message with the name of the object selected or a general message if no object was selected.
' Continue on error
On Error Resume Next
' Prompt the user for an object
Dim vObj As Object, vPt As Variant
ThisDrawing.Utility.GetEntity vObj, vPt, vbLf & "Select an object: "
' If an object was selected, display its object name
If Not vObj Is Nothing Then
MsgBox "Type of object selected: " & vObj.ObjectName
Else
MsgBox "No object selected."
End If
The GetEntity
method allows you to select an object as a whole, but not an entity inside of an object known as a subentity. The GetSubEntity
method is similar to GetEntity
except that GetSubEntity
allows you to select an entire object or a subentity within an object such as an old-style polyline, dimension, or block. When the GetSubEntity
method is used, it expects four arguments and can accept an optional prompt message. The four values that the GetSubEntity
method returns are (in this order):
For more information on the GetSubEntity
method, see the AutoCAD Help system.
A grouping of selected objects in the AutoCAD drawing environment is known as a selection set. A selection set is a named container that holds references to objects in a drawing and exists only while a drawing remains open. From the AutoCAD user interface, a selection set is created when a user selects one or more objects at the Select objects:
prompt.
In the AutoCAD Object library, a selection set is represented by an AcadSelectionSet
object and all selection sets in a drawing are stored in the AcadSelectionSets
collection object. The AcadSelectionSets
collection object of a drawing is accessed using the SelectionSets
property of an AcadDocument
or ThisDrawing
object.
In addition to the SelectionSets
property, an AcadDocument
or ThisDrawing
object has two other properties that are related to selection sets: ActiveSelectionSet
and PickfirstSelectionSet
. Both properties are read-only. The ActiveSelectionSet
property returns an AcadSelectionSet
object that represents the active selection set of the drawing. The PickfirstSelectionSet
property returns an AcadSelectionSet
object that contains a selection set of the objects contained in the pickfirst selection. The pickfirst selection is made up of the objects that were selected before the execution of the VBA macro.
A selection set must be created or obtained before a user can be requested to select objects. The Add
function of the AcadSelectionSets
collection object creates a new selection set with the provided name and returns an AcadSelectionSet
object. If you want to work with an existing selection set, use the Item
method or a For
statement on the AcadSelectionSets
collection object to obtain an AcadSelectionSet
object. When a selection set is no longer needed, use the Delete
method of the AcadSelectionSet
object to be removed.
The following example creates a new selection set or returns an existing selection if one already exists with the same name:
On Error Resume Next
' Create a new selection set named NewSS
Dim oSSet As AcadSelectionSet
Set oSSet = ThisDrawing.SelectionSets.Add("NewSS")
' Check for an error, if so get the existing selection set
If Err Then
Err.Clear
Set oSSet = ThisDrawing.SelectionSets.Item("NewSS")
' Reset the selection set
oSSet.Clear
End If
' Perform selection tasks here and work with the objects selected
' When done with a selection set, it is best to remove it
oSSet.Delete
After a selection set has been created or an existing one obtained from the AcadSelectionSets
collection object, you can work with the objects in the selection set or prompt the user to select objects in a drawing. The AddItems
method of an AcadSelectionSet
object allows you to add an array of objects to a selection set. Table 5.2 lists additional methods that can be used to manually add objects to a selection set by their placement in the drawing area.
Table 5.2 Object selection methods
Method | Description |
Select |
Adds objects to a selection set by selection mode: all objects, crossing window, last object added to a drawing, previous selected objects, or window. The method expects a selection mode that is a constant value from the AcSelect enumerator, and two optional arrays of three doubles that represent points in the drawing area. |
SelectAtPoint |
Adds an object to a selection set at a point in the drawing; the object selected is the topmost in the draw order at that point. The method expects an array of three doubles that represents a point in the drawing area. |
SelectByPolygon |
Adds objects to a selection set by selection mode: crossing polygon, fence, or window polygon. The method expects a selection mode that is a constant value from the AcSelect enumerator, and an array of doubles that represents multiple point values in the drawing area. |
The Select
, SelectAtPoint
, and SelectByPolygon
methods support object selection filtering with two optional arguments. I discuss object selection filtering in the next section. For more information on adding objects to a selection set with the Select
, SelectAtPoint
, and SelectByPolygon
methods, see the AutoCAD Help system.
Although adding objects manually to a selection set has its benefits, it is more common to prompt the user to select the objects that should be modified or queried. The SelectOnScreen
method of an AcadSelectionSet
object allows the user to interactively select objects in the drawing area using the standard selection methods. The SelectOnScreen
method also supports object selection filtering.
The following shows the syntax of the SelectOnScreen
method:
object.SelectOnScreen([filterType, filterData])
Its arguments are as follows:
object
The object
argument represents the AcadSelectionSet
object.filterType
The filterType
argument is an optional array of integers that represents the DXF code groups that you want to filter objects on.filterData
The filterData
argument is an optional array of variants that represents the values that you want to filter objects on.I explain how to define the arrays used to filter objects during selection in the “Filtering Objects” section later in this chapter.
Objects are typically only added to a selection set, but they can also be removed from a selection set. You might want to remove one or more objects from a selection set that don't meet certain criteria. One or more objects can be removed from a selection set with the RemoveItems
method. The RemoveItems
method is similar to the AddItems
method, and it accepts an array of objects that should be removed from the selection set.
The following example prompts the user to select objects using the SelectOnScreen
method, and adds the first and last objects in the drawing to the selection set named NewSS with the AddItems
and Select
methods. The last object is also removed to demonstrate the use of the RemoveItems
method.
' Prompt the user for objects
ThisDrawing.Utility.Prompt vbLf & "Select objects to list: "
oSSet.SelectOnScreen
' Add the first object in model space to the selection set
Dim arObj(0) As AcadEntity
Set arObj(0) = ThisDrawing.ModelSpace(0)
oSSet.AddItems arObj
' Add the last object in the drawing to the selection set
oSSet.Select acSelectionSetLast
' Remove the last object in model space from
' the selection set
Set arObj(0) = ThisDrawing.ModelSpace( _
ThisDrawing.ModelSpace.Count - 1)
oSSet.RemoveItems arObj
A selection set isn't any different than any other collection object. You can use the Item
function of an AcadSelectionSet
object to get a specific object in a selection set or a For
statement to step through all the objects in a selection set. In addition to the Item
function and For
statement, you can use a While
statement in combination with the Item
function to step through all the objects in a selection set. The Count
property of an AcadSelectionSet
object lets you know how many objects are in a selection set; this value can be helpful when you are using the Item
function or a While
statement.
The following example steps through all the objects in a selection set and outputs the object name for each object to the command-line window:
' Step through each object in the selection set and output
' the name of each object with the Prompt method
Dim oEnt As AcadEntity
ThisDrawing.Utility.Prompt vbLf & "Objects in " & _
oSSet.Name & " selection set:"
For Each oEnt In oSSet
ThisDrawing.Utility.Prompt vbLf & " " & oEnt.ObjectName
Next oEnt
' Return the user to a blank Command prompt
ThisDrawing.Utility.Prompt vbLf & ""
Here is an example of the output that might be displayed in the command-line window:
Objects in NewSS selection set:
AcDbLine
AcDbLine
AcDbLine
AcDbLine
AcDbCircle
AcDbArc
The particular objects that are added to a selection set can be affected through the use of an optional selection filter. A selection filter can be used to limit the objects added to a selection set by type and property values. Filtering is defined by the use of two arrays with the same number of elements. Selection filters are supported by the Select
, SelectAtPoint
, SelectByPolygon
, and SelectOnScreen
methods of the AcadSelectionSet
object. The two arrays are passed to the filterType
and filterData
arguments of the methods.
The first array of a selection filter contains only integer values that represent DXF group codes and the types of data that will be used to restrict object selection. The second array defines the actual values for the selection filter. The type of data to filter on can be a string, integer, or double, among other data types. When selection filter is used, objects are only selected when all conditions of the selection set are True
.
For example, if you filter on circles that are placed on the Holes layer, only circles placed on the Holes layer will be added to the selection set. Lines and other objects placed on the layer named Holes will not be selected; circles on other layers will not be selected.
The following is an example of a selection filter that can be used to select the circles placed on the layer named Holes:
Dim arDXFCodes(1) As Integer, arValues(1) As Variant
' Object type
arDXFCodes(0) = 0: arValues(0) = "circle"
' Object layer
arDXFCodes(1) = 8: arValues(1) = "Holes"
' Prompt for and restrict the selection of objects with a selection filter
ThisDrawing.Utility.Prompt
vbLf & "Select circles with a radius between 1 and 5: "
oSSet.SelectOnScreen arDXFCodes, arValues
In the previous example, the arDXFCodes
variable contains an array of integer values that includes two DXF group codes. The DXF group code 0 represents an object's type, and the DXF group code 8 represents the name of the layer which an object is placed. For more information on DXF group codes, use the AutoCAD Help system and search on the keywords “dxf codes.”
Object types and properties are not the only values that can be used to filter objects—a filter can also include logical grouping and comparison operators. Logical grouping and comparison operators allow for the selection of several object types, such as both text and MText
objects, or allow for the selection of circles with a radius in a given range. Logical grouping and comparison operators are specified by string values with the DXF group code -4. For example, the following filter allows for the selection of circles with a radius in the range of 1 to 5:
Dim arDXFCodes(6) As Integer, arValues(6) As Variant
' Object type
arDXFCodes(0) = 0: arValues(0) = "circle"
' Start AND grouping
arDXFCodes(1) = -4: arValues(1) = "<and"
' Select circles with a radius between 1 and 5
arDXFCodes(2) = -4: arValues(2) = "<="
arDXFCodes(3) = 40: arValues(3) = 5#
arDXFCodes(4) = -4: arValues(4) = ">="
arDXFCodes(5) = 40: arValues(5) = 1#
' End AND grouping
arDXFCodes(6) = -4: arValues(6) = "and>"
Selection filters support four logical grouping operators: and
, or
, not
, and xor
. Each logical grouping operator used in a selection filter must have a beginning and ending operator. Beginning operators start with the character < and ending operators end with the character >. In addition to logical operators, you can use seven different comparison operators in a selection filter to evaluate the value of a property: =
(equal to), !=
(not equal to), <
(less than), >
(greater than), <=
(less than or equal to), >=
(greater than or equal to), and *
(wildcard for string comparisons).
In addition to object types and property values, selection filters can filter on objects with attached extended data (Xdata). Xdata is used to add custom information to an object in a drawing. I discuss working with and selecting objects that have attached Xdata in Chapter 9, “Storing and Retrieving Custom Data.”
The math functions of the VBA programming language are great for calculating numeric values based on other numeric values, but they aren't specifically designed to work with geometric values. With the AutoCAD Object library and standard math formulas, you can calculate the following:
When you create or modify an object, you frequently need to calculate a new point based on another point on or near an existing graphical object. Although you could prompt the user to specify a point you might need, that could lead to unnecessary steps in a workflow, so it is always best to calculate any and all points that you can with minimal input from the user.
The PolarPoint
function returns a 2D or 3D point in the current UCS, based on an angle and distance from a point. The result of the PolarPoint
function is similar to specifying a relative polar coordinate from the AutoCAD user interface.
The following shows the syntax of the PolarPoint
function:
retVal = object.PolarPoint(point, angle, distance)
Its arguments are as follows:
retVal
The retVal
argument represents the variant value that contains the new coordinate point that was calculated as an array of two or three doubles.object
The object
argument represents the AcadUtility
object.point
The point
argument represents the coordinate point in the drawing that you want to calculate the new point from. If a 2D point is specified, a 2D point is returned; specifying a 3D point results in a 3D point being returned.angle
The angle
argument represents the angle, in radians, by which the new point should be separated from the coordinate point specified with the point
argument.distance
The distance
argument represents the distance at which the new point should be calculated from the point
argument and along the angle specified by the angle
argument.The following is an example of the PolarPoint
function:
Dim oUtil As AcadUtility
Set oUtil = ThisDrawing.Utility
Dim pt1(2) As Double
pt1(0) = 0: pt1(1) = 0: pt1(2) = 0
Dim vPt As Variant
vPt = oUtil.PolarPoint(pt1, 0.785398, 5#)
' Returns the calculated coordinate value
oUtil.Prompt vbLf & "X=" & CStr(vPt(0)) & _
" Y=" & CStr(vPt(1)) & _
" Z=" & CStr(vPt(2)) & vbLf
X=3.53553448362991 Y=3.53553332823547 Z=0
The AutoCAD Object library doesn't provide a function to calculate the distance between two points; instead you must rely on a geometric formula. The geometric formula is shown in Figure 5.4, and the VBA equivalent is as follows:
' Distance of 3D points
Sqr((X2 - X1) ^ 2 + (Y2 - Y1) ^ 2 + (Z2 - Z1) ^ 2)
If you need to calculate the distance between 2D points, the code statement in VBA might be as follows:
' Distance of 2D points
Sqr((X2 - X1) ^ 2 + (Y2 - Y1) ^ 2)
Listing 5.2 shows a custom function named Distance
that can be used to calculate the distance between two points in the drawing area. The value returned is a double number.Here is an example of using the custom Distance
function from Listing 5.2:
Dim pt1(2) As Double, pt2(2) As Double
pt1(0) = 0: pt1(1) = 0: pt1(2) = 0
pt2(0) = 2: pt2(1) = 2: pt2(2) = 2
ThisDrawing.Utility.Prompt vbLf & _
"Distance=" & CStr(Distance(pt1, pt2)) & vbLf
Distance=3.46410161513775
When you draw or modify an object, you commonly need to know the angle at which an object should be drawn in relationship to the X-axis or other objects in a drawing. The AngleFromXAxis
function accepts two arrays of three elements that define the line from which you want to calculate the angular value.
The following shows the syntax of the AngleFromXAxis
function:
retVal = object.AngleFromXAxis(fromPoint, toPoint)
Its arguments are as follows:
retVal
The retVal
argument represents the angular value expressed in radians from the X-axis. The value is returned as a double.object
The object
argument represents the AcadUtility
object.fromPoint
The fromPoint
argument is an array of three doubles that defines the start point of the line.toPoint
The toPoint
argument is an array of three doubles that defines the end point of the line.The following is an example of the AngleFromXAxis
function:
Dim oUtil As AcadUtility
Set oUtil = ThisDrawing.Utility
Dim pt1(2) As Double, pt2(2) As Double
pt1(0) = 0: pt1(1) = 0: pt1(2) = 0
pt2(0) = 5: pt2(1) = 5: pt2(2) = 0
oUtil.Prompt vbLf & _
"Angle=" & CStr(oUtil.AngleFromXAxis(pt1, pt2)) & vbLf
Angle=0.785398163397448
The view of model space can be adjusted to show a specific area of a drawing or the full extents of all objects in model space. You can adjust the area and magnification of the current view, and store a view that can later be restored in model space or applied to a floating viewport on a named layout. In addition to managing named views, you can divide model space into multiple viewports known as tiled viewports. Each tiled viewport can display a different view of model space and can be helpful when modeling in 3D. Visual styles can also be used to affect the way objects appear in a view or viewport.
You can manipulate the current model space view by adjusting its scale and center in which objects should be displayed; this is typically known as zooming and panning. When you want to zoom or pan the current view, you will use the zoom-related methods of the AcadApplication
object. You can get a reference to the AcadApplication
object with the Application
property of an AcadDocument
or ThisDrawing
object. Table 5.3 lists the different zoom-related methods that are available from the AcadApplication
object.
Table 5.3 Zoom-related methods
Method | Description |
ZoomAll |
Fills the current view with the extents of the drawing limits or all graphical objects depending on which is largest. |
ZoomCenter |
Defines the center point of the current view, and increases or decreases the objects based on a specified magnification. |
ZoomExtents |
Fills the current view with the extents of all graphical objects. |
ZoomPickWindow |
Prompts the user for two points. The points define the area of the drawing and magnification in which the objects should be displayed. |
ZoomPrevious |
Restores the most recent view. |
ZoomScaled |
Increases or decreases the magnification of the current view; the center point of the view remains unchanged. |
ZoomWindow |
Defines the area of the drawing and magnification in which the objects should be displayed. |
For specifics on the arguments that each of the methods listed in Table 5.3 expects, see the AutoCAD Help system. The following is an example of the ZoomExtents
method:
' Set model space current
ThisDrawing.ActiveSpace = acModelSpace
Dim dPt1(2) As Double, dPt2(2) As Double
dPt1(0) = 1: dPt1(1) = 5: dPt1(2) = 0
dPt2(0) = 7: dPt2(1) = 3: dPt2(2) = 0
' Add a line to model space
ThisDrawing.ModelSpace.AddLine dPt1, dPt2
' Zoom to the extents of model space
ThisDrawing.Application.ZoomExtents
Although it might not seem obvious, you can use the ZoomCenter
method to pan the current view. The following example gets the center point and magnification of the current view with the viewctr
and viewsize
system variables. Once the center point is obtained from the viewctr
system variable, the point is adjusted to pan the current view 10 units to the right. The new center point and current magnification are passed to the ZoomCenter
method to cause the current view to be panned and not zoomed.
' Get the current values of the viewctr
' and viewsize system variables
Dim vViewPt As Variant, dViewSize As Double
vViewPt = ThisDrawing.GetVariable("viewctr")
dViewSize = ThisDrawing.GetVariable("viewsize")
' Pan the viewport 10 drawing units to the right
vViewPt(0) = vViewPt(0) - 10
ThisDrawing.Application.ZoomCenter vViewPt, dViewSize
The Model tab in the AutoCAD user interface is used to view and interact with the graphical objects of the model space block. By default, the objects in model space are displayed in a single tiled viewport named *Active
. Tiled viewports aren't the same as the viewports displayed on a named layout tab; they do share some properties and methods in common, though. You use tiled viewports to view different areas or angles of the same drawing, whereas you use viewports on a named layout to control which model space objects are plotted, the angle in which objects are viewed, and at which scale. I discuss the viewports that can be added to a named layout in Chapter 8, “Outputting Drawings.”
Each tiled viewport in model space can be split into two or more smaller viewports, but only one viewport can be active at a time. Unlike with the AutoCAD user interface, you can't join viewports back together again once they have been split; instead, you need to create a new configuration that reflects the desired layout and set it as current. Use the name of the active viewport to determine which viewports are part of the active viewport configuration.
You can access the active model space viewport with the ActiveViewport
property of an AcadDocument
or Thisdrawing
object. The ActiveViewport
property returns an AcadViewport
object that represents a tiled viewport in model space. Not only is the ActiveViewport
property used to get the active viewport, but it is also used to set a viewport configuration as active. Once you have the active viewport, you can modify the drafting aids that are viewport specific along with the current model view.
In addition to working with the active viewport, you can create and manage named viewport configurations with the AcadViewports
collection object. You use the Add
function of the AcadViewports
collection object to create a new viewport configuration, and the Item
function or a For
statement to step through all the viewports of a viewport configuration. Named viewport configurations that are no longer needed can be removed using the DeleteConfiguration
method on the AcadViewports
collection object, not the Delete
method of the AcadViewport
object like other collection objects.
The following code statements split the current active viewport vertically into two viewports and then change some of the drafting aids related to the active viewport:
' Get the name of the current viewport configuration
Dim sVpName As String
sVpName = ThisDrawing.ActiveViewport.Name
' Create a new viewport with the same name
' as the active viewport
Dim oVPort As AcadViewport
Set oVPort = ThisDrawing.Viewports.Add(sVpName)
' Split the active viewport vertically
oVPort.Split acViewport2Vertical
' Turn off the grid and snap in the new viewport
oVPort.GridOn = False
oVPort.SnapOn = False
' Turn on Ortho mode
oVPort.OrthoOn = True
' Set the viewport active
ThisDrawing.ActiveViewport = oVPort
' Set snap style to rectangular
ThisDrawing.SetVariable "snapstyl", 0
Using the AcadViewport
object returned by the Add
function of the AcadViewports
collection object or the ActiveViewport
property, you can obtain information about the current view and some of the drafting aids that are enabled. Table 5.4 lists the properties of the AcadViewport
object.
Table 5.4 Properties related to an AcadViewport
object
Property | Description |
ArcSmoothness |
Specifies the smoothness for curved model space objects. Enter a value from 1 to 20,000. |
Center |
Specifies an array of three double values that represents the center point of the view in the viewport. |
Direction |
Specifies the view direction of the model space objects. View direction is expressed as an array of three double values. |
GridOn |
Specifies whether grid display is enabled. A Boolean value of True indicates the grid display is on. |
Height |
Specifies the height of the view in drawing units, not pixels. This value corresponds to the magnification factor of the current view. The value returned or expected is a double. |
LowerLeftCorner |
Specifies an array of two double values that represents the lower-left corner of the viewport. |
Name |
Specifies the name of the configuration in which the viewport is associated. |
OrthoOn |
Specifies whether Ortho mode is enabled. A Boolean value of True indicates Ortho mode is on. |
SnapBasePoint |
Specifies an array of two double values that represents the base point of the snap grid for the viewport. |
SnapOn |
Specifies whether snapping is enabled. A Boolean value of True indicates snapping is on. |
SnapRotationAngle |
Specifies the angle in which the snap grid is rotated. The value returned or expected is a double that represents the angle in radians. |
Target |
Specifies the target point of the current view in the viewport. View direction is expressed as an array of three double values. |
UCSIconAtOrigin |
Specifies whether the UCS icon is displayed at the origin of the drawing. A Boolean value of True indicates the UCS icon is displayed at the drawing's origin, or in the lower-left corner of the drawing area if the origin is off the screen. |
UCSIconOn |
Specifies whether the UCS icon is displayed in the drawing area. A Boolean value of True indicates the UCS icon is displayed. |
UpperRightCorner |
Specifies an array of two double values that represents the upper-right corner of the viewport. |
Width |
Specifies the width of the view in drawing units, not pixels. This value corresponds to the magnification factor of the current view. The value returned or expected is a double. |
In addition to the GridOn
and SnapOn
properties that allow you to turn on grid display and enable snapping to grid, you can use the GetGridSpacing
and GetSnapSpacing
methods to get the current grid and snap spacing. Both of the methods expect two arguments that are used to return the X and Y spacing values for the grid or snap. To change the spacing of the grid and snap, use the SetGridSpacing
and SetSnapSpacing
methods, which expect two double values that represent the X and Y spacing values for the grid or snap.
A named view can be assigned to a model space viewport using the SetView
function. I explain how to work with named views in the next section. For more information on working with tiled viewports, see the AutoCAD Help system.
Named views are areas in a drawing with a user-defined name that can later be restored to improve navigation around a large drawing and even help to output various areas of a drawing with viewports on a named layout. Many users associate named views with 3D modeling, but they can be just as helpful with designs that consist of just 2D objects. Named views are stored in the AcadViews
collection object, which you can access from the Views property of the AcadDocument
or ThisDrawing
object. Each view stored in the AcadViews
collection object is represented by an AcadView
object.
You can create a new named view with the Add
function of the AcadViews
collection object. If you want to work with an existing view, use the Item
function of the AcadViews
collection object or a For
statement to get the AcadView
object that represents the named view you want to modify or query. Once a named view has been created, you can pass the AcadView
object to the SetView
method of an AcadViewport
or AcadPViewport
object to restore the view. If you no longer need a named view, you can use the Delete
method of the AcadView
object to be removed.
Table 5.5 lists the properties of an AcadView
object that can be used to modify or query a named view.
Table 5.5 Properties related to an AcadView
object
Property | Description |
CategoryName |
Specifies a category name for the view. The category name is used to group multiple views on the ShowMotion bar when it is pinned and controls how named views are organized in sheet sets. |
Center |
Specifies an array of three double values that represents the center point of the view. |
Direction |
Specifies the direction from which the objects in the model space should be viewed. View direction is expressed as an array of three double values. |
HasVpAssociation |
Specifies whether the view is associated with a viewport. A Boolean value of True indicates that the view is associated with a viewport placed from the Sheet Set Manager. |
Height |
Specifies the height of the view in drawing units, not pixels. The value returned or expected is a double. |
LayerState |
Specifies the name of the layer state that should be restored when the view is restored. I discussed layer states in Chapter 4. |
LayoutId |
Specifies the object ID of the layout that the view is associated with. Model space views can't be used on a named layout and a named layout can't be used on the Model tab. |
Name |
Specifies the name of the named view. |
Target |
Specifies the target point of the view. The target is expressed as an array of three double values. |
Width |
Specifies the width of the view in drawing units, not pixels. This value corresponds to the magnification factor of the view. The value returned or expected is a double. |
For more information on working with named views, see the AutoCAD Help system.
Visual styles affect the way 2D and 3D objects are displayed on screen and how they are plotted. The AutoCAD Object library offers very limited support when it comes to managing visual styles. Using the AutoCAD Object library, you can obtain a listing of which visual styles are stored in a drawing by accessing the ACAD_VisualStyles
dictionary. I explain how to work with dictionaries in Chapter 9.
If you need to create or update a visual style using the AutoCAD Object library, set as current the visual style that you want to base the new visual style on or modify with the vscurrent
command. Once the visual style is current, modify the values of the system variables related to visual styles. Many of the system variables that are related to visual styles begin with the prefix VS
.
Use the SetVariable
and GetVariable
methods to work with the system variables. After the variables have been updated, use the vssave
command to save the new visual style or overwrite an existing visual style with the same name. You can assign a visual style to model space with the vscurrent
command, or use the VisualStyle
property of an AcadPViewport
object, which represents a floating viewport on a named layout. I explain how to work with floating viewports in Chapter 8.
In this section, you will continue to build on the DrawPlate
project that was introduced in Chapter 4. The key concepts I cover in this exercise are as follows:
True
. You can use a loop to keep allowing the user to provide input.The changes to the CLI_DrawPlate
function implement the use of user input to get points and distances. The points and distances provided by the user are used to specify the size and location of the plate in the drawing. The following steps have you replace the CLI_DrawPlate
function with a newer version in the drawplate.dvb
project file:
drawplate.dvb
file into the AutoCAD drawing environment and display the VBA Editor.basDrawPlate
component.Private myUtilities As New clsUtilities
Private g_drawplate_width As Double
Private g_drawplate_height As Double
' Constants for PI and removal of the "Command: " prompt msg
Const PI As Double = 3.14159265358979
Const removeCmdPrompt As String = vbBack & vbBack & vbBack & _
vbBack & vbBack & vbBack & _
vbBack & vbBack & vbBack & vbLf
Public Sub CLI_DrawPlate()
Dim oLyr As AcadLayer
On Error Resume Next
Dim sysvarNames As Variant, sysvarVals As Variant
sysvarNames = Array("nomutt", "clayer", "textstyle")
' Store the current value of system variables to be restored later
sysvarVals = myUtilities.GetSysvars(sysvarNames)
' Set the current value of system variables
myUtilities.SetSysvars sysvarNames, Array(0, "0", "STANDARD")
' Define the width and height for the plate
If g_drawplate_width = 0 Then g_drawplate_width = 5#
If g_drawplate_height = 0 Then g_drawplate_height = 2.75
' Get recently used values from the global variables
Dim width As Double, height As Double
width = g_drawplate_width
height = g_drawplate_height
' Prompt for the current values
ThisDrawing.Utility.Prompt removeCmdPrompt & "Current width: " & _
Format(ThisDrawing.Utility. _
RealToString(width, acDecimal, 4), _
"0.0000") & _
" Current height: " & _
Format(ThisDrawing.Utility. _
RealToString(height, acDecimal, 4), _
"0.0000") & _
vbLf
Dim basePt As Variant
' Continue to ask for input until a point is provided
Do
Dim sKeyword As String
sKeyword = ""
basePt = Null
' Set up default keywords
ThisDrawing.Utility.InitializeUserInput 0, "Width Height"
' Prompt for a base point, width, or height value
basePt = ThisDrawing.Utility.GetPoint(, _
removeCmdPrompt & _
"Specify base point for plate or [Width/Height]: ")
' If an error occurs, the user entered a keyword or pressed Enter
If Err Then
Err.Clear
sKeyword = ThisDrawing.Utility.GetInput
Select Case sKeyword
Case "Width"
width = ThisDrawing.Utility. _
GetDistance(, removeCmdPrompt & _
"Specify the width of the plate <" & _
Format(ThisDrawing.Utility. _
RealToString(width, acDecimal, 4), _
"0.0000") & _
">: ")
Case "Height"
height = ThisDrawing.Utility. _
GetDistance(, removeCmdPrompt & _
"Specify the height of the plate <" & _
Format(ThisDrawing.Utility. _
RealToString(height, acDecimal, 4), _
"0.0000") & _
">: ")
End Select
End If
' If a base point was specified, then draw the plate
If IsNull(basePt) = False Then
' Create the layer named Plate or set it current
Set oLyr = myUtilities.CreateLayer("Plate", acBlue)
ThisDrawing.ActiveLayer = oLyr
' Create the array that will hold the point list
' used to draw the outline of the plate
Dim dPtList(7) As Double
dPtList(0) = basePt(0): dPtList(1) = basePt(1)
dPtList(2) = basePt(0) + width: dPtList(3) = basePt(1)
dPtList(4) = basePt(0) + width: dPtList(5) = basePt(1) + height
dPtList(6) = basePt(0): dPtList(7) = basePt(1) + height
' Draw the rectangle
myUtilities.CreateRectangle dPtList
' Create the layer named Holes or set it current
Set oLyr = myUtilities.CreateLayer("Holes", acRed)
ThisDrawing.ActiveLayer = oLyr
Dim cenPt1 As Variant, cenPt2 As Variant
Dim cenPt3 As Variant, cenPt4 As Variant
Dim dAng As Double, dDist As Double
' Calculate the placement of the circle in the lower-left corner.
' Calculate a new point at 45 degrees and distance of 0.7071 from
' the base point of the rectangle.
cenPt1 = ThisDrawing.Utility.PolarPoint(basePt, PI / 4, 0.7071)
myUtilities.CreateCircle cenPt1, 0.1875
' Calculate the distance between the first
' and second corners of the rectangle.
dDist = myUtilities.Calc2DDistance(dPtList(0), dPtList(1), _
dPtList(2), dPtList(3))
' Calculate and place the circle in the lower-right
' corner of the rectangle.
dAng = myUtilities.Atn2(dPtList(2) - dPtList(0), _
dPtList(3) - dPtList(1))
cenPt2 = ThisDrawing.Utility.PolarPoint(cenPt1, dAng, dDist - 1)
myUtilities.CreateCircle cenPt2, 0.1875
' Calculate the distance between the second
' and third corners of the rectangle.
dDist = myUtilities.Calc2DDistance(dPtList(2), dPtList(3), _
dPtList(4), dPtList(5))
' Calculate and place the circle in the upper-right
' corner of the rectangle.
dAng = myUtilities.Atn2(dPtList(4) - dPtList(2), _
dPtList(5) - dPtList(3))
cenPt3 = ThisDrawing.Utility.PolarPoint(cenPt2, dAng, dDist - 1)
myUtilities.CreateCircle cenPt3, 0.1875
' Calculate and place the circle in the upper-left
' corner of the rectangle.
dAng = myUtilities.Atn2(dPtList(6) - dPtList(0), _
dPtList(7) - dPtList(1))
cenPt4 = ThisDrawing.Utility.PolarPoint(cenPt1, dAng, dDist - 1)
myUtilities.CreateCircle cenPt4, 0.1875
End If
Loop Until IsNull(basePt) = True And sKeyword = ""
' Restore the saved system variable values
myUtilities.SetSysvars sysvarNames, sysvarVals
' Save previous values to global variables
g_drawplate_width = width
g_drawplate_height = height
End Sub
The changes to the Utilities
class add a new constant named PI
that holds the mathematical value of PI and introduce two new functions: Calc2DDistance
and Atn2
. The Calc2DDistance
function returns a double value that is the distance between two 2D points, and the Atn2
function returns an angular value in radians between two points. The following steps have you adding the constant value and two functions to the clsUtilities
class module:
clsUtilities
component.Const PI As Double = 3.14159265358979
' Returns the 2D distance between two points.
' Function expects four double numbers that represent the
' X and Y values of the two points.
Public Function Calc2DDistance(X1, Y1, X2, Y2) As Double
Calc2DDistance = Sqr((X2 - X1) ^ 2 + (Y2 - Y1) ^ 2)
End Function
' Returns the radians angular value between the differences of the
' X and Y delta values.
' Function expects the X and Y delta differences between two points.
Function Atn2(dDeltaX As Double, dDeltaY As Double) As Double
Select Case dDeltaX
Case Is > 0
Atn2 = Atn(dDeltaY / dDeltaX)
Case Is < 0
Atn2 = Atn(dDeltaY / dDeltaX) + PI * Sgn(dDeltaY)
If dDeltaY = 0 Then Atn2 = Atn2 + PI
Case Is = 0
Atn2 = (PI / 2) * Sgn(dDeltaY)
End Select
End Function
The following steps explain how to export the clsUtilities
class module from the drawplate.dvb
file:
clsUtilities
component and choose Export File.MyCustomFiles
folder.clsUtilities.cls
and click Save.
The clsUtilities.cls
file is exported from the DrawPlate
project.
Utilities
class.Now that that the drawplate.dvb
project file has been revised, you can test the changes that have been made. The following steps explain how to use the revised drawplate
function:
vbarun
and press Enter.DrawPlate.dvb!basDrawPlate.CLI_DrawPlate
macro from the list and click Run.Current width: 5.0000 Current height: 2.7500
Specify base point for the plate or [Width/Height]:
prompt, type w
and press Enter.Specify the width of the plate <5.0000>:
prompt, type 3
and press Enter.Specify base point for the plate or [Width/Height]:
prompt, type h
and press Enter.Specify the height of the plate <2.7500>:
prompt, type 4
and press Enter.Specify base point for the plate or [Width/Height]:
prompt, pick a point in the drawing area to draw the plate and holes based on the width and height values specified.'zoom
and press Enter, and then type e
and press Enter.
Figure 5.5 shows a number of different plates that were drawn at various sizes with the CLI_DrawPlate
macro.
CLI_DrawPlate
macro with different input values.18.224.51.145