SWE Engineering has much experience creating AutoLisp software for extending the functionality of AutoCAD. Families of parts can be created through programming AutoCAD to automate many common CAD functions. AutoCAD can be programmed in AutoLisp, C, and VBA. Micro Wizard Software has experience in all of these programming systems. This is one sample of AutoLisp programming which shows some of the code used to create whole mechanical systems with a little interaction of the CAD operator.

; -------------------------------------------------------------------------
; | ..................................................................... |
; | .......... --------------------------------------------- ............ |
; | .......... | AutoCAD Geometry Generator Program | ............ |
; | .......... --------------------------------------------- ............ |
; | .......... | (c) Copyright 2001 SWE Engineering | ............ |
; | .......... | All Rights Reserved | ............ |
; | .......... --------------------------------------------- ............ |
; | ..................................................................... |
; | .......... Written by Steven W. Ellstrom ............ |
; | .......... Mar 22, 2001 ............ |
; | .......... ............ |
; | .......... Modified Apr 17, 2001 ............ |
; | ..................................................................... |
; -------------------------------------------------------------------------
; Operation:
; This is a program written in AutoLISP to create a drawing of the tooling
; for a packaging machine.
; This program basically takes the blister, flange, and card specified by
; the operator, and arrays the parts, creates conveyor trays, card and
; blister denesting plates, and sealing die for a sealer. The blister
; is first created by the program for rectangular blisters, or the operator
; draws the blister. The card is then created. (again by the program if
; rectangular or by the operator) Based on operator input, the program
; will then array the parts with the standard clearance between parts. The
; operator will be allowed to modify the array pattern. Then the locating
; pins are created parametrically by the program. The operator is allowed
; to modify these pin locations. The program then creates blister and card
; denesting plates with retaining rod slots and denesting tab holes. The
; operator is allowed to change those holes/slots. The program will then
; proceed to draw the sealing die, creating relief holes for locating
; pins, and allowing for thermal expansion. All tooling parts are created
; in the same drawing file. The operator is left to cleanup the drawing
; at this point, and create whatever drawings are necessary to release
; the individual parts in the CAD system.
; This program can only be run from the startup drawing. This drawing
; contains drawing entities for the components used in the machine's tooling.
; Other entities needed such as blocks to define where the parts should
; be stretched are also in the drawing on hidden layers. These layers
; should be left alone, but minor changes to visible geometry can be made.
; AutoLisp:
; AutoLISP is an extension of the LISP programming language. The LISP
; language is used for list processing, which is what "LISP" stands for.
; Lists in LISP are a number of items placed in parenthises and separated
; by spaces. Lists are evaluated by applying a function, which is the first
; item in the list, to the rest of the list. The list returns that value
; when evaluated. Items in the list can be functions, individual discrete
; items, or other lists. The individual items in a list which can not be
; broken down any further are called "atoms". Variables defined in LISP
; are atoms, and the values of those variables can be set using the "SET"
; command. Immediate values can only actually be set by using the quote
; function, and so setting the value of a variable is normally done by
; using the "SET QUOTE" function, usually written as "SETQ". The function
; "progn" is used to group together statements much like the "begin" and
; "end" keywords in Pascal. There are functions for accessing elements of a
; list. "car" returns the 1st element, "cdr" returns the rest of the list,
; cadr returns the 2nd element. "list" constructs a list, and "cons" adds
; an element to a list. A special type of list called a dotted pair must
; contain 2 elements separated by a period. The "assoc" function will
; extract the dotted pair from a list of dotted pairs where the first item
; in that dotted pair matches the assoc value.
; A list in AutoCAD can be evaluated by typing the list at the AutoCAD
; Command: prompt. (complete with parenthises) For example, typing (+ 2 2)
; into autoCAD will evaluate the list by applying the plus function to the
; rest of the list and returning the value 4. In AutoCAD, the LISP language
; can access the AutoCAD drawing database stored in each drawing. In
; general, points are handled as lists of points such as (1.0 2.0 2.5)
; where the point specified has X=1.0 Y=2.0 Z=2.5. AutoCAD commands can be
; executed from AutoLISP by using the "command" function. For example,
; (command "ZOOM" "ALL") will execute the ZOOM ALL command. The AutoCAD
; drawing database is made up of all the drawing elements in a drawing.
; It is accessible from AutoLISP using the "entget" and "ssget" functions.
; Entities are returned as lists of dotted pairs. Elements are made up
; of entity parameters stored in those dotted pairs.
; The following parameter values are used:
; 0 - Entity Type (POINT, LINE, CIRCLE, ARC, POLYLINE, etc..)
; 1 - Block Value
; 2 - Block Name
; 8 - Layer Name
; 10 - Point 1
; 11 - Point 2
; 40 - Radius
; 41 - X scale
; 42 - Y scale
; 50 - Ang1
; 51 - Ang2
; There are a number of AutoLISP functions defined in this program. The
; parameters passed to the function are defined in the list following the
; function name in the defun line. Local variables are listed after the /
; and are safe from being accidentally modified by another function.
; Functions defined as c:functionname can be executed by the AutoCAD
; operator when they type the function name at the command: prompt. The
; following functions are defined:
; START - Go to "START" view and UCS
; ALL - Go to "ZOOM ALL" view and World UCS
; DONE - Done editing drawing, run next step in this program
; CONT - Same as DONE
; The continue function (called by DONE and CONT) is redefined after each
; step to point to the next logical function in the program. All functions
; defined in this program have a heading showing a brief description of that
; function in a box. The box is a single outline for supporting functions,
; and a double outline for those main functions which describe the higher
; level operations performed by this program.
; -----------------------------------------------------------------------------
; | BEEP |
; | Go to text page, clear screen and beep |
; -----------------------------------------------------------------------------
(defun beep ()
(textpage)
; (write-char 7)
)
; -----------------------------------------------------------------------------
; | MAKELIST |
; | Returns a list of n elements initialized to m |
; -----------------------------------------------------------------------------
(defun makelist (n m / i j)
(setq i 1 j nil)
(while (<= i n)
(progn
(setq j (cons m j))
(setq i (1+ i))
)
)
j
)
; -----------------------------------------------------------------------------
; | SETLIST |
; | Returns a copy of list l with element n = m |
; -----------------------------------------------------------------------------
(defun setlist (l n m / i j)
(setq i (1- (length l)) j nil)
(while (>= i 0)
(progn
(if (= i n)
(setq j (cons m j))
; else
(setq j (cons (nth i l) j))
)
(setq i (1- i))
)
)
j
)
; -----------------------------------------------------------------------------
; | ~= |
; | Approximately equal |
; -----------------------------------------------------------------------------
(defun ~= (n m)
(if (= (type n) 'LIST)
(and (~= (car n) (car m)) (~= (cadr n) (cadr m)))
(< (abs (- n m)) 0.00001)
)
)
; -----------------------------------------------------------------------------
; | REFPOINT |
; | Returns reference point named ptname in ptlist |
; -----------------------------------------------------------------------------
(defun refpoint (ptname)
(cdr (assoc ptname ptlist))
)
; -----------------------------------------------------------------------------
; | VIEW |
; | Restore view named v or find reference pt closest to v |
; | and restore the view of the same name |
; -----------------------------------------------------------------------------
(defun view (v / n lname pl d)
(if (= (type v) 'STR)
(setq vname v)
; else
(progn
(setq d 100000.0 vname "ALL")
(setq n 0)
(while (nth n ptlist)
(progn
(setq lname (car (nth n ptlist)))
(setq pl (cdr (nth n ptlist)))
(if (< (distance v pl) d) (setq d (distance v pl) vname lname))
(setq n (1+ n))
)
)
)
)
(if (or (= (type v) 'STR) (and (/= vname currentview) (/= currentview "ALL")))
(progn
(command "VIEW" "RESTORE" vname)
(setq currentview vname)
)
)
)
; -----------------------------------------------------------------------------
; | LINELST |
; | Returns list of type "LINE" |
; -----------------------------------------------------------------------------
(defun linelst (x y i j absmode)
(if absmode
(list '(0 . "LINE") (list 10 x y 0.0) (list 11 i j 0.0))
; else
(list '(0 . "LINE") (list 10 x y 0.0) (list 11 (+ x i) (+ y j) 0.0))
)
)
; -----------------------------------------------------------------------------
; | SELECTPT |
; | Returns selection pt for entity e |
; -----------------------------------------------------------------------------
(defun selectpt (e / p p1 p2 r a1 a2)
(setq ent (entget e))
(if (= (cdr (assoc 0 ent)) "LWPOLYLINE")
(progn
;(setq ent (entget (entnext e)))
(setq p (cdr (assoc 10 ent)))
)
)
(if (= (cdr (assoc 0 ent)) "LINE")
(progn
(setq p1 (cdr (assoc 10 ent)))
(setq p2 (cdr (assoc 11 ent)))
(setq p (midpt p1 p2))
)
)
(if (= (cdr (assoc 0 ent)) "CIRCLE")
(progn
(setq p1 (cdr (assoc 10 ent)) r (cdr (assoc 40 ent)))
(setq p (midarc p1 r 0.0 PI))
)
)
(if (= (cdr (assoc 0 ent)) "ARC")
(progn
(setq p1 (cdr (assoc 10 ent)) r (cdr (assoc 40 ent)))
(setq a1 (cdr (assoc 50 ent)) a2 (cdr (assoc 51 ent)))
(setq p (midarc p1 r a1 a2))
)
)
p
)
; -----------------------------------------------------------------------------
; | BOX |
; | Returns a list of startpt and endpt for box block w/ value "name" |
; -----------------------------------------------------------------------------
(defun box (name / ss n ent attr sp x1 y1 x2 y2)
(setq ss (ssget "X" '((0 . "INSERT") (2 . "BOX"))))
(setq n 0)
(while (< n (sslength ss))
(progn
(setq en (ssname ss n) ent (entget en))
(setq attr (entget (entnext en)))
(if (= (cdr (assoc 1 attr)) name)
(progn
(setq sp (cdr (assoc 10 ent))) ; X,Y insert
(setq x1 (car sp))
(setq y1 (cadr sp))
(setq x2 (+ x1 (cdr (assoc 41 ent)))) ; X scale
(setq y2 (+ y1 (cdr (assoc 42 ent)))) ; Y scale
(setq n (sslength ss))
)
)
(setq n (1+ n))
)
)
(list sp (list x2 y2))
)
; -----------------------------------------------------------------------------
; | MIDPT |
; | Returns midpoint of line segment |
; -----------------------------------------------------------------------------
(defun midpt (p1 p2 / x1 y1 x2 y2)
(setq x1 (car p1) y1 (cadr p1) x2 (car p2) y2 (cadr p2))
(list (/ (+ x1 x2) 2) (/ (+ y1 y2) 2))
)
; -----------------------------------------------------------------------------
; | MIDARC |
; | Checks if Pt is on arc |
; -----------------------------------------------------------------------------
(defun midarc (ctr r a1 a2 / amid)
(if (< a2 a1) (setq a2 (+ a2 (* PI 2)))) ' Always CCW
(setq amid (+ a1 (* (- a2 a1) 0.406)))
(setq pt (polar ctr amid r))
)
; -----------------------------------------------------------------------------
; | ONSEG |
; | Checks if Pt is on line segment |
; -----------------------------------------------------------------------------
(defun onseg (p seg / p1 p2 a l aok mid)
(setq p1 (cdr (assoc 10 seg)) p2 (cdr (assoc 11 seg)))
(setq mid (midpt p1 p2))
(setq a (angle p1 p2) l (distance p1 p2))
(setq aok (or (~= (angle mid p) a) (~= (angle p mid) a) (~= mid p)))
(and (<= (distance mid p) (/ l 2)) aok)
)
; -----------------------------------------------------------------------------
; | ONARC |
; | Checks if Pt is on arc |
; -----------------------------------------------------------------------------
(defun onarc (pt arc / ctr r a1 a2 apt)
(setq ctr (cdr (assoc 10 arc)) r (cdr (assoc 40 arc)))
(setq a1 (cdr (assoc 50 arc)) a2 (cdr (assoc 51 arc)))
(if (< a2 a1) (setq a2 (+ a2 (* PI 2)))) ' Always CCW
(setq apt (angle ctr pt))
(if (< apt a1) (setq apt (+ apt (* PI 2))))
(and (>= apt a1) (<= apt a2) (~= r (distance ctr pt)))
)
; -----------------------------------------------------------------------------
; | INTPT |
; | Find int of line and line/circle/arc |
; | (returns closest to start pt of line if 2 exist) |
; -----------------------------------------------------------------------------
(defun intpt (ln ent
/ typ pt1 pt2 pt| pt4 xpt1 xpt2 cen rad slope a1 a2 ok1 ok2
piv dist1 dist2 len1 len2 ang1a ang1b len_a opp dist)
(setq xpt nil)
(setq pt1 (cdr (assoc 10 ln)) pt2 (cdr (assoc 11 ln)))
(setq typ (cdr (assoc 0 ent)))
(if (= typ "LINE")
(progn
(setq pt1 (cdr (assoc 10 ent)) pt4 (cdr (assoc 11 ent)))
(setq xpt (inters pt1 pt2 pt1 pt4))
)
)
(if (or (= typ "CIRCLE") (= typ "ARC"))
(progn
(setq cen (cdr (assoc 10 ent)) rad (cdr (assoc 40 ent)))
(if (= typ "ARC")
(setq a1 (cdr (assoc 50 ent)) a2 (cdr (assoc 51 ent)))
(setq a1 0 a2 (* PI 2))
)
(setq dist1 (distance pt2 cen) dist2 (distance pt1 cen))
(if (> dist1 dist2)
(progn
(setq ang1a (abs (- (angle pt1 pt2) (angle cen pt2))))
(setq slope (angle pt2 pt1))
(setq dist dist1)
(setq piv pt2)
)
(progn
(setq ang1a (abs (- (angle pt2 pt1) (angle cen pt1))))
(setq slope (angle pt1 pt2))
(setq dist dist2)
(setq piv pt1)
)
)
(if (> ang1a PI) (setq ang1a (- ang1a PI)))
(setq ang1b (abs (- (/ PI 2) ang1a)))
(setq opp (* (sin ang1a) dist))
(if (< opp rad)
(progn
(setq cos_b (/ opp rad))
(setq len_a (sqrt (- (expt rad 2) (expt opp 2))))
(setq len1 (- (sqrt (- (expt dist 2) (expt opp 2))) len_a))
(setq len2 (+ len1 (* len_a 2)))
(setq xpt1 (polar piv slope len1))
(if (= typ "ARC")
(setq ok1 (and (onseg xpt1 ln) (onarc xpt1 ent)))
(setq ok1 (onseg xpt1 ln))
)
(setq xpt2 (polar piv slope len2))
(if (= typ "ARC")
(setq ok2 (and (onseg xpt2 ln) (onarc xpt2 ent)))
(setq ok2 (onseg xpt2 ln))
)
(setq dist1 (distance pt1 xpt1) dist2 (distance pt1 xpt2))
(if (<= dist1 dist2)
(if ok1
(setq xpt xpt1)
(if ok2 (setq xpt xpt2))
)
(if ok2
(setq xpt xpt2)
(if ok1 (setq xpt xpt1))
)
)
)
)
)
)
xpt
)
; -----------------------------------------------------------------------------
; | MINMAX |
; | Find min and max X and Y points |
; -----------------------------------------------------------------------------
(defun minmax (p)
(setq x (car p))
(setq y (cadr p))
(if (< x minx) (setq minx x))
(if (> x maxx) (setq maxx x))
(if (< y miny) (setq miny y))
(if (> y maxy) (setq maxy y))
)
; -----------------------------------------------------------------------------
; | MEASURE |
; | Finds the Min/Max of a layer |
; | (Exploding LWPOLYLINES if found) |
; -----------------------------------------------------------------------------
(defun measure (layer / ss n en ent p r a1 a2)
(setq minx 100000.0 maxx -100000.0 miny 100000.0 maxy -100000.0)
(setq ss (ssget "X" (list (cons 8 layer))))
(setq n 0)
(while (< n (sslength ss))
(progn
(setq en (ssname ss n) ent (entget en))
(if (= (cdr (assoc 0 ent)) "LWPOLYLINE") (command "EXPLODE" en))
(setq n (1+ n))
)
)
(setq ss (ssget "X" (list (cons 8 layer))))
(setq n 0)
(if ss
(while (< n (sslength ss))
(progn
(setq en (ssname ss n) ent (entget en))
(if (= (cdr (assoc 0 ent)) "LINE")
(progn
(minmax (cdr (assoc 10 ent)))
(minmax (cdr (assoc 11 ent)))
)
)
(if (= (cdr (assoc 0 ent)) "ARC")
(progn
(setq p (cdr (assoc 10 ent)) r (cdr (assoc 40 ent)))
(setq a1 (cdr (assoc 50 ent)) a2 (cdr (assoc 51 ent)))
(if (< a2 a1) (setq a2 (+ a2 (* PI 2))))
(setq a 0)
(while (<= a a2)
(progn
(if (and (>= a a1) (<= a a2))
(minmax (polar p a r))
)
(setq a (+ a (/ PI 2)))
)
)
(minmax (polar p a1 r))
(minmax (polar p a2 r))
)
)
(if (= (cdr (assoc 0 ent)) "CIRCLE")
(progn
(setq p (cdr (assoc 10 ent)) r (cdr (assoc 40 ent)))
(minmax (polar p 0.0 r))
(minmax (polar p (/ PI 2) r))
(minmax (polar p PI r))
(minmax (polar p (* PI 1.5) r))
)
)
(setq n (1+ n))
)
)
)
)
; -----------------------------------------------------------------------------
; | PICKPT |
; | Find pt intersecting with line and entities on layer |
; -----------------------------------------------------------------------------
(defun pickpt (ln layer / ss n ent pickp p)
(setq ss (ssget "X" (list (cons 8 layer))))
(setq n 0 pickp nil)
(if ss
(while (< n (sslength ss))
(progn
(setq ent (entget (ssname ss n)))
(setq p (intpt ln ent))
(if p
(progn
(setq pickp p)
(setq n (sslength ss))
)
)
(setq n (1+ n))
)
)
)
pickp
)
; -----------------------------------------------------------------------------
; | POLYLINE |
; | Creates a polyline from entities on layer starting at pt |
; -----------------------------------------------------------------------------
;(defun polyline (layer / ln1 ln2 p1 p2 ss n en ent)
(defun polyline (layer)
(measure layer)
(setq ln1 (linelst (/ (+ minx maxx) 2.0) (/ (+ miny maxy) 2.0) 0 100 nil))
(setq ln2 (linelst (- (/ (+ minx maxx) 2.0) 0.001) (/ (+ miny maxy) 2.0) 0 100 nil))
(setq ss (ssget "X" (list (cons 8 layer))))
(command "CHPROP" ss "" "LT" "CONTINUOUS" "")
(setq n 0 p1 nil p2 nil)
(while (< n (sslength ss))
(progn
(setq en (ssname ss n) ent (entget en))
(setq p (intpt ln1 ent))
(if p (setq p1 p e1 en))
(setq p (intpt ln2 ent))
(if p (setq p2 p e2 en))
(setq n (1+ n))
)
)
(if (= e1 e2) (command "BREAK" p1 p2)) ; Break line through start pt
(setq ss (ssget "X" (list (cons 8 layer)))) ; Get all entities on layer
(if (/= e1 e2) ; Make into one Polyline
(progn
(ssdel e2 ss)
(line p1 p2)
(setq en (entlast))
(command "PEDIT" e1 "Y" "J" ss "J" e2 en "" "X")
)
; else
(command "PEDIT" e1 "Y" "J" ss "" "X")
)
(entlast)
)
; -----------------------------------------------------------------------------
; | SETLAYER |
; | Sets current layer |
; -----------------------------------------------------------------------------
(defun setlayer (name)
(command "LAYER" "SET" name "")
)
; -----------------------------------------------------------------------------
; | FREEZE |
; | Freeze a layer |
; -----------------------------------------------------------------------------
(defun freeze (name)
(command "LAYER" "FREEZE" name "")
)
; -----------------------------------------------------------------------------
; | THAW |
; | Thaw a layer |
; -----------------------------------------------------------------------------
(defun thaw (name)
(command "LAYER" "THAW" name "")
)
; -----------------------------------------------------------------------------
; | LINE |
; | Draw a line from p1 p2 |
; -----------------------------------------------------------------------------
(defun line (p1 p2)
(view (trans p1 1 0))
(command "LINE" p1 p2 "")
)
; -----------------------------------------------------------------------------
; | CIRCLE |
; | Draw a circle at x,y radius r |
; -----------------------------------------------------------------------------
(defun circle (x y r)
(view (trans (list x y) 1 0))
(command "CIRCLE" (list x y) r)
)
; -----------------------------------------------------------------------------
; | RCT |
; | Draw a rectangular polyline w/ radius |
; -----------------------------------------------------------------------------
(defun rct (x y w h r)
(view (trans (list x y) 1 0))
(command "PLINE" (list (- x (/ w 2.0)) (- y (/ h 2.0))))
(command (list (+ x (/ w 2.0)) (- y (/ h 2.0))))
(command (list (+ x (/ w 2.0)) (+ y (/ h 2.0))))
(command (list (- x (/ w 2.0)) (+ y (/ h 2.0))))
(command "C")
(if (> r 0)
(progn
(command "FILLET" "RADIUS" r)
(command "FILLET" "P" (entlast))
)
)
)
; -----------------------------------------------------------------------------
; | INS |
; | Insert a block at pt p named "name" x1,y1,a0 |
; -----------------------------------------------------------------------------
(defun ins (name p)
(command "INSERT" name p "" "" "")
)
; -----------------------------------------------------------------------------
; | MOVE |
; | Moves entity at p1 from p2 to p| |
; -----------------------------------------------------------------------------
(defun move (p1 p2 p|)
(if (and (/= (type p1) 'STR) (/= (type p1) 'ENAME) (/= (type p1) 'PICKSET))
(view p1)
)
(command "MOVE" p1 "" p2 p1)
)
; -----------------------------------------------------------------------------
; | COPY |
; | Copies entity at p1 from p2 to p| |
; -----------------------------------------------------------------------------
(defun copy (p1 p2 p|)
(if (and (/= (type p1) 'STR) (/= (type p1) 'ENAME) (/= (type p1) 'PICKSET))
(view p1)
)
(command "COPY" p1 "" p2 p1)
)
; -----------------------------------------------------------------------------
; | ARRAY |
; | Arrays entity at p1 rows, cols at dist x,y |
; -----------------------------------------------------------------------------
(defun array (p1 cols rows x y)
(if (and (/= (type p1) 'STR) (/= (type p1) 'ENAME) (/= (type p1) 'PICKSET))
(view p1)
)
(if (> rows 1)
(if (> cols 1)
(command "ARRAY" p1 "" "R" (itoa rows) (itoa cols) (rtos y) (rtos x))
; else
(command "ARRAY" p1 "" "R" (itoa rows) (itoa cols) (rtos y))
)
(if (> cols 1)
(command "ARRAY" p1 "" "R" (itoa rows) (itoa cols) (rtos x))
)
)
)
; -----------------------------------------------------------------------------
; | STRETCH |
; | Find block named "name" and stretch a crossing window |
; | defined by that box x and y distance |
; -----------------------------------------------------------------------------
(defun stretch (name x y / bx xm ym p1 p2)
(setq bx (box name))
(setq xm (rtos x) ym (rtos y))
(setq p1 (car bx) p2 (cadr bx))
(view (list (/ (+ (car p1) (car p2)) 2) (/ (+ (cadr p1) (cadr p2)) 2)))
(command "STRETCH" "C" p1 p2 "" "0,0" (strcat xm "," ym))
)
; -----------------------------------------------------------------------------
; | OFFSET |
; | Offsets entity at p1 toward p2 |
; -----------------------------------------------------------------------------
(defun offset (p1 offsetdist p2)
(if (= (type p1) 'ENAME)
(setq p1 (selectpt p1))
)
(view p1)
(command "OFFSET" (rtos offsetdist) p1 p2 "")
)
; -----------------------------------------------------------------------------
; | LISTSS |
; | List a selection set |
; -----------------------------------------------------------------------------
(defun listss (ss)
(if ss
(progn
(setq n 0)
(while (< n (sslength ss))
(progn
(setq en (ssname ss n) ent (entget en))
(princ ent)
(princ)
(princ)
(setq n (1+ n))
)
)
)
)
)
; -----------------------------------------------------------------------------
; | C:START |
; | Go to "START" view and UCS |
; -----------------------------------------------------------------------------
(defun C:START ()
(view "START")
(command "UCS" "W" "UCS" "O" startpt)
(princ)
)
; -----------------------------------------------------------------------------
; | C:ALL |
; | Go to "ZOOM ALL" view and World UCS |
; -----------------------------------------------------------------------------
(defun C:ALL ()
(command "UCS" "WORLD")
(view "ALL")
(print)
(print)
(print)
)
This is just an example of the kind of solution we provide. If you're looking for this type of application, or you need a custom CAD application to solve a specific problem, then contact us at info@swe-eng.com We'll be glad to help.
Send mail to webmaster@swe-eng.com with questions or comments about this web site.
Please read our Usage Rules before using any information from this site.
Copyright © 2000 SWE Engineering
Last modified: June 10, 2002