Lunchtime diversion, so no crankiness here.
No fuzz sorting or k-means clustering, just assume that rows follow an approximately even spacing (but columns seldom do due to text width).
Other caveats listed in code. Most significantly, gaps in table entries are not handled.
Enhancement could be to supply a vector instead of Row spacing (Yspace), then use the vector to transform coordinates for table with rotation.
(defun C:TestTGTL
( / SET0 DataList CNT MyEnt MyEntData EntType YSpace
) ; Test routine for 'TextGridToList' aka Challenge A36
; KJM - March 2022
; Leave 'Ans' as global
; Get bunch of text items
(prompt "\nSelect text entities, omitting any headers...")(princ)
)
) ; close repeat
(setq Ans
(TextGridToList DataList YSpace
0)) ) ; close repeat
)
) ; close if
; Next steps:
; use Lee Mac's 'LM:writecsv' to write to CSV
; or use Fixo's Excel library to write directly into Excel
)
(defun TextGridToList
(MyList YSpace RetCode
/ TextEntList CNT MyItem CNT1 MyItem1 MyEnt MyEntData EntType TextString X Y MyLayer XMin XMax YMin YMax
S1 S2 NumItems NumRows RowList Index OutList OutList1
)
; Challenge A36 - Convert a number of text entities in grid format to 2D list or list of CSV entries
; KJM - March 2022
; Input:
; MyList - (list or enames)
; YSpace - (real) typical row spacing (basis: table columns may differ but rows ususully have consistent spacing)
; RetCode - (integer) code indicating what to return
; 0 or nil = return list of text strings only
; 1 = return list of sublists of (0-Ename 1-TextString 2-X 3-Y 4-layer), may be useful for Excel <--> Acad conversion
; Returns:
; list of text values with rows as sublists ((row0) (row1) (row2)...)
; Uses custom functions:
; Replace1
; Notes and Assumptions:
; Uses 'simple' Text or single item Mtext entities, not a table or multiline Mtext
; table is orthagonal and aligned with X and Y axes
; table is in plan view, Z coordinate not considered
; Gaps in data not handled (just return a fewer number of items in row sublists)
; defaults
; Build list of (0-Ename 1-TextString 2-X 3-Y 4-layer) and get minimum and maximum X,Y values
; Only add text
(setq TextString
(cdr (assoc 1 MyEntData
))) ; multiline Mtext not accommodated (setq MyLayer
(cdr (assoc 8 MyEntData
))) ; don't need this, but may want to add separation by layer
; Build list
(setq TextEntList
(cons (list MyEnt TextString X Y MyLayer
) TextEntList
))
; Get min and max X, Y
; Initialize min and max
)
)
; Update min and max
)
) ; close if
) ; close repeat
; Sort by Y (not needed)
;(setq TextEntList (vl-sort TextEntList '(lambda (S1 S2) (< (nth 3 S1) (nth 3 S2)))))
; Group by Y
(setq NumRows
(1+ (fix (+ 0.5 (/ (- Ymax Ymin
) Yspace
)))))
(setq RowList
(cons '
() RowList
)) ; build list with emply list elements for each row ) ; close repeat
(setq MyItem
(nth CNT TextEntList
))
(setq Index
(fix (+ 0.5 (/ (- Y Ymin
) Yspace
)))) ; get index (setq RowList
(replace1 RowList Index
(cons MyItem
(nth Index RowList
)))) ; update RowList to include current item
) ; close repeat
(setq RowList
(reverse RowList
)) ; reverse to place row with largest Y first
; Sort each sublist in RowList by X
(setq RowList
(replace1 RowList CNT MyItem
)) ; update RowList with sorted values
) ; close repeat
; Process output
; Return simple nested list of text values
) ; close repeat
) ; close repeat
)
)
(setq OutList RowList
) ; more complex list )
) ; close cond
OutList
)
(defun Replace1
(MyLIST POS NEWITEM
/ K CNT NEWLIST
) ; Replace one item in a list with a new item
; KJM - 1989?, Misc mods - KJM - Aug 2005
; Input:
; MyList - a list
; POS - (integer) list position
; NewItem - new item to be inserted into list, replacing old item
; Returns:
; List with item replaced
)
)
)
)
NEWLIST
)
Output:
(S1 1350 Type C 95.861 94.57 1.066 577058.125 135718.604)
(S2 1350 Type C 95.741 94.47 1.046 577058.180 135706.489)
(S3 1350 Type C 95.544 94.22 1.099 577055.753 135686.910)
(S4 1350 Type C 95.358 94.02 1.113 577058.152 135669.421)
(S5 1350 Type C 95.209 93.925 1.059 577052.074 135656.460)
(S6 1350 Type C 97.424 96.29 0.909 577003.660 135702.212)
(S7 1350 Type C 96.260 95.05 0.985 577009.494 135671.766)
(S8 1350 Type C 95.372 93.97 1.177 577026.597 135656.388)