Convert texts that are close to each other into Mtext

Convert texts that are close to each other into Mtext

oli-123
Contributor Contributor
6,145 Views
36 Replies
Message 1 of 37

Convert texts that are close to each other into Mtext

oli-123
Contributor
Contributor

Would it be possible to select all the text objects within a drawing and then convert those that are close to each other into individual Mtext? I'm trying to figure out a fast way to do this with hundreds of Mtext.

 

See attached sample drawing in case you need it.

0 Likes
Accepted solutions (1)
6,146 Views
36 Replies
Replies (36)
Message 2 of 37

pendean
Community Legend
Community Legend
Have you tried TXT2MTXT command built into the program (or if you are using an old version, its part of EXPRESS TOOLS) https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/AutoC...
0 Likes
Message 3 of 37

Kent1Cooper
Consultant
Consultant

@pendean wrote:
Have you tried TXT2MTXT command ....

That's not going to do it:

Kent1Cooper_0-1632779173182.png

They're looking to convert adjacent pairs of Text objects into separate two-line Mtext objects, but by overall collective selection.

 

I suspect it's going to require stepping through the Text objects and evaluating how far they are from all other Text objects, with some kind of criteria about how close is close enough.  @oli-123 , are they always pairs, or might there sometimes be more than 2 close together that you want converted into one Mtext object?

 

And even finding the correct pairings or groupings, TXT2MTXT does odd things if the rotation is not zero:

Kent1Cooper_1-1632779641488.png

 

Kent Cooper, AIA
Message 4 of 37

oli-123
Contributor
Contributor

Yeah, the numbers I want to convert into Mtext are always in pairs, so there won't any with 3 texts.

 

I've tried using TXT2MTXT command too, but it keeps moving the text too much.

0 Likes
Message 5 of 37

Kent1Cooper
Consultant
Consultant
Accepted solution

@oli-123 wrote:

.... the numbers I want to convert into Mtext are always in pairs, so there won't any with 3 texts.

....


Give this a try [it worked for me in your sample drawing]:

 

(defun C:2T2M ; = 2 nearby Text objects {to} two-line Mtext
  (/ ss1 T1 minpt maxpt LL UR ss2 T2 data1 data2 txt1 txt2)
  (if (setq ss1 (ssget "_:L" '((0 . "TEXT"))))
    (while (> (sslength ss1) 1); still at least 2 Text objects remaining
      (setq T1 (ssname ss1 0))
      (vla-getboundingbox (vlax-ename->vla-object T1) 'minpt 'maxpt)
      (setq
        LL (vlax-safearray->list minpt)
        UR (vlax-safearray->list maxpt)
      ); setq
      (if
        (and ; finds 2 Text objects [including T1] in vicinity
          (setq ss2
            (ssget
              "_C"
                (polar LL (angle UR LL) (distance LL UR))
                (polar UR (angle LL UR) (distance LL UR))
              '((0 . "TEXT"))
            ); ssget
          ); setq
          (= (sslength ss2) 2)
        ); and
        (progn ; then
          (setq T2 (ssname (ssdel T1 ss2) 0))
          (vla-getboundingbox (vlax-ename->vla-object T2) 'minpt 'maxpt)
          (setq ; collective bounding box of both
            LL (mapcar 'min (vlax-safearray->list minpt) LL)
            UR (mapcar 'max (vlax-safearray->list maxpt) UR)
            data1 (entget T1)
            data2 (entget T2)
            txt1 (cdr (assoc 1 data1))
            txt2 (cdr (assoc 1 data2))
          ); setq
          (command "_.ucs" "_object" T1)
          (if (minusp (cadr (trans (cdr (assoc 10 data2)) 0 1))); T2 "under" T1
            (setq txtA txt1 txtB txt2); then
            (setq txtA txt2 txtB txt1); else
          ); if
          (command
            "_.ucs" "_previous"
            "_.mtext"
              "_non" LL
              "_height" (cdr (assoc 40 data1))
              "_rotation" (cdr (assoc 50 data1))
              "_style" (cdr (assoc 7 data1))
              "_justify" "_mc" "_non" UR
              (strcat txtA "\\P" txtB) ""
            "_.matchprop" T1 (entlast) "" ; Layer, color etc. override(s)
            "_.erase" T1 T2 ""
          ); command
          (ssdel T1 ss1) (ssdel T2 ss1)
        ); progn
        (ssdel T1 ss1); else [no other nearby]
      ); if
    ); while
  ); if
  (princ)
); defun

 

It can very slightly shift the positions, because its line spacing is as defined in the font used, which can be different from the spacing between the original Text objects [which is not the same everywhere in the sample drawing], and also because the bounding box is affected even by the particular text content and the rotation.

 

It could have unexpected results if arrangement is ever non-standard, such as if the pairs do not match in angle, which could mean it might read which is on top differently from what you would expect.  Or if they don't match in other properties -- it uses the one called T1 for all the characteristics [Style, Rotation, Height, Layer and any property overrides], but that could be either the upper or the lower one in a given pair, depending on the method of selection and/or the drawing order.

 

It could use an *error* handler to ensure setting the UCS back, and command-echo suppression, and the other typical things, but first see whether it does what you want.

Kent Cooper, AIA
Message 6 of 37

kwankitfu
Participant
Participant
@Kent1Cooper
how about 3 nearby text into 3 lines M-text?
0 Likes
Message 7 of 37

Kent1Cooper
Consultant
Consultant

That may be possible.  If the situation is similar to the OP's, but with groups of 3 instead of 2, then the "reaching out" around a given Text object in the overall selection would need to reach farther out to find the associated others, in case the one it's reaching out from is not the middle one in a group of 3.  I would wonder whether some sets might be close enough together that more would be found than intended, and would need to think about how to process only those within a certain kind of relationship.  Do you have a [small] sample drawing showing likely arrangements?

Kent Cooper, AIA
0 Likes
Message 8 of 37

kwankitfu
Participant
Participant

Here is the sample drawing. in fact the data given were usually in grouping of 2 ~ 5 text. 

0 Likes
Message 9 of 37

Sea-Haven
Mentor
Mentor

A complex task may be able to be done as the purple text is on a different layer than the other text. So maybe a step by step approach using ssget "f" once nothing is found both directions then stop. The text must be approx vertical aligned not a mix of angles maybe version 5.

 

SeaHaven_0-1677739168704.png

 

Dinner time now maybe Kent will jump in if he thinks my idea will work, happy to hear of any other way to approach.

 

0 Likes
Message 10 of 37

Kent1Cooper
Consultant
Consultant

@kwankitfu wrote:

Here is the sample drawing. in fact the data given were usually in grouping of 2 ~ 5 text. 


Clarify....


The groupings are not of 2 to 5 Text objects as described above and in the drawing, but of one Text object [on the UNIT-ADDRESS Layer] and one or more Mtext objects [on the CPNO-... Layer].  Do you, in fact, want both kinds combined into the Mtext results?  It would seem necessary for two of your circled groups containing only two, one of each kind.

 

And is it acceptable that they will afterwards, of course, be on one Layer -- the distinction between the Layers of the source objects will be lost?

 

@Sea-Haven 's suggestion of using Fence selection has the possible drawback that if the Fence line happens to pass through a gap between characters, the Text/Mtext object will not be found.  So I think a bounding-box-based selection would be better, likely a Crossing window built to extend above and below that of a UNIT-ADDRESS Text object to find the nearby CPNO-... Mtext objects.  Are they always "safely" separated from other groups as in the drawing?  And are they always at zero rotation?

Kent Cooper, AIA
0 Likes
Message 11 of 37

Sea-Haven
Mentor
Mentor

Removed did not work with more testing.

0 Likes
Message 12 of 37

Kent1Cooper
Consultant
Consultant

@Sea-Haven wrote:

Removed did not work with more testing.


Removed what?  Removed it from what?

Kent Cooper, AIA
0 Likes
Message 13 of 37

kwankitfu
Participant
Participant

yes, it can be in one layer. In fact i can explode all mtext into text first and even move all text closer to each others. I just want the text to be in 1 mtext and the sequence is not my priority focus also.

0 Likes
Message 14 of 37

kwankitfu
Participant
Participant

yes, the data given were all separated & the orientation of text were always 0 as in the sample drawing.  

0 Likes
Message 15 of 37

Sea-Haven
Mentor
Mentor

Try this its really step 1 as it will need some adjustment but seems to be making mtext. Any one please comment. 

 

; https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/convert-texts-that-are-close-to-each-other-into-mtext/td-p/10650813
; An attempt by Alan H March 2023

(defun c:ahmtxt ( / oldsnap ss ss2 pt1 pt2 pt3 pt4 lst ent inspt txt lst k str )
(setq oldsnap (getvar 'osmode))
(setvar 'osmode 0)
(setq ss (ssget (list (cons 0 "*TEXT")(cons 8 "UNIT-ADDRESS"))))
(repeat (setq x (sslength ss))
(setq pt1  (cdr (assoc 10 (entget (ssname ss (setq x (1- x)))))))
(setq pt1 (mapcar '+ pt1 (list 0.0 5.0 0.0)))
(setq pt2 (mapcar '+ pt1 (list 4.0 -15.0 0.0)))
(setq pt3 (mapcar '+ pt1 (list 4.0 0.0 0.0)))
(setq pt4 (mapcar '+ pt1 (list 8.0 -15 0.0)))
(setq ss2 (ssget "F" (list pt1 pt2 pt3 pt4)))
(setq lst '())
(repeat (setq I (sslength ss2))
(setq ent (entget (ssname ss2 (setq i (1- i)))))
(setq inspt (cdr (assoc 10 ent)))
(setq txt (cdr (assoc 1 ent)))
(setq lst (cons (list (cadr inspt) txt) lst))
)
(setq lst  (vl-sort lst
 (function (lambda (e1 e2) (> (car e1) (car e2))))
 )
)
(setq k 0)
(setq str (cadr (nth 0 lst)))
(repeat (- (length lst) 1)
(setq str (strcat str "\\P" (cadr (nth (setq k (1+ k)) lst))))
)
(entmakex (list (cons 0 "MTEXT")         
(cons 100 "AcDbEntity")
(cons 100 "AcDbMText")
(cons 10 pt1)
(cons 1 str))
)
)
(setvar 'osmode oldsnap)
(princ)
)
(C:ahmtxt)
0 Likes
Message 16 of 37

kwankitfu
Participant
Participant

@Sea-Haven 

Its works perfectly. Thanks a lot. you save me days of work. Really appreciate. 

0 Likes
Message 17 of 37

Sea-Haven
Mentor
Mentor

Thanks to Kent making me aware of missing text using "F" option, use a 3 line fence as even at 2 lines would some times miss a text.

0 Likes
Message 18 of 37

radu_609
Participant
Participant

Is there any way to make this lisp to convert 3 TEXTs within a radius of 10 units to a MTEXT (right side of the image) with the insertion point where the top text is placed (Text1), please?

0 Likes
Message 19 of 37

Kent1Cooper
Consultant
Consultant

@radu_609 wrote:

.... convert 3 TEXTs within a radius of 10 units to a MTEXT ....


Define "within a radius."  Do I assume correctly that you mean within that kind of distance from each other, without an actual Circle drawn to find Text inside of?  If so, do you mean entirely within a virtual Circle like that [I'm having trouble thinking of how a routine could determine that], or with their insertion points all within no more than 20 units of each other regardless of the actual extent of the Text objects:

Kent1Cooper_0-1686922658815.png

or .... ?

 

And what do you have in mind for selection of them?  More than one such grouping User-selected collectively?  Routine finds them all without User input?  Only one such grouping, User-selected with the routine only checking whether they qualify as "close to each other"?

Kent Cooper, AIA
0 Likes
Message 20 of 37

radu_609
Participant
Participant

The circle was actually some sort of my idea of how to determine which texts to combine into a mtext. I attached another drawing with more texts for which I'd need such a lisp. I'm interested if I can select all the texts at once and then the lisp should try to determine which texts are close one to each other (like 10-20 units measured between their insertion points or something like that or if they are placed within that virtual circle) and then combine them into mtexts placed where those "Title" texts are. The texts should be sorted in mtexts as they are placed in the drawing like :

 

Title

Text1

Text2

 

0 Likes