Lisp to Mirror the Location of TEXT or MTEXT objects across Polyline

Lisp to Mirror the Location of TEXT or MTEXT objects across Polyline

Yasir.Aman
Advocate Advocate
2,227 Views
17 Replies
Message 1 of 18

Lisp to Mirror the Location of TEXT or MTEXT objects across Polyline

Yasir.Aman
Advocate
Advocate

Respected Members,

 

Can anybody guide me to a LISP capable of flipping/mirroring the positions of TEXT/MTEXT objects across a polyline object. The polyline may have multiple segments/vertices and can be either closed or open in various scenarios.

See the following screenshot to demonstrate the outcome. A .dwg file is also attached for reference.

 

Mirror-Text-Demo.png

 

Thank you!

0 Likes
Accepted solutions (4)
2,228 Views
17 Replies
Replies (17)
Message 2 of 18

ВeekeeCZ
Consultant
Consultant
Accepted solution

Any objects along any geometrical object.

 

(vl-load-com)

(defun c:MirrorAlong ( / s l m i e d y p a)
  
  (if (and (setq s (ssget "_:L"))
	   (setq l (car (entsel "\nSelect polyline: ")))
	   (not (initget "Yes No"))
	   (setq m (cond ((getkword "\nErase source objects? [Yes/No] : ")) ("No")))
	   )
    (repeat (setq i (sslength s))
      (and (setq e (ssname s (setq i (1- i)))
		 d (entget e)
		 y (cdr (assoc 0 d))
		 p (cond ((wcmatch y "INSERT,MTEXT,CIRCLE,POINT")
			  (cdr (assoc 10 d)))
			 ((= y "TEXT")
			  (cdr (assoc (if (= 0 (cdr (assoc 72 d)) (cdr (assoc 73 d))) 10 11) d)))
			 ((not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list o 'll 'ur))))
			  (mapcar '/ (apply 'mapcar (cons '+ (mapcar 'vlax-safearray->list (list ll ur)))) '(2 2)))))
	   (not (vl-catch-all-error-p (setq p (vl-catch-all-apply 'vlax-curve-getclosestpointto (list l p)))))
	   (setq a (vlax-curve-getfirstderiv l (vlax-curve-getparamatpoint l p)))
	   (setq a (angle '(0 0 0) a))
	   (vl-cmdf "_.mirror" e "" "_non" (trans p 0 1) "_non" (trans (polar p a 1.) 0 1) (strcat "_" m)))))
  (princ)
  )

 

Message 3 of 18

hak_vz
Advisor
Advisor

@ВeekeeCZ  has made it the way it should be, here is my code created in less than a minute for sequential mirroring with deletion of original text objects

(defun c:mirrortext ( / *error* ss)
	(defun *error* (msg)
		(if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*"))
			(princ (strcat "\nOops an Error : ( " msg " ) occurred."))
		)
		(setvar 'cmdecho 1)
		(princ)
	)
	(setvar 'cmdecho 0)
	(princ "\nSelect text to mirror >")
	(while (setq ss (ssget '((0 . "*TEXT"))))
		(command "_.mirror" ss "" (getpoint "\nFirst mirror point >")(getpoint "\nSecond mirror point >") "y")
	)
	(setvar 'cmdecho 1)
	(princ)
)

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 4 of 18

Kent1Cooper
Consultant
Consultant
Accepted solution

My routine to do that kind of thing [with any kind(s) of objects across any kind of path] is MirrorAcrossObject.lsp with its MAO command, >here<.

Kent Cooper, AIA
Message 5 of 18

Yasir.Aman
Advocate
Advocate

@ВeekeeCZ 

I appreciate it immensely. It fulfills my requirements perfectly, and its flawless execution brought tears of joy to my eyes.

Thanks once more for your time and help.

Stay blessed!

0 Likes
Message 6 of 18

kajanthangavel
Advocate
Advocate
Accepted solution

Try this,

mirror txt.gif

 

 

(defun c:mirror-text (/ ss e eo ent dxf_ent  di var_cmdecho var_osmode)
    (defun *error* ( msg )
        (LM:endundo (LM:acdoc))
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
        (princ)
    )

  (LM:startundo (LM:acdoc))
  (setq var_cmdecho (getvar "cmdecho"))
  (setq var_osmode (getvar "osmode"))
  (setvar 'cmdecho 0)
  (setvar 'osmode 0)



(setq ss (ssget ":L" (list '(0 . "TEXT,MTEXT")   )))
(setq e (car (entsel "\nSelect polyline : ")))
(setq eo (vlax-ename->vla-object e))
	(if ss	(repeat 
				(setq n (sslength ss))
				(setq
					ent (ssname ss (setq n (1- n)))
					dxf_ent (entget ent)
				)
				(vla-getboundingbox (vlax-ename->vla-object ent) 'mn 'mx)
				(setq llpt (vlax-safearray->list mn))
				(setq urpt (vlax-safearray->list mx))
				(setq midpt (mapcar '(lambda (x y) (/ (+ x y) 2)) llpt urpt))
				(setq di (distance (setq pt (vlax-curve-getclosestpointto eo midpt)) midpt))
				(command "_.move" ent ""   midpt (polar midpt (angle midpt pt)  (* di 2) ))
			)
			)
			(LM:endundo (LM:acdoc))
    (setvar 'cmdecho var_cmdecho)
    (setvar 'osmode var_osmode)
(princ)
);defun


;; Start Undo  -  Lee Mac
;; Opens an Undo Group.

(defun LM:startundo ( doc )
    (LM:endundo doc)
    (vla-startundomark doc)
)

;; End Undo  -  Lee Mac
;; Closes an Undo Group.

(defun LM:endundo ( doc )
    (while (= 8 (logand 8 (getvar 'undoctl)))
        (vla-endundomark doc)
    )
)

;; Active Document  -  Lee Mac
;; Returns the VLA Active Document Object

(defun LM:acdoc nil
    (eval (list 'defun 'LM:acdoc 'nil (vla-get-activedocument (vlax-get-acad-object))))
    (LM:acdoc)
)

(princ "\nmirror-text" )
(princ)

 

 

Message 7 of 18

Yasir.Aman
Advocate
Advocate

@hak_vz  I highly appreciate your effort immensely but unfortunately this is not what I need. This is essentially just another replication of AutoCAD's mirror command.

In any case, I thank you for considering my post.

0 Likes
Message 8 of 18

Yasir.Aman
Advocate
Advocate

@Kent1Cooper  Thank you Sir. Your routine also works perfectly. I am so happy to see more than one solutions to a problem. This also offers me a chance to study the code and understand the different approaches that can be made to solve a problem.

Once again thank you!

0 Likes
Message 9 of 18

komondormrex
Mentor
Mentor
Accepted solution

hey there,

another one changing text justifying in case of  manual changing text data.

 

(defun c:mirror_m_text_along_pline (/ m_text_pline_sset m_text_pline_list pline mirr_1st_point text_mirrored)
	(if (setq m_text_pline_sset (ssget '((0 . "text,mtext,lwpolyline"))))
		(progn
			(setvar 'cmdecho 0)
			(if (vl-some '(lambda (ename) (= "LWPOLYLINE" (cdr (assoc 0 (entget (setq pline ename))))))
						  		  (setq m_text_pline_list (vl-remove-if 'listp (mapcar 'cadr (ssnamex m_text_pline_sset))))
				)
					(setq m_text_pline_list (vl-remove pline m_text_pline_list))
					(setq pline (car (entsel "\Pick mirroring pline: ")))
			)
			(foreach text m_text_pline_list
					(cond
						(
							 (= "TEXT" (cdr (assoc 0 (entget text))))
								(setq  mirr_1st_point (if (equal '(0 0 0) (vlax-get (vlax-ename->vla-object text) 'textalignmentpoint))
															(vlax-curve-getclosestpointto pline (vlax-get (vlax-ename->vla-object text) 'insertionpoint))
															(vlax-curve-getclosestpointto pline (vlax-get (vlax-ename->vla-object text) 'textalignmentpoint))
													  )
									   text_mirrored (vla-mirror (vlax-ename->vla-object text)
																 (vlax-3d-point mirr_1st_point)
																 (vlax-3d-point (polar mirr_1st_point (+ (* 0.5 pi) (vla-get-rotation (vlax-ename->vla-object text))) 0.1))
													 )
								)
								(cond
									(
										(= 0 (vla-get-alignment (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_r")
									)
									(
										(= 2 (vla-get-alignment (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_l")
									)
									(
										(= 8 (vla-get-alignment (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_tl")
									)
									(
										(= 6 (vla-get-alignment (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_tr")
									)

									(
										t
									)
								)
						)
						(
							t
								(setq  mirr_1st_point (vlax-curve-getclosestpointto pline (vlax-get (vlax-ename->vla-object text) 'insertionpoint))
									   text_mirrored (vla-mirror (vlax-ename->vla-object text)
																 (vlax-3d-point mirr_1st_point)
																 (vlax-3d-point (polar mirr_1st_point (+ (* 0.5 pi) (vla-get-rotation (vlax-ename->vla-object text))) 0.1))
													 )
								)
								(cond
									(
										(= 0 (vla-get-attachmentpoint (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_tr")
									)
									(
										(= 2 (vla-get-attachmentpoint (vlax-ename->vla-object text)))
											(command "_justifytext" (vlax-vla-object->ename text_mirrored) "" "_tl")
									)
									(
										t
									)
								)
						)
					)
					(entdel text)
			)
			(setvar 'cmdecho 1)
		)
	)
	(princ)
)

 

 

Message 10 of 18

Yasir.Aman
Advocate
Advocate

@kajanthangavel

Wow, I'm truly awestruck. While I've always held high regard for the selflessness of this community's members, today you all have surpassed my expectations. Expressing enough gratitude feels impossible.

Thank you. Thank you. Thank you.

0 Likes
Message 11 of 18

Yasir.Aman
Advocate
Advocate

@komondormrex 

Although codes provided by all honorable members work perfectly, your code outperforms when I use it on the same objects to mirror them back to their original side. They almost exactly go back to their original location.

Hats off Sir!

Thank you.

Message 12 of 18

komondormrex
Mentor
Mentor

that is the target!

Message 13 of 18

hak_vz
Advisor
Advisor

@Yasir.Aman wrote:

@hak_vz  I highly appreciate your effort immensely but unfortunately this is not what I need. This is essentially just another replication of AutoCAD's mirror command.

In any case, I thank you for considering my post.


At the time I wanted to paste my solution @ВeekeeCZ has already done it. My code was in general totally similar with his solution so I restrained from doing it. Since one of the goals of this forum is no to continuously provide code solutions but to teach autolisp beginners to start programming I posted this simple solution to show novice learners how they can simply make their code execution faster.

 

Now, question to other code providers to this post.

 

@ВeekeeCZ  and @kajanthangavel  In your code you are extracting text bounding box.  To mirror text object is this really necessary?

In @Yasir.Aman demo we have text with different justification, but all of them mirror correctly.

Catch is in system variable MIRRTEXT that controls how MIRROR reflects text ( 0 - Retains text direction 1 - Mirrors the text). Instead of search for vlax-curve-getclosestpointto finding appropriate polyline segment is all what is needed.

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 14 of 18

Yasir.Aman
Advocate
Advocate

I wholeheartedly agree, Sir. Teaching someone to catch fish is indeed more valuable than merely providing them with a fish. However, there are occasions when someone may be in such dire need that initially being given a fish becomes a vital step. Once they've regained their strength, they can then embark on learning the art of fishing😉

Anyway, thank you once again.

0 Likes
Message 15 of 18

Kent1Cooper
Consultant
Consultant

@hak_vz wrote:
....

@ВeekeeCZ  and @kajanthangavel  In your code you are extracting text bounding box.  To mirror text object is this really necessary?

..... Instead of search for vlax-curve-getclosestpointto finding appropriate polyline segment is all what is needed.


Mine also uses the bounding box, and finds the closest point to the middle of that on the Mirror path object.  The "appropriate polyline segment" may serve well enough for the Mirror axis when the path is a Polyline made of only line segments, but mine works with Polylines including arc segments and all other kinds of path objects with linearity [(vlax-curve-...)-class objects].

 

EDIT -- Further elaboration on the difference it makes:

If "finding appropriate polyline segment" means you would use the endpoints of that nearest segment for the Mirror axis, then if that segment is a line segment, it doesn't matter, but if it's an arc segment, here's the difference:

Kent1Cooper_0-1702997123427.png

The white "test" Texts are the originals, and the yellow Polyline is the Mirroring path.  The red ones are the result of using the endpoints of the nearest segment [the magenta Points] as the Mirror axis.  The green ones are the result of using the direction of the path at its closest point to the midpoint of the object's bounding box [here done with my MAO command, but I assume similar results from other routines that take a similar approach].

 

And if "finding appropriate polyline segment" involves finding the place on the path that is closest to the object, then if it's not using the middle of its bounding box, presumably for Text it would have to use the insertion point.  The results from that will vary depending on the justification of the Text, even when using the local direction of the path for the Mirror axis, not just the segment endpoints.  Here, the Text is left-justified.  Again, if the closest point is on a line segment, it doesn't matter, but with an arc segment, here's the difference:

Kent1Cooper_1-1702997710680.png

The magenta Point is the closest point on the path to the Text's insertion point.  Using the direction of the path at that point for the Mirror axis, the result is the red one.  Using the closest point to the Text's bounding-box midpoint gives the green result [again, here done with MAO].

 

If the Text were Middle or Middle-Center or Middle-Left of Middle-right justified, and if its rotation were always perpendicular to the path as in these examples, it wouldn't matter [or not much -- there could be slight differences depending on which of those justifications and the specifics of the text content].  Likewise if it were Center or Bottom-Center or Middle-Center or Top-Center justified and its rotation were parallel to the path.  But other justifications and/or rotations will have similar differences in results.

 

The effects are similar with path objects such as Ellipses, Splines, Arcs, and Circles.  It wouldn't make a difference when the path is a Line or Ray or Xline, nor a Polyline line segment except for situations where a Text object is close to a bend in the Polyline, where again the justification could make a difference, because the nearest point on the Polyline to the insertion point could be on a different segment than the nearest point to the bounding-box midpoint.

Kent Cooper, AIA
Message 16 of 18

hak_vz
Advisor
Advisor

@Kent1Cooper  You really take time for detailed explanation. I'm fully aware of it, but in case of OP request where he uses straight segments (a little bit overcrowded what I noticed to late) I thought simple  mirror flip over a polygon segment will do the trick. >The other case to consider are when using nearest point algorithm are sharp edges, where depending on text position regarding to flipping polyline, may also produce undesired result.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 17 of 18

Yasir.Aman
Advocate
Advocate

Thank you, sir, for this detailed explanation. For people like me this is a great help.

0 Likes
Message 18 of 18

Yasir.Aman
Advocate
Advocate

You're absolutely correct. The example file I shared includes polylines with straight segments, even though they're a bit crowded, as you pointed out. These segments get automatically generated by third-party software, and users don't really have control over how they end up, apart from choosing the color.

My intention was to keep the request broad so that the solution could help others facing similar issues, not just my specific problem. That's why you might have noticed I included various "maybe this/maybe that" scenarios in my request. I did miss mentioning polylines with arc segments and other possibilities like splines, but the senior members exceeded my expectations by providing a solution that's as perfect as possible.

I appreciate your valuable contribution. Thanks a lot!

0 Likes