Chapter 5
Interacting with the User and Controlling the Current View

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.

Interacting with the User

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

Requesting Input at the Command Prompt

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:

  • Integer or double (real) numeric value
  • Distance or angular value
  • String or keyword
  • 2D or 3D point

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.”

Getting Numeric Values

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:

  1. retVal The retVal argument represents the integer or double value returned.
  2. object The object argument represents the AcadUtility object.
  3. 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

Acquiring a Point Value

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.

image

Figure 5.1 Rubber-band line effect used when specifying a point from a base point

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:

  • The GetCorner function requires a base point.
  • The 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.
image

Figure 5.2 The rubber-band effect used when specifying the opposite corner with the GetCorner function

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:

  1. retVal The retVal argument represents the variant value returned by the function. This variant is an array of three doubles representing the point specified.
  2. object The object argument represents the AcadUtility object.
  3. 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.
  4. 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

Getting the Distance Between Points

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:

  1. retVal The retVal argument represents the double that is the result of the function calculating the distance between the two points specified.
  2. object The object argument represents the AcadUtility object.
  3. 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.
  4. 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.

Getting the Angular Difference Between Points

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.

Prompting for String Values

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:

  1. retVal The retVal argument represents the string that is returned by the function.
  2. object The object argument represents the AcadUtility object.
  3. 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.
  4. 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"

Initializing User Input and Keywords

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

Providing Feedback to the User

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:

  1. Starts Consider displaying the default settings or options that your program will be using, similar to the informational text that is displayed before the first prompt when using the fillet or style command.
  2. Executes When processing a large dataset or number of objects, consider displaying a counter that helps the user know that something is still happening.
  3. Causes an Error If something happens internally in your program, you should let users know what went wrong so they can let you (the programmer) know or try to fix the problem themselves.
  4. Completes In most cases, you don't need to display information when a macro is done executing. However, you might want to let the user know if the information from a set of objects was successfully extracted or how many objects were modified.

Displaying Messages at the Command Prompt

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 arrow 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

Displaying Messages in a Message Box

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 arrow 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
image

Figure 5.3 Message displayed with the MsgBox function

Selecting Objects

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.

Selecting an Individual Object

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:

  1. object The object argument represents the AcadUtility object.
  2. 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.
  3. 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.
  4. 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):

  • The object that represents the subentity selected by the user; a value of the Object data type is returned
  • The center point of where the pick box was positioned when the user selected the object; an array of three doubles
  • A transformation matrix for the subentity; a multi-element array of doubles
  • The object IDs of the subentities in the selected object or subentity; an array of long integers that represent the object IDs

For more information on the GetSubEntity method, see the AutoCAD Help system.

Working with Selection Sets

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.

Managing Selection Sets

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

Adding and Removing Objects in a Selection Set

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:

  1. object The object argument represents the AcadSelectionSet object.
  2. filterType The filterType argument is an optional array of integers that represents the DXF code groups that you want to filter objects on.
  3. 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

Accessing Objects in a Selection Set

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

Filtering Objects

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.”

Performing Geometric Calculations

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:

  • A new coordinate value based on a starting point, and at a specific angle and distance
  • The distance value between two points
  • An angular value from the X-axis

Calculating a Coordinate Value

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:

  1. 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.
  2. object The object argument represents the AcadUtility object.
  3. 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.
  4. 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.
  5. 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

Measuring the Distance Between Two Points

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)
image

Figure 5.4 Formula for calculating the distance between two points

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

Calculating an Angle

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:

  1. retVal The retVal argument represents the angular value expressed in radians from the X-axis. The value is returned as a double.
  2. object The object argument represents the AcadUtility object.
  3. fromPoint The fromPoint argument is an array of three doubles that defines the start point of the line.
  4. 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

Changing the Current View

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.

Zooming and Panning the Current View

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

Working with Model Space Viewports

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.

Creating and Managing Named Views

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.

Applying Visual Styles

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.

Exercise: Getting Input from the User to Draw the Plate

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:

  1. Requesting Input Input functions can be used to get values from the user at the Command prompt.
  2. Creating a New Point Value Values from different point lists can be used to create new coordinate values.
  3. Using Conditional Statements Conditional statements are a great way to check the data provided by a user.
  4. Looping Until a Condition Is Met Loops allow you to execute a set of expressions a specific number of times or while a condition remains True. You can use a loop to keep allowing the user to provide input.

Revising the CLI_DrawPlate Function

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:

  1. Load the drawplate.dvb file into the AutoCAD drawing environment and display the VBA Editor.
  2. In the VBA Editor, in the Project Explorer, double-click the basDrawPlate component.
  3. In the code editor window, replace all of the code statements in the code module with the following code statements; the comments are here for your information and don't need to be typed:
    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
  4. Click File arrow Save.

Revising the Utilities Class

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:

  1. In the VBA Editor, in the Project Explorer, double-click the clsUtilities component.
  2. In the code editor window, click to the left of the first comment or code statement and press Enter twice.
  3. Click in the first blank line of the code module and type the following code statement:
    Const PI As Double = 3.14159265358979
  4. Scroll to the bottom of the code editor window and click to the right of the last code statement. Press Enter twice.
  5. Type the following code statements; the comments are here for your information and don't need to be typed:
    ' 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
  6. Click File arrow Save.

The following steps explain how to export the clsUtilities class module from the drawplate.dvb file:

  1. In the VBA Editor, in the Project Explorer, right-click the clsUtilities component and choose Export File.
  2. When the Export File dialog box opens, browse to the MyCustomFiles folder.
  3. Keep the default filename of clsUtilities.cls and click Save.

    The clsUtilities.cls file is exported from the DrawPlate project.

  4. In the Confirm Save As dialog box, click Yes to replace the previously exported version of the Utilities class.

Using the Revised drawplate Function

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:

  1. Switch to AutoCAD by clicking on its icon in the Windows taskbar or click View arrow AutoCAD from the menu bar in the Visual Basic Editor.
  2. In AutoCAD, at the Command prompt, type vbarun and press Enter.
  3. When the Macros dialog box opens, select the DrawPlate.dvb!basDrawPlate.CLI_DrawPlate macro from the list and click Run.
  4. Press F2 to expand the command-line window. The current width and height values for the plate are displayed in the command-line history.
    Current width: 5.0000  Current height: 2.7500
  5. At the Specify base point for the plate or [Width/Height]: prompt, type w and press Enter.
  6. At the Specify the width of the plate <5.0000>: prompt, type 3 and press Enter.
  7. At the Specify base point for the plate or [Width/Height]: prompt, type h and press Enter.
  8. At the Specify the height of the plate <2.7500>: prompt, type 4 and press Enter.
  9. At the 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.
  10. Type '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.

  11. Continue trying the CLI_DrawPlate macro with different input values.
  12. Press Enter to exit the macro when you are done.
image

Figure 5.5 Completed plates

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.51.145