GregG Posted November 10, 2024 Share Posted November 10, 2024 (edited) Importing from AutoCAD or PDF creates single lines of text. Is there a straight forward way to combine single text lines into a paragraph? Edited November 10, 2024 by GregG spelling Quote Link to comment
rDesign Posted November 10, 2024 Share Posted November 10, 2024 Try installing the script linked below. You’ll still have to format the end of each text line so that it flows as a paragraph, but it will combine single line text to multi line text. Quote Link to comment
michaelk Posted November 10, 2024 Share Posted November 10, 2024 Of course @Jesse Cogswell has already done this! I took a swing at it for fun and came up with this script. Because of a limitation of the forum software you have to remove the spaces between the C and the H and the R in the line that begins CR =. This will take all selected text objects, combine them into one text object, place the text object at the highest object on the page and delete all the selected text objects. Selected objects other than text are ignored. This has an arbitrary limit of 1000 text objects because it uses a bubble sort, which is a sorting algorithm you learn in your first computer science class. Since I never took a second computer science class, that's what I'm using. Jesse's is probably much cooler. PROCEDURE Test; CONST MaxObjects = 1000; { Adjust this limit if necessary } CR = C H R(13); VAR textHandles : ARRAY[1..MaxObjects] OF HANDLE; numTextObjects, i, j : INTEGER; tempHandle : HANDLE; x1, y1, x2, y2, top1, top2 : REAL; concatenatedText : STRING; {**** Get number of text objects. Hope that it's less than 1000. Assign text objects to an array ****} PROCEDURE CollectTextObjects(h: HANDLE); BEGIN IF numTextObjects < MaxObjects THEN BEGIN numTextObjects := numTextObjects + 1; textHandles[numTextObjects] := h; END ELSE BEGIN AlrtDialog( Concat('More than ',MaxObjects, ' objects selected. Some objects may be skipped.') ); END; END; {**** Yeah, it's a bubble sort. Get over it. ****} PROCEDURE SortTextObjectsByTop; BEGIN FOR i := 1 TO numTextObjects - 1 DO BEGIN FOR j := i + 1 TO numTextObjects DO BEGIN { Get top coordinate of bounding box for comparison } GetBBox(textHandles[i], x1, y1, x2, y2); top1 := y1; { Top of the bounding box } GetBBox(textHandles[j], x1, y1, x2, y2); top2 := y1; { Top of the bounding box } { Sort in descending order (highest top coordinate first) } IF top1 < top2 THEN BEGIN tempHandle := textHandles[i]; textHandles[i] := textHandles[j]; textHandles[j] := tempHandle; END; {IF top1<top2} END; {For j := 1 to numTextObjects} END; {FOR i := 1 TO numTextObjects - 1} END; {**** Concatonate into one text object. New text object placed at location of first text object ****} PROCEDURE ConcatenateTextObjects; VAR textContent: STRING; BEGIN concatenatedText := ''; FOR i := 1 TO numTextObjects DO BEGIN textContent := GetText(textHandles[i]); IF concatenatedText = '' THEN concatenatedText := textContent ELSE concatenatedText := CONCAT(concatenatedText, CR, textContent); { Concatenate with carriage return } END; { Place the new text object at the position of the hightest text object } GetBBox(textHandles[1],x1, y1, x2, y2); IF concatenatedText <> '' THEN BEGIN MoveTo(x1, y1); BeginText; concatenatedText EndText; END ELSE BEGIN AlrtDialog('No text objects selected.'); END; END; {**** Delete the original and annoying lines of text. ****} PROCEDURE GoodbyeSingleLinesofText; BEGIN FOR i := 1 to numTextObjects DO BEGIN DelObject(textHandles[i]); END; END; BEGIN numTextObjects := 0; ForEachObject(CollectTextObjects, ((T=Text) & (VSEL=TRUE))); IF numTextObjects > 1 THEN BEGIN SortTextObjectsByTop; ConcatenateTextObjects; GoodbyeSingleLinesofText; END ELSE BEGIN AlrtDialog('No text objects selected or only one text object is selected.'); END; END; Run(Test); Combine Text.vwx 3 Quote Link to comment
Jesse Cogswell Posted November 10, 2024 Share Posted November 10, 2024 My script isn't too dissimilar to @michaelk's, it just uses a data structure in the array storing the Y location, the text, and a handle to the original text object. That way I could use the SortArray function to sort by Y location rather than needing to write my own. The only other major difference is that it contains a bit of code to handle text objects inside of symbol edit containers and viewport annotations. It also uses a dynamic array, so there's no limit to the number of objects other than having a limit to the total length of each selected text object being limited to 2048 characters due to Vectorscript's string limit and not being able to have a DYNARRAY[] OF CHAR inside a data structure. Code pasted below. Please note the C h r() change (remove the spaces in between the c, h, and r) and that my version uses plug-in strings so that it can be localized after encryption. To make it a document script, just remove the GetPluginString(3000) function and the comment brackets around the string, as in sMiscMoreThanOne:='Requires more than one Text object to be selected.'; PROCEDURE CombineTextToMultiline; {* Combines selected text boxes into a single multi-line text box Developed by: Jesse Cogswell VW Version: 24 (VW2019) Date: 5/8/2024 Revisions: *} CONST kCR = C h r(13); TYPE TextBox = STRUCTURE hd:HANDLE; y:REAL; str:STRING; END; VAR {Plug-in Strings} sMiscMoreThanOne:STRING; {Other Variables} textBoxes:DYNARRAY[] OF TextBox; currentParent:HANDLE; numText:INTEGER; PROCEDURE LoadPluginStrings; {Loads plug-in strings into variables} BEGIN sMiscMoreThanOne:=GetPluginString(3000); {'Requires more than one Text object to be selected.'} END; PROCEDURE CheckText(h:HANDLE); {Tests given text object for matching current parent container, adds to array if matching} VAR temp:TextBox; A,B:POINT; BEGIN IF(GetParent(h) = currentParent) THEN BEGIN GetBBox(h,A.x,A.y,B.x,B.y); temp.hd:=h; temp.y:=A.y; temp.str:=GetText(h); numText:=numText + 1; ALLOCATE textBoxes[1..numText]; textBoxes[numText]:=temp; END; END; PROCEDURE CombineText(arr:DYNARRAY[] OF TextBox; num:INTEGER); {Combines given text boxes into single text box and deletes originals} VAR tempStr:STRING; i:INTEGER; BEGIN tempStr:=arr[num].str; FOR i:=num - 1 DOWNTO 1 DO tempStr:=Concat(tempStr,kCR,arr[i].str); SetText(arr[num].hd,tempStr); ResetObject(arr[num].hd); FOR i:=num - 1 DOWNTO 1 DO DelObject(arr[i].hd); END; BEGIN LoadPluginStrings; numText:=0; Locus(0,0); currentParent:=GetParent(LNewObj); DelObject(LNewObj); ForEachObject(CheckText,(INSYMBOL & INVIEWPORT & ((SEL) & (T = TEXT)))); IF(numText > 1) THEN BEGIN SortArray(textBoxes,numText,2); CombineText(textBoxes,numText); END ELSE AlrtDialog(sMiscMoreThanOne); END; Run(CombineTextToMultiline); 1 Quote Link to comment
michaelk Posted November 10, 2024 Share Posted November 10, 2024 Using a structure makes way more sense!😄 Quote Link to comment
GregG Posted November 10, 2024 Author Share Posted November 10, 2024 Thank you! Very helpful. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.