# Lisp Parabola

This is pretty simple. Its a start. Func1 defines the equation ax^2 + bx + c with the specific values of a b and c and returns the value when passed the current value of X.  C:para calls the parabola function and sets the x minimum, maximum and x increment.

screenshot from the visual lisp editor.

if instead of unconnected lines, we want to graph with a 2D Polyline, the command is PLine, it takes the same point list. We start the Pline command with the first point, then enter the loop and calculate the next point each time through the loop, leaving the command processor running and just feeding it one point each time.

For graphing polar equations – Polar Coordinates – P(R,Ɵ) – A point is defined by how far it is from the origin (R – Radius) and what angle (Ɵ – Theta) a line from the origin to the point makes with the horizontal axis. (I am using A for angle instead of Ɵ in the code)

To change the command from separate lines to connected polyline, we start the pline command outside the loop and only calculate one point in the loop, just as for the rectangular cartesian program.

# AutoLisp 2.5

about 1986 R.C. Bradlee published a Xeroxed page book “Programming Autocad” which featured the Autolisp command set as of autocad version 2.5. Selection Sets had just been added. Entity names could be retrieved and properties modified but new entitities had to be added with the Command function (command “Line” pnt1 …). This would be a good starter section for learning the language, not overwhelming but not trivial. Some or most of the links seem to paste in from the Autodesk 2017 help reference. I rearranged and edited the entries into my own idea of fuzzy categories. A disclaimer – this is not an official list of Lisp 2.5 but just my reconstruction. Some functions i left out either inadvertently, or i assume they are obsolete, or simply i dont see a need for them.

Descriptions below all belong to Autodesk. Here is there notice cut / pasted from their help page.

Math and booleans are first and easiest to master.

 + (add) (+ [number number …]) Returns the sum of all numbers – (subtract) (- [number number …]) Subtracts the second and following numbers from the first and returns the difference * (multiply) (* [number number …]) Returns the product of all numbers / (divide) (/ [number number …]) Divides the first number by the product of the remaining numbers and returns the quotient 1+ (increment) (1+ number) Returns the argument increased by 1 (incremented) 1- (decrement) (1- number) Returns the argument reduced by 1 (decremented) abs (abs number) Returns the absolute value of the argument atan (atan num1 [num2]) Returns the arctangent of a number in radians cos (cos ang) Returns the cosine of an angle expressed in radians exp (exp number) Returns the constant e (a real) raised to a specified power (the natural antilog) expt (expt base power) Returns a number raised to a specified power fix (fix number) Returns the conversion of a real into the nearest smaller integer float (float number) Returns the conversion of a number into a real gcd (gcd int1 int2) Returns the greatest common denominator of two integers log (log number) Returns the natural log of a number as a real max (max [number number …]) Returns the largest of the numbers given min (min [number number …]) Returns the smallest of the numbers given rem (rem [num1 num2 …]) Divides the first number by the second, and returns the remainder sin (sin ang) Returns the sine of an angle as a real expressed in radians sqrt (sqrt number) Returns the square root of a number as a real ~ (bitwise NOT) (~ int) Returns the bitwise NOT (1’s complement) of the argument logand (logand [int int …]) Returns the result of the logical bitwise AND of a list of integers logior (logior [int int …]) Returns the result of the logical bitwise inclusive OR of a list of integers lsh (lsh [int numbits]) Returns the logical bitwise shift of an integer by a specified number of bits atom (atom item) Verifies that an item is an atom boundp (boundp sym) Verifies whether a value is bound to a symbol listp (listp item) Verifies that an item is a list not (not item) Verifies that an item evaluates to nil null (null item) Verifies that an item is bound to nil numberp (numberp item) Verifies that an item is a real or an integer minusp (minusp number) Verifies that a number is negative zerop (zerop number) Verifies that a number evaluates to zero = (equal to) (= numstr [numstr …]) Returns T if all arguments are numerically equal, and returns nil otherwise /= (not Equal to) (/= numstr [numstr …]) Returns T if the arguments are not numerically equal, and nil if the arguments are numerically equal > (greater than) (< numstr [numstr …]) Returns T if each argument is numerically less than the argument to its right, and returns nil otherwise >= (greater than or equal to) (<= numstr [numstr …]) Returns T if each argument is numerically less than or equal to the argument to its right, and returns nil otherwise < (less than) (> numstr [numstr …]) Returns T if each argument is numerically greater than the argument to its right, and returns nil otherwise <= (less than or equal to) (>= numstr [numstr …]) Returns T if each argument is numerically greater than or equal to the argument to its right, and returns nil otherwise and (and [expr …]) Returns the logical AND of a list of expressions boole (boole func int1 [int2 …]) Serves as a general bitwise Boolean function eq (eq expr1 expr2) Determines whether two expressions are identical equal (equal expr1 expr2 [fuzz]) Determines whether two expressions are equal or (or [expr …]) Returns the logical OR of a list of expressions angtos (angtos angle [mode [precision]]) Converts an angular value in radians into a string ascii (ascii string) Returns the conversion of the first character of a string into its ASCII character code (an integer) atof (atof string) Returns the conversion of a string into a real atoi (atoi string) Returns the conversion of a string into an integer chr (chr integer) Returns the conversion of an integer representing an ASCII character code into a single-character string itoa (itoa int) Returns the conversion of an integer into a string rtos (rtos number [mode [precision]]) Converts a number into a string

Lists and Loops contain the core LIST Processing commands

 type (type item) Returns the type of a specified item eval (eval expr) Returns the result of evaluating an AutoLISP expression quote (quote expr) Returns an expression without evaluating it repeat (repeat int [expr …]) Evaluates each expression a specified number of times, and returns the value of the last expression while (while testexpr [expr …]) Evaluates a test expression, and if it is not nil, evaluates other expressions; repeats this process until the test expression evaluates to nil if (if testexpr thenexpr [elseexpr]) Conditionally evaluates expressions cond (cond [(test result …) …]) Serves as the primary conditional function for AutoLISP foreach (foreach name lst [expr …]) Evaluates expressions for all members of a list progn (progn [expr …]) Evaluates each expression sequentially, and returns the value of the last expression command (command [arguments] …) Executes an AutoCAD command defun (defun sym ([arguments] [/variables …]) expr … ) Defines a function setq (setq sym1 expr1 [sym2 expr2 …]) Sets the value of a symbol or symbols to associated expressions getvar (getvar “varname”) Retrieves the value of an AutoCAD system variable setvar (setvar “varname” value) Sets an AutoCAD system variable to a specified value load (load filename [onfailure]) Evaluates the AutoLISP expressions in a file *error* (*error* string) A user-definable error-handling function list (list [expr …]) Takes any number of expressions and combines them into one list length (length lst) Returns an integer indicating the number of elements in a list last (last lst) Returns the last element in a list nth (nth n lst) Returns the nth element of a list reverse (reverse lst) Returns a list with its elements reversed car (car lst) Returns the first element of a list cdr (cdr lst) Returns the specified list, except for the first element of the list caddr cadr cons (cons new-first-element lst) The basic list constructor append (append lst …) Takes any number of lists and runs them together as one list member (member expr lst) Searches a list for an occurrence of an expression and returns the remainder of the list, starting with the first occurrence of the expression assoc (assoc item alist) Searches an association list for an element and returns that association list entry apply (apply function lst) Passes a list of arguments to a specified function mapcar (mapcar function list1 … listn) Returns a list of the result of executing a function with the individual elements of a list or lists supplied as arguments to the function lambda (lambda arguments expr …) Defines an anonymous function

Strings and File I/O are pretty straighforward

 read (read [string]) Returns the first list or atom obtained from a string strcat (strcat [string1 [string2 …]) Returns a string that is the concatenation of multiple strings strlen (strlen [string …]) Returns an integer that is the number of characters in a string substr (substr string start [length]) Returns a substring of a string vl-string-subst (vl-string-subst new-str pattern string [start-pos]) Substitutes one string for another, within a string open (open filename mode) Opens a file for access by the AutoLISP I/O functions read-char (read-char [file-desc]) Returns the decimal ASCII code representing the character read from the keyboard input buffer or from an open file read-line (read-line [file-desc]) Reads a string from the keyboard or from an open file write-char (write-char num [file-desc]) Writes one character to the screen or to an open file write-line (write-line string [file-desc]) Writes a string to the screen or to an open file close (close file-desc) Closes an open file

The last category is Autocad graphic interfacing commands. ( I am leaving out a few things I think may be less useful or obsolete or inadvertently)

# Autocad Help System for Lisp and VBA (ActiveX)

I have found the front end pages for Autocad programming languages VBA (ActiveX) and Lisp (Visual Lisp). Here is my big suggestion. You can copy and paste an entire page of links into Excel and the links transfer. Use Excel to collate and organize Autodesk help bookmarks.

Autodesk splits both subjects into two groups – what they call a Guide which would be teaching text and a Reference which is a page by page Index. Visual Lisp is traditional Autocad Lisp plus ActiveX. So if you are looking for Visual Lisp help, you need to include the ActiveX references in your reading list.

As of 2017, Autodesk has returned “Developer Documentation” to its front end for Autocad 2017 help,
http://help.autodesk.com/view/ACD/2017/ENU/

http://help.autodesk.com/view/ACD/2017/ENU/?home=homepage_dev

If you copy and paste that page into excel, the links all transfer without any additional work. Here i have marked with asterisk the 5 critical pages.

you can then make tabs for guide and reference for both lisp and activeX. In a few minutes you have an upper level table of contents in a single file. as you explore the pages using the live links you can make notes or mark as read. you can make a reference to the entire page at the top of your excel sheet. Pages come in formatted with good links, you might have to reset column width and row height for entire sheet.

If you are looking for Visual Lisp code, it is in the ActiveX reference. Both groups ActiveX and Lisp have an Object Model page, but the Lisp page is not live, just a picture. The Object Model page for ActiveX has live links. You do not need to paste that page into Excel, but it also pastes with live links, and you never have to go looking for it. You can have the Object Model with links in your spread sheet. Regardless how you access it, it is a very valuable tool.

As an example of its usefulness, say you want to know how to draw a circle with Visual Lisp.

Click on the Circle object. It takes you to Circle Object ActiveX help page. Which has the properties and methods of the object that is a circle, but it does not have the tool to draw a circle. The Addcircle is a method of ModelSpace, PaperSpace and Block. Click on ModelSpace, scroll down to the methods, and click on AddCircle. there you find the code to draw a circle in both VBA and Lisp. Code that you can paste into your VBA module or Lisp editor.

http://help.autodesk.com/view/ACD/2017/ENU/?guid=GUID-837C702F-91A7-445B-8713-3099B94664BE

the object model –

http://help.autodesk.com/view/ACD/2017/ENU/?guid=GUID-A809CD71-4655-44E2-B674-1FE200B9FE30

* EDIT – unfortunately the ActiveX Reference page links did NOT copy from www into Excel. *
The other pages, lisp guide and reference, activex guide, and activex model links do work in excel.

and finally, autocad 2017 still installs two activex chm files on your hard drive with installation, the Guide and the Reference. You can also link to those.

The Ellipse

Autocad has an ellipse object. The AddEllipse method takes a center point, a second point which is the end of the major axis, and a factor autodesk calls RadiusRatio, which is just b / a. This is not the same thing as Eccentricity which is c / a, though similar but inverse and they both must be less than 1. I have not seen RadiusRatio in a math book. RadiusRatio gives a circle if it is equal to 1. If it is greater than 1 it throws an error. Eccentricity is a math term and gives a circle when it is zero. If it were 1 i believe the ellipse would collapse to a straight line.

To create an autocad vba ellipse with vertical axis, make the second point, MajorAxis, vertical above the center point. Autocad gives no indication where the Focus is. It has to be calculated from the values of A and B.

```Sub init_frm_ellipse()
a = frm_Ellipse.txt_a1
b = frm_Ellipse.txt_b1
End Sub

Sub horz_new_ellipse()
'RadiusRatio must be less than or equal to 1
'MajorAxis is a relative point off the center, not an absolute point
Call init_frm_ellipse

Dim ptctr(0 To 2) As Double
Dim pta(0 To 2) As Double
Call initpt(ptctr, 0, 0, 0)
Call initpt(pta, a, 0, 0)

obj_ellipse.Update
End Sub

Sub vert_new_ellipse()
Call init_frm_ellipse

Dim ptctr(0 To 2) As Double
Dim pta(0 To 2) As Double
Call initpt(ptctr, 0, 0, 0)
Call initpt(pta, 0, a, 0)

obj_ellipse.Update
End Sub
```

The autodesk method advantage is that by specifying a center, then a relative point from the center for the end of the major axis, the ellipse can be turned to any angle. With some simple trig we can accept input in degrees and calculate the major axis vertex.

``` Function deg2rad(deg As Double) As Double
deg2rad = deg * Pi / 180
End Function

Sub init_frm_ellipse()
a = frm_Ellipse.txt_a1
b = frm_Ellipse.txt_b1
c = frm_Ellipse.txt_c1
End Sub

Sub new_ellipse()
'RadiusRatio must be less than or equal to 1
'MajorAxis is a point, not a length
Call init_frm_ellipse

Dim ptctr(0 To 2) As Double
Dim pta(0 To 2) As Double
Dim x1 As Double, y1 As Double

Call initpt(ptctr, 0, 0, 0)
Call initpt(pta, x1, y1, 0)

obj_ellipse.Update
End Sub
```

we can move the ellipse off the center. The input for AddEllipse does not require an absolute point for MajorAxis. It takes a point relative to the center.

Drawing the ellipse is straightforward. calculating the focus and end points to mark them requires some trig to accomodate the angled axes.

```
Sub new_ellipse()
'takes input from the form
'a major axis
'b minor axis
'd degree of major axis
'h and k, xy values for center of ellipse
'converts input to
'RadiusRatio must be less than or equal to 1
'MajorAxis is a point relative from the center, not an absolute point
Call init_frm_ellipse ' gets the values from the form

Dim ctr(0 To 2) As Double
Dim pt_a(0 To 2) As Double
Dim x1 As Double, y1 As Double

Call initpt(ctr, h, k, 0)
Call initpt(pt_a, x1, y1, 0)

obj_ellipse.Update

'to plot points
Dim pt_a1(0 To 2) As Double
Dim pt_a2(0 To 2) As Double
Dim pt_b1(0 To 2) As Double
Dim pt_b2(0 To 2) As Double
Dim pt_f1(0 To 2) As Double
Dim pt_f2(0 To 2) As Double

Dim fx1 As Double, fy1 As Double, fx2 As Double, fy2 As Double
Dim ax1 As Double, ay1 As Double, ax2 As Double, ay2 As Double
Dim bx1 As Double, by1 As Double, bx2 As Double, by2 As Double

'c is the focal distance from ctr
c = (a ^ 2 - b ^ 2) ^ 0.5
fx1 = h + c * Cos(deg2rad(d))
fy1 = k + c * Sin(deg2rad(d))
fx2 = h - c * Cos(deg2rad(d))
fy2 = k - c * Sin(deg2rad(d))

bx1 = h + b * Cos(deg2rad(d + 90))
by1 = k + b * Sin(deg2rad(d + 90))

bx2 = h - b * Cos(deg2rad(d + 90))
by2 = k - b * Sin(deg2rad(d + 90))

ax1 = h + a * Cos(deg2rad(d))
ay1 = k + a * Sin(deg2rad(d))

ax2 = h - a * Cos(deg2rad(d))
ay2 = k - a * Sin(deg2rad(d))

Call initpt(pt_a1, ax1, ay1, 0)
Call initpt(pt_a2, ax2, ay2, 0)
Call initpt(pt_b1, bx1, by1, 0)
Call initpt(pt_b2, bx2, by2, 0)
Call initpt(pt_f1, fx1, fy1, 0)
Call initpt(pt_f2, fx2, fy2, 0)

Update

End Sub
```

In astronomy, planets orbit around the sun in ellipses with the sun at one focus. To draw these orbits we need to input the different numbers but always draw one focus, the sun, at the origin.

orbits of the nine planets (simplified with major axes aligned, no inclination). The sun and all planets are drawn full size, but the distances of the orbits are so vast they are not seen. this is much more fun to do yourself to zoom around and get a feel for the distance than to look at a screenshot.

the astronomy book gives the half major axis in (x 10^6 km), Orbital Eccentricity, and planet radius in km. those are the inputs. The value for Uranus caused Long and Double variable types to overflow but i had no issues using Currency data type. don’t base your senior thesis on this, i dont have supervision. it gives a visually correct orbit for pluto that it actually crosses inside neptune’s orbit because of pluto’s higher eccentricity. there are other 3D factors i do not take into consideration, inclination – ellipse tilt – and two other twists in 3D space. so neptune and pluto can never collide.

```Public Const xkm As Currency = 1000000

Sub solar_system()
'testCall planetary_ellipse(6, 0.5, 1)

Dim pt0(0 To 2) As Double
Call initpt(pt0, 0, 0, 0)

'this is the sun

'mercury
Call planetary_ellipse(57.9 * xkm, 0.206, 2440)

'venus
Call planetary_ellipse(108.2 * xkm, 0.007, 6052)

'earth
Call planetary_ellipse(149.6 * xkm, 0.017, 6378)

'mars
Call planetary_ellipse(227.9 * xkm, 0.093, 3397)

'jupiter
Call planetary_ellipse(778.4 * xkm, 0.048, 71492)

'saturn
Call planetary_ellipse(1427 * xkm, 0.054, 60268)

'too large
'uranus
Call planetary_ellipse(2871 * xkm, 0.047, 25559)

'neptune
Call planetary_ellipse(4498 * xkm, 0.009, 24764)

'pluto
Call planetary_ellipse(5906 * xkm, 0.249, 1195)

End Sub

Sub planetary_ellipse(a As Currency, e As Double, r As Long)
'a is major axis km
'e is eccentricity
'r is planetary equatorial radius in km

'RadiusRatio must be less than or equal to 1
'MajorAxis is a point, not a length

Dim b As Double
Dim c As Double

Dim ctr(0 To 2) As Double
Dim f1(0 To 2) As Double
Dim f2(0 To 2) As Double
Dim pt_a(0 To 2) As Double
Dim pt_p(0 To 2) As Double
Dim a_vector(0 To 2) As Double

c = a * e
b = a * (1 - e ^ 2) ^ 0.5

Call initpt(ctr, c, 0, 0)
Call initpt(f1, 0, 0, 0)
Call initpt(f2, 2 * c, 0, 0)
Call initpt(pt_a, a + c, 0, 0)
Call initpt(pt_p, c - a, 0, 0)

Call initpt(a_vector, 1 * a, 0, 0)

obj_ellipse.Update

End Sub

```

# Autocad VBA Logo Turtle Graphics

Logo was a lisp like educational language designed to introduce children to coding. I believe there may be no serious impediments to implementing an experimental version in Autocad VBA. This is a work in process, first post is proof of concept. The full implementation is yet to be planned. I wont worry too much about deviating from standard logo methods or syntax. If i hit a problem that cannot be coded around, that will be information gained. I believe the concepts may turn out to be useful for more general VBA parametric autocad code.

For all of my projects, I code in an Excel XLSM file. I have a standard ACAD_CONNECT sub i use, and reference the Autocad Type Library in the Excel VBAProject. i have never downloaded the Autocad VBA implementation. It is not necessary to code Autocad VBA. I use the VBA editor provided routinely in Excel.

The fundamental element of turtle geometry is the current position of the pen, and the heading or direction it is pointing. This prototype will be 2D, so we need a global variable for the X and Y position, and a variable for the heading. We will keep heading in degrees and convert it in the low level subs to radians.

The first thing we will need is a line subroutine that takes logo style input – current point, distance, and heading – to draw the line and change the pen position to the end of the line. The user wont call this sub directly but will use std routines like Forward, PenUP, Right, Left, etc.

```Option Explicit
Public px As Double 'position x
Public py As Double 'position y
Public hxy As Double 'heading degree

Sub line_hd(x1 As Double, y1 As Double, dist As Double, heading As Double)

Dim pt1(0 To 2) As Double
Dim pt2(0 To 2) As Double

pt1(0) = x1: pt1(1) = y1: pt1(2) = 0

'px and py are global position

pt2(0) = px: pt2(1) = py: pt2(2) = 0

Update
End Sub
```

standard logo subroutines FORWARD, RIGHT, LEFT and BACK to get started are pretty simple at this point. i dont have a PENUP, PENDOWN yet that will modify these.

```Sub forward(dist As Double)
Call line_hd(px, py, dist, hxy)
End Sub

Sub right(deg As Double)
hxy = hxy - deg
End Sub

Sub left(deg As Double)
hxy = hxy + deg
End Sub

Sub back(dist As Double)
End Sub
```

a sample user prototype sub and init sub helper.

``` Sub init_turtle()
px = 0
py = 0
hxy = 0
End Sub

Sub to_honeycomb()
init_turtle
Dim i As Integer, j As Integer

For j = 1 To 3
For i = 1 To 6
forward 6
left 60
Next i

left 120
Next j

End Sub
```

``` Sub to_star()
init_turtle
Dim i As Integer

For i = 1 To 5
forward 6
right 144
Next i

End Sub
```

the circle routine according to python turtle graphics just takes a radius. from the position and heading of the turtle, it makes a 360 arc back to the starting point. if the radius is positive, it turns counterclockwise, if negative then opposite. the task then is to run a normal perpendicular off the heading vector the same distance as the radius to find the center.

this is a little messy, i dont think it will stay this way.

first a demo calling program, then the circle primitive code.

```Sub test_circle()
init_turtle

For i = 1 To 21
forward 6
right 15 + i
forward 6
curcle 3
forward 3
curcle -3
forward 6
curcle -3
forward 3
curcle 3
Next i

End Sub

End Sub

Sub circle_turtle(x1 As Double, y1 As Double, radius As Double, hxy As Double)
' circle wrapper
Dim Cx As Double, Cy As Double
Dim pt2(0 To 2) As Double

Else
End If

'px and py are global position
'we are calculating circle center but not changing position
pt2(0) = Cx: pt2(1) = Cy: pt2(2) = 0

Update
End Sub

```

more to come

# Polyline SetBulge Arc factor

The Autocad VBA object AcadLWPolyline is made in straight line segments with AddLightWeightPolyline method using an array of coordinates. The LWPolyline object returned has a SetBulge method to change a straight line segment to an arc. Setbulge takes two parameters, the lower numbered index of the vertex that begins the segment, and a Bulge value. the Bulge value is explained thusly –

“The bulge is the tangent of 1/4 of the included angle for the arc between the selected vertex and the next vertex in the polyline’s vertex list. A negative bulge value indicates that the arc goes clockwise from the selected vertex to the next vertex. A bulge of 0 indicates a straight segment, and a bulge of 1 is a semicircle.”

The arc no matter what curvature it takes is always a part of a circle. Two lines drawn from the center to the vertexes define the included angle. This center moves along a line as the bulge factor changes. As the center gets closer to the arc, the angle gets larger. If the center moves far away the included angle gets small, the tangent of that angle is small, the arc is nearly a straight line, and the Bulge factor is small.

The gist of the code. Vertexes start numbering with zero.

plineObj.SetBulge 3, -0.5

what does an even number 0.5 Bulge factor give?

what Bulge factor would give an included angle of 90 deg?

since B = TAN(PI/8) this can be entered directly in code

```Sub B2_test()
Dim pt As Variant

pt = Array(0, 0, Cos(Pi / 4), Sin(-Pi / 4), Cos(Pi / 4), Sin(Pi / 4))
Call draw_array(pt)
global_plineobj.SetBulge 1, Tan(Pi / 8)

End Sub
```

To create a rounded fillet the vertexes of the arc have to be encoded in the square edge polyline, then rounded.
The B value for 90 degrees is 90/4 or 1/4 * pi/2. Here is a program to create a filleted rectangle of any size with any radius at any location. (the draw_array sub is posted previously)

```Sub B2_test_rectangle()
Dim pt As Variant
Dim x1 As Double, x2 As Double, x3 As Double, x4 As Double
Dim y1 As Double, y2 As Double, y3 As Double, y4 As Double
Dim A As Double, B As Double, R As Double, Dx As Double, Dy As Double
'A is width X
'B is height Y
'Dx and Dy are coordinates for lower left corner

A = 4
B = 5
R = 1
Dx = 2
Dy = 2

x1 = Dx
x2 = Dx + R
x3 = A + Dx - R
x4 = A + Dx

y1 = Dy
y2 = Dy + R
y3 = B + Dy - R
y4 = B + Dy

pt = Array(x2, y1, x3, y1, x4, y2, x4, y3, x3, y4, x2, y4, x1, y3, x1, y2)
Call draw_array(pt)
global_pline.SetBulge 1, Tan(Pi / 8)
global_pline.SetBulge 3, Tan(Pi / 8)
global_pline.SetBulge 5, Tan(Pi / 8)
global_pline.SetBulge 7, Tan(Pi / 8)

End Sub
```

A slot sub would simply draw a rectangle and use a B factor for the ends to give a 180 degree arc. Here is a routine for both vertical and horizontal slots. This could be combined into one program with a switch or flag. We would also call them with the dimensions as parameters. The B factor is the TAN of one fourth of 180 or pi/4.

```Sub B2_horz_slot()
Dim pt As Variant
Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
Dim A As Double, B As Double, Cx As Double, Cy As Double
'A is length
'B is width
'Cx and Cy are center coordinates

A = 2
B = 0.5
Cx = 3
Cy = 3

x1 = Cx - A / 2
x2 = Cx + A / 2

y1 = Cy - B / 2
y2 = Cy + B / 2

pt = Array(x1, y1, x2, y1, x2, y2, x1, y2)
Call draw_array(pt)
global_pline.SetBulge 1, Tan(Pi / 4)
global_pline.SetBulge 3, Tan(Pi / 4)
Call draw_point(Cx, Cy, 0) 'this draws a point for reference
End Sub

Sub B2_vert_slot()
Dim pt As Variant
Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
Dim A As Double, B As Double, Cx As Double, Cy As Double
'A is length
'B is width
'Cx and Cy are center coordinates

A = 2
B = 0.5
Cx = 3
Cy = 3

x1 = Cx - B / 2
x2 = Cx + B / 2

y1 = Cy - A / 2
y2 = Cy + A / 2

pt = Array(x1, y1, x2, y1, x2, y2, x1, y2)
Call draw_array(pt)
global_pline.SetBulge 0, Tan(Pi / 4)
global_pline.SetBulge 2, Tan(Pi / 4)
Call draw_point(Cx, Cy, 0)
End Sub

```

autodesk (or somebody) made the B factor the tan of one fourth the included angle. As the included arc varies from zero to almost 360, one fourth of that angle varies from zero to almost 90, and the tangent of that angle (Bulge Factor B) varies from zero to infinity. Because of the imprecision of doubles, Tan(Pi/2) should give an error, the slope of a vertical line, divide by zero, but the imprecision causes an arc with a very large radius.