Convert Old Table Data to New Table Format (AutoLISP Solutions AutoCAD Tutorial)

29 Feb, 2008 By: Tony Hotchkiss

Routine selects formatted lines, polylines, and text and converts it all to an AutoCAD table object.

Jeff Smith of Ohio e-mailed a request to create a spreadsheet kind of table by converting tables made prior to the introduction of AutoCAD's Table command. At first, I thought this could be accomplished in AutoCAD 2008 using the data extraction method of the Table command. Data extraction is a powerful tool, but when the data is in the form of lines, polylines, text, and mtext, it is quite cumbersome and time consuming to get the data in a usable format. The solution was to write the routine MAKETABLE.LSP, which allows the user to select lines, polylines, and any type of text and convert them into an AutoCAD table object that replaces the original data.

Get the Code!
Download the MAKETABLE.LSP file from Cadalyst's CAD Tips site. Save the file in AutoCAD's Support directory. Use the Appload facility by selecting Tools / Load Application, and then use the browser to select the file.

How to Use the MAKETABLE.LSP Code
To start the program, enter MTB on the Command line, and you will be prompted to "Select old table with a window: Upper left point:" followed by the prompt, "Lower right point:". The table that is made of lines, polylines, and text is automatically replaced by an AutoCAD table object that contains all original data and headers. These figures show the table before and after conversion.


A table composed of lines, polylines, and text.


The table converted to the AutoCAD table format.

The code works with most tables of the type shown with any number of rows and columns and any type of text or multiline text. The routine also works if there are lines drawn exactly on top of each other (as was the case with some of Jeff's data) or if there are polylines used arbitrarily -- for example, as separators for rows or columns. The new table format centers all cell text except for text in the Description column (if it exists), which is aligned to the left.

Programming Notes
After my usual error and system variable management functions, the program starts with the GETOLDTABLE function that uses the VLA-GETPOINT and VLA-GETCORNER methods to establish two diagonally opposite points that are used to select the table entities. The points are actually used twice: once to select any polylines that may exist and again to select all lines and text objects. If any polylines are found, they are exploded via the VLA-EXPLODE method. GETOLDTABLE concludes by creating a selection set of the lines and text objects, then calling MAKETABLE using the selection set as its argument.

MAKETABLE collects the lines and text in separate lists via calls to GET-LINES and GET-TEXT. The lines are further separated into horizontal and vertical lines via calls to GET-ROWSCOLS before being sorted into lists of rows and columns. In case there are duplicate lines, the lists of rows and columns are refined by the DO-DUPES function before being sorted again. The text objects are separated into multiline text and single-line text lists via calls to GET-TXTMTXT. The parameters for the VLA-ADDTABLE method are the number of rows and columns and the row height and column width. The table object is then created as an empty table by the following code:


    (setq tableobj (vla-AddTable
                (vlax-3D-point (caar collines3))
                ) ;_ end of vla-AddTable
    ) ;_ end of setq

The default table has a header and a title, and I opted to take out the merging for the title row and place the table object on the layer of the original text objects. Then it's time to populate the table cells by a call to POPULATE-TABLE as follows:


    (vla-UnmergeCells tableobj 0 0 0 (- cols 1))
    (setq lyr (vla-get-Layer (nth 0 horlines)))
    (vla-put-layer tableobj lyr)
    (populate-table tableobj tlist rowlines3 collines3)

One of the more interesting functions in the above is DO-DUPES, which should be fairly straightforward because there is a great Visual LISP function (VL-REMOVE) that purports to remove any item (and its duplicates) from a list. Unfortunately, in this case the method did not work consistently on lists of points because the coordinates were not exact enough, even though the lines were exactly on top of each other to within 13 decimal places! Instead, after wasting much time wondering why the duplicate lines were not being removed, I wrote my own version of the remove method (MYVL-REMOVE):


    (defun myvl-remove (item llst)
     (setq j (- 1))
     (repeat (length llst)
     (setq item2 (nth (setq j (1+ j)) llst))
     (if (equal item item2 fuzz)
     (setq llst (vl-remove item2 llst))
     ) ;_ end of if
     ) ;_ end of repeat
    ) ;_ end of myvl-remove

The solution here was to include a fuzz factor to test equality, then to remove the actual item compared in the list, shown here as ITEM2. This method only guarantees to remove one duplicated item at a time, but it tests every item in the list, so it takes care of any number of duplicates. I usually designate global variables by starting and ending them with asterisks, but in the above, the FUZZ variable does not conform to that format. In fact, throughout this particular program, I have not designated local and global variables at all except those that are passed as arguments. Programming in this way can be risky, but I opted to initialize lists and counters in the separate functions instead.

The POPULATE-TABLE function relies on taking each text object in turn from a text list and using its insertion point to determine where (which row and column) it should be placed in the new table. This is a reasonable approach for tables that are not completely full of text because the empty cells are simply not considered. All header text objects are in Row 0 (the top row), and that made it easy to deal with them. The columns for the header text were determined by the locations of the merged cells. All other text objects are placed using the VL-SETTEXT method, then the cell parameters are set for cell height, column width, text style, and text height. The code fragment for this is:


         (vla-SetText tobj row col txtstr)
    ) ;_ end of progn
    ) ;_ end of if
    (vla-SetCellTextHeight tobj row col txtht)
    (vla-SetColumnWidth tobj col colwidth)
    (vla-SetRowHeight tobj row rowheight)
    (vla-SetCellTextStyle tobj row col textstyle)

When tables are created they start off empty, then cells are formatted and text is added. Each time this is done, the table is automatically regenerated, so I advise that you hold off on regeneration until all cells are completed. The regeneration is designated as true or false, and the following code taken from the MAKETABLE function shows how this has been done:


     (vla-put-RegenerateTableSuppressed tableobj :vlax-True)
     (vla-UnmergeCells tableobj 0 0 0 (- cols 1))
     (setq lyr (vla-get-Layer (nth 0 horlines)))
     (vla-put-layer tableobj lyr)
     (populate-table tableobj tlist rowlines3 collines3)
     (if (> cols 6)
     (vla-MergeCells tableobj 0 0 0 5)
     (vla-MergeCells tableobj 0 0 6 7)
     ) ;_ end of progn
     (vla-MergeCells tableobj 0 0 0 (- cols 1))
     ) ;_ end of if
     (vla-put-RegenerateTableSuppressed tableobj :vlax-False)
     (vla-erase ss1)
    ) ;_ end of MakeTable

The last line of this function erases the entire selection set of lines and text that make up the original table.

As always, I look forward to receiving your comments and requests for "AutoLISP Solutions." Please contact me using the links below.

About the Author: Tony Hotchkiss

More News and Resources from Cadalyst Partners

For Mold Designers! Cadalyst has an area of our site focused on technologies and resources specific to the mold design professional. Sponsored by Siemens NX.  Visit the Equipped Mold Designer here!

For Architects! Cadalyst has an area of our site focused on technologies and resources specific to the building design professional. Sponsored by HP.  Visit the Equipped Architect here!