FILEDIA System Variable

Quick one for today – the system variable FILEDIA.

I remember on more than one occasion when learning AutoCAD® tearing my hair out wondering why my SAVE dialog box had vanished, forcing me to input paths to the command line. Very frustrating… so this system variable can be a sanity-saver to know.

The default behaviour is determined by the FILEDIA system variable. Set it to 0 to hide dialog boxes, and 1 to display.

One of my subscribers Chris Thron got in touch with an excellent addition to this post. Although his comment is still below where you’d expect comments to be, I though it would be useful to include it in the main body of this post to make sure it is not missed:

“If you find this happens you need to open a drawing or template to activate the FILEDIA command so you have to input the path name at least once. To get round this on the path prompt enter “~” “enter” (tidle) and it open the dialog box”

Sanity saved.

Will

AutoCAD®, VB and Mathematics

If you want to become an expert AutoCAD® script writer, at some point you’re going to need to know a bit about maths, or at least have the capacity to learn. It doesn’t have to calculus, but stuff like Pythagoras theorem and trigonometry are very much your friend in a geometric environment such as AutoCAD®. Cringing yet? Don’t worry – often it’s not as difficult as it seems.

I’ve been asked how to replicate the measure command along an arc – there is no real simple answer (that I can think of). The way I would do it is through actually calculating the points in 2D space. This may sound tricky, but languages such as VB really are conducive to this kind of work, and you may be surprised how simple this actually is.

So for the purposes of this post I will be showing you how to calculate and draw a circle of points using VBA. Obviously an arc is merely just part of a circle, so isn’t really any different. Although we’re using VBA for convenience, the rationale behind the exercise will work in any programming language.

Step One – Get it clear in our minds

Logically, to define a circle in 2D space, you need to know the centre for the circle, and the radius. It’s no coincidence then that this is exactly what is required by the CIRCLE command in AutoCAD.

To define a point on the circumference of that circle then – if you have defined your circle, all you need is an angle. From that angle, we can logically derive the point on the circle at that angle. So in our minds at least, we know how to define a point on the circumference of a circle using a centre for the circle, a radius, and an angle.

Now we have to convert that logic into code.

Step Two – Understand Sine and Cosine

One of the key things that will be at work here will be the use of the trigonometric functions sine and cosine. I think it is worth delving into what these actually mean, as understanding this can be very helpful for this kind of work. In fact, when I was at school I was taught parrot-fashion how to use SOH-CAH-TOA to work out which trig function to use for which situation. I’ve never been a fan of that kind of “learning”. I like to understand the underlying principles so that I can apply them to any situation, but sadly I was never taught in that way. My own curiosity led me to figuring out the diagram below for myself, and it really enhanced my ability to understand trigonometry, and what sine and cosine actually are.

Consider the image below:


Assuming a hypotenuse (the angled lines coming from the centre) length of 1, sine is the length of the deflection in the Y axis for a given angle. So in the example above, a line drawn at 30°  a length of 1, will produce a deflection in the Y axis of 0.5. Sine 30 = 0.5. It’s as simple as that.

Cosine is equally as simple, but rather than the deflection in the Y axis, it will return the deflection in the X axis. So, Cosine 30 = 0.866.

This is how we are able to determine the length of sides in a triangle from angles through trigonometry. Lets assume the hypotenuse is actually 4. The ratio between the sides is still the same, so the calculation to work out the vertical edge of the triangle (the deflection in the Y axis) is as simple as 4 * Sin 30. We multiply by the length of the hypotenuse to scale the side length to the correct size. Simples.

Step Three – Write the code

I think we’re ready for some code. Below is a function that accepts the various inputs we have identified and will draw a point in modelspace.

Sub drawPointOnCirc(xPos As Double, yPos As Double, radius As Double, angle As Double)
Dim insertPoint(2) As Double
Dim xOffset As Double
Dim yOffset As Double
Dim angleRadians As Double
Const PI As Double = 3.14159265358979

'Convert degrees to radians, as required by VBA trig functions
angleRadians = 2 * PI * angle / 360

'Calculate the X and Y offset from the centre of the circle
xOffset = Cos(angleRadians) * radius
yOffset = Sin(angleRadians) * radius

'Add the circle centre to the offset values, to get the absolute
'position of the point on the circumference of the circle.
insertPoint(0) = xPos + xOffset
insertPoint(1) = yPos + yOffset

ThisDrawing.ModelSpace.AddPoint insertPoint

End Sub

This function is actually really useful to us now. We are able to draw a point in modelspace that represents a location on the circumference of a circle. Now, if we were to call the function in the manner below:

Sub main()
Dim n As Double
For n = 1 To 120
drawPointOnCirc 10, 10, 3, n
Next
End Sub

this would draw 120 points at 1 degree intervals along an arc. The circle centre is defined at 10,10 with a radius of 3, which is what the arc should show.

And that’s it!

Hopefully this post has shown you how a little bit of maths can be helpful – the production and reuse of functions like this is really helpful to building up more complex applications… have fun, and as always, feel free to get in touch if you have any problems.

And please subscribe below if you want more tips like this!

Will

How to Control AutoCAD® From a Standalone Executable

I’ve had a few requests recently to do a post on creating executables that control AutoCAD®. Though generally it is better to have tools well integrated into AutoCAD® via the use of a NETLOADed dll for example, sometimes an exe can be an elegant solution.

The general concepts are fairly straight forward.

  1. Check for a running instance of AutoCAD®, and create a reference to it. If it is not running, launch AutoCAD®, and create a reference to it.
  2. Use COM to control AutoCAD

When I started that list, I expected it to be longer – but essentially that’s it. If you’re more of a VBA user, you’ll be very pleased to hear that as we’re using COM, you can pretty much re-use all the VBA code you ever learned.

So, lets draw a basic shape. Something like below:

random shape

Ok – this can easily be handled by a polyline, so this is what our exe will do.

First things first though. Create a new standalone exe project in VB. You can use VB.NET, or VB6 for this. You’ll not need to worry about targeting any specific .NET frameworks or anything like that. As we are using COM we are completely sidestepping those issues.

So I’m going to go ahead with VB6; a bit old-school, but it illustrates the point well. New Project > Standard EXE.

Firstly, we need to create a reference to AutoCAD® in our code. To do this, we need to load the relevant AutoCAD® types and libraries into our exe project. So, go to Project > References. From here you’ll want to select the AutoCAD® type libraries you want to use, depending on which version of AutoCAD® you’re using.

Once loaded, we can create variables that are typed for AutoCAD®, and we are now able to write our code. For the purposes of this example we’re not really interested in using the Form properly, we’re only really using it as a container for our code in the Load event:

Private Sub Form_Load()
Dim ACAD As AcadApplication 'Create ACAD variable of type AcadApplication
'On Error Resume Next 'This tells VBA to ignore errors
Set ACAD = GetObject(, "AutoCAD.Application") 'Get a running instance of the class AutoCAD.Application
'On Error GoTo 0 'This tells VBA to go back to NOT ignoring errors
If ACAD Is Nothing Then 'Check to see if the above worked
Set ACAD = New AcadApplication 'Set the ACAD variable to equal a new instance of AutoCAD
ACAD.Visible = True 'Once loaded, set AutoCAD® to be visible
End If

Dim llCorner As Variant
llCorner = ACAD.ActiveDocument.Utility.GetPoint(, "Pick the lower left corner for the shape")

'Draw shape in terms of the lower left corner
Dim coords(11) As Double
'lower left corner of shape
coords(0) = llCorner(0)
coords(1) = llCorner(1)
'lower right corner of shape
coords(2) = llCorner(0) + 100
coords(3) = llCorner(1)
'upper right corner of shape
coords(4) = llCorner(0) + 100
coords(5) = llCorner(1) + 30
'right hand corner of semicircle
coords(6) = llCorner(0) + 70
coords(7) = llCorner(1) + 30
'Draw the semicircle as a straight line for now. We will set the bulge on this segment later.
'left hand corner of semicircle
coords(8) = llCorner(0) + 30
coords(9) = llCorner(1) + 30
'upper left corner of shape
coords(10) = llCorner(0)
coords(11) = llCorner(1) + 30

'With the coordinates defined, use these to create a new polyline
Dim poly As AcadLWPolyline
Set poly = ACAD.ActiveDocument.ModelSpace.AddLightWeightPolyline(coords)
'Set the bulge of segment 4 of the polyline (ie, index 3) to a value of -1
poly.SetBulge 3, -1
'Close the polyline
poly.Closed = True

'End application
Unload Me

End Sub

So that’s how to draw this shape using a VB6 standalone. The method would be very similar for VB.NET, but you’ll need to take a slightly different approach when accessing the ThisDrawing object. This is discussed in my Introduction to VB.NET in AutoCAD.

Hope this helps someone, and I encourage you to join the hordes of people that have subscribed by filling out an email address below!

Will

AutoCAD® Copy Paste Between Drawings Scale

The other day, I came across a very bizarre problem. All I was doing was copying and pasting between drawings, but the entities were being pasted into the other drawing a different scale!

Having not encountered this before, I assumed it was something to do with units, so I typed the UNITS command. But to my surprise, all was as it should be, which meant something else was causing the problem.

It turns out the fix was in a discrepency between the values accessibly by -DWGUNITS. So if you ever have this problem, that’s the fix.

Hope this helps,

Will

Export Points from AutoCAD® to CSV file using VBA

Today I’m going to show you how to use a bit of simple VBA to export data to a CSV file. It’s really simple, and although there are other ways of achieving the same thing, this way allows great flexibility, and is very versatile.

Firstly, I’ll set up a drawing with a few points in it. These points will be what we will export:

Screenshot Of Points

The next step is to open the VBA editing window using the VBAIDE command. Of course, if you’re using AutoCAD® 2010+ you’ll need to download the VBA add-on. Once open, right click in the project explorer window and create a new module.

Now for the code. I was going to explain the code, but as I’ve commented it pretty well, I don’t really think I need to. Take note of the part about the FileSystemObject, as you’ll need to follow the instructions before the code will work. Do ask if you have any other questions.

Option Explicit

Sub ExportPoints()
    'Declare variables
    Dim currentSelectionSet As AcadSelectionSet
    Dim ent As AcadEntity
    Dim pnt As AcadPoint
    Dim csvFile As String
    Dim FSO As FileSystemObject
    Dim textFile As TextStream
    
    'Create a reference to the selection set of the currently selected objects
    Set currentSelectionSet = ThisDrawing.ActiveSelectionSet
    
    'Check if anything is selected, and give exit with a warning if not
    If currentSelectionSet.Count = 0 Then
        ThisDrawing.Utility.Prompt "There are no currently selected objects. Please select some points to export, and run this command again." & vbNewLine
    End If
    
    'Use a For Each statement to look through every item in CurrentSelectionSet
    For Each ent In currentSelectionSet
        'In here, ent will be one of the selected entities.
        
        'If ent is not a point object, we should ignore it
        If TypeOf ent Is AcadPoint Then
            'Only points will make it this far
            
            'Now that we know we are dealing with a point,
            'we can use the specific AcadPoint type of variable.
            Set pnt = ent
            'You'll notice that after doing this, you have more
            'intellisense methods when you type "pnt."
            
            'Add a line to the string variable csvFile.
            'We are concatenating two numbers together with a comma in between,
            'and adding a new line character at the end to complete the row.
            csvFile = csvFile & pnt.Coordinates(0) & "," & pnt.Coordinates(1) & vbNewLine
            
            'Saying that csvFile = csvFile & whatever is a useful
            'way to repeatedly add to the end of a string variable.
            
        End If
        
    Next
    
    'Write the contents of the csvFile variable to a file on the C:\ with the same name
    
    'FileSystemObjects are really useful for manipulating files
    'But, you'll need a reference to the Microsoft Scripting Runtime in your VBA project.
    'Go Tools>References, and select the Microsoft Scripting Runtime.
    
    'Create a new File System Object
    Set FSO = New FileSystemObject
    
    'Using FSO.CreateTextFile, create the text file csvFile.csv,
    'and store a reference to it in the variable textFile
    Set textFile = FSO.CreateTextFile("C:\csvFile.csv")
    
    'Write the string variable csvFile to textFile
    textFile.Write csvFile
    
    'Close textFile, as we are finished with it.
    textFile.Close
    
    'Alert the user that the file has been created
    ThisDrawing.Utility.Prompt "Points have been exported to C:\csvFile.csv" & vbNewLine
    
End Sub

And there we have it. You could of course add more conditions in there – say, nest another IF statement in the middle that filters out say only red points. It doesn’t have to be points either – this process will work with any properties of any AutoCAD® entity.

Have fun, and if you haven’t already, please do subscribe below!

Will

AutoCAD® Fractal – A bit of fun…

Ok, I’ve got a few tips and tricks on here, and I thought I’d post something totally random, but actually quite interesting – interesting at least to me anyway! Take a look at the video below, which shows you an easy way to produce the paper folding fractal in AutoCAD:

I hope you enjoyed that – just don’t crash AutoCAD® by repeating the process too many times!

Will

Excel and AutoCAD® – A match made in heaven – Part 3

One of my readers has requested some help regarding the drawing of windows. I’m not 100% sure of his exact requirements, but it’s a good opportunity for me to build on what I’ve already shown you. This will be a brief post – the main content of which is some annotated VB code (below). This simply takes the previous Excel and AutoCAD® post a little further by creating a practical implementation.

What this does is allows the user to enter an X,Y,Width and Height coordinate in Excel, in columns A,B,C and D respectively. Running the code draws them as rectangles in modelspace.

I’ve decided to compile this as an Excel file, which is downloadable below. It is worth mentioning that I have referenced a specific version of AutoCAD® in this file (Under Tools>References from the VBA editor accessible from Excel using Alt+F11). The code should work if you reference your own version of AutoCAD.

WindowMaker

The source code is here also for you to look at, or paste into your own project. Again, you’ll need to create a reference to AutoCAD® as explained in the previous article.

Sub Main()
Dim ACAD As AcadApplication 'Create ACAD variable of type AcadApplication
On Error Resume Next 'This tells VBA to ignore errors
Set ACAD = GetObject(, "AutoCAD.Application") 'Get a running instance of the class AutoCAD.Application
On Error GoTo 0 'This tells VBA to go back to NOT ignoring errors
If ACAD Is Nothing Then 'Check to see if the above worked
Set ACAD = New AcadApplication 'Set the ACAD variable to equal a new instance of AutoCAD
ACAD.Visible = True 'Once loaded, set AutoCAD® to be visible
End If
ACAD.ActiveDocument.Utility.Prompt "Hello from Excel!" 'Print a message to the AutoCAD® command line
Dim Coords(7) As Double 'This is an array of double precision floating point numbers

Dim n As Integer 'Create the variable n as the type Integer
For n = 1 To 10 'Loop this code, incrementing the value of n from 1 to 10

'Variables for X,Y,Width and Height
Dim X As Double
Dim Y As Double
Dim Width As Double
Dim Height As Double

'Store the values from Excel in memory - We could just use Sheet1.Cells(), but
'this makes it much more readable for us as programmers, and it is faster to retrieve
'data from variables than from the worksheet.
X = Sheet1.Cells(n, 1)
Y = Sheet1.Cells(n, 2)
Width = Sheet1.Cells(n, 3)
Height = Sheet1.Cells(n, 4)

'Lightweight polylines are defined by a series of 2D coords in an array

'Bottom Left Corner
Coords(0) = X
Coords(1) = Y

'Bottom right Corner
Coords(2) = X + Width
Coords(3) = Y

'Top Right Corner
Coords(4) = X + Width
Coords(5) = Y + Height

'Top Left Corner
Coords(6) = X
Coords(7) = Y + Height

'Create a polyline-type variable - its initial value will be empty (non-existent)
Dim PL As AcadLWPolyline

'Create a polyline based on these coordinates
'The Set statement is used when creating a reference to objects (complex data types)
'The value of PL will be a reference to our new polyline
Set PL = ACAD.ActiveDocument.ModelSpace.AddLightWeightPolyline(Coords)   'Add a point in AutoCAD® at this location

'Make PL a closed polyline
PL.Closed = True

Next
End Sub

Hope this helps! And if you want to reap the benefit of spectacular hints and tips like this regularly, subscribe below! Not to mention my outstandingly witty writing style…errmm…so yes please do subscribe!
Will