Jump to content

Import files form AutoCAD or PDF brings in single lines to text. How to best combine into paragraphs?


GregG

Recommended Posts

  • GregG changed the title to Import files form AutoCAD or PDF brings in single lines to text. How to best combine into paragraphs?

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

  • Like 3
Link to comment

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);

 

  • Like 1
Link to comment

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...