LISP TO ALIGN TEXTS TO A POLYLINE

LISP TO ALIGN TEXTS TO A POLYLINE

MEAN28
Participant Participant
724 Views
6 Replies
Message 1 of 7

LISP TO ALIGN TEXTS TO A POLYLINE

MEAN28
Participant
Participant

Hello everyone,

I have a LISP (not created by me) related to this topic (there are several others), and I would like to add to it or optimize it.

I have a sample drawing here, and I would like the output to be more readable and to modify certain aspects of the output, similar to what is shown in the drawing.

Screenshot 2024-11-25 205657.pngScreenshot 2024-11-25 205727.pngScreenshot 2024-11-25 205734.png

 

What I would like to do is adjust the rotation of the text based on the length of its nearest line, ensure that it is readable, and move it perpendicularly to the polyline with a predefined length, which will be entered first.

 

Regarding the rotation of the text: when its nearest line is longer than the text, the text is rotated parallel to the line. If the nearest line is shorter than the text, then the text is rotated perpendicular to the line.

 

Thank you in advance, and I would greatly appreciate any help you can provide.

0 Likes
Accepted solutions (2)
725 Views
6 Replies
Replies (6)
Message 2 of 7

jayhar
Advisor
Advisor

The updated code fixes errors, improves text rotation based on line length, dynamically adjusts text offsets, handles TEXT and MTEXT better, and ensures safe undo operations. It’s more efficient and readable.

Please Subscribe YouTube Channel
https://www.youtube.com/channel/UCclj8v9vHQiFa8_DriuAk3w

Please Mark the Post or Posts as Solution(s) to help others find the answer quickly.
0 Likes
Message 3 of 7

MEAN28
Participant
Participant
Thank you for your response. I appreciate your help. However, I am still encountering the following error: "error: no function definition: ANGLE," and nothing seems to happen. Could you kindly advise me on what I might be missing?
0 Likes
Message 4 of 7

Sea-Haven
Mentor
Mentor

Using an in built function name as a variable can create problems, like "angle" this was mentioned a couple of days ago as a problem in code, angle & line was used as variable names. Personally I use "ang" for angles, same if you have a defun like this (defun angle..... you have redefined the inbuilt function. Try with ang and change line also to something else maybe lin, line 11 to remain as is. 

 

Not tested just trying to remove any possible gliches.

0 Likes
Message 5 of 7

Moshe-A
Mentor
Mentor
Accepted solution

@MEAN28  hi,

 

i saw this thread is still not close so i jumped in 😀

check this ATP2 command, support only text (not mtext)

 

enjoy

moshe

 

 

 

(vl-load-com) ; load activex support

(defun c:atp2 (/ text_boundary draw_boundary _midpt text_middle_point	; local functions
	         textbox_geo readable_angle exec_main 			; local functions
	         ss0 ss1 ss2 ename0 elist0 ;| local variables |;)

 (defun text_boundary (base dx0 dx1 dy0 dy1 ang)
  (mapcar
   (function
    (lambda (dx dy a0 a1)
     (polar (polar base a0 dx) a1 dy)
    )
   ); function
   (list dx0 dx1 dx1 dx0)
   (list dy0 dy0 dy1 dy1)
   (list (+ ang pi) ang ang (+ ang pi))
   (list (- ang (* pi 0.5)) (- ang (* pi 0.5)) (+ ang (* pi 0.5)) (+ ang (* pi 0.5)))
  ); mapcar
 ); text_boundary 

  
 (defun draw_boundary (base dx0 dx1 dy0 dy1 ang / pt lst)
  (setq lst (text_boundary base dx0 dx1 dy0 dy1 ang))
  (command "._pline" (car lst))
  (foreach pt (cdr lst)
   (command "none" pt)
  )
  (command "_close")
 ); draw_boundary

  
 ; anonymous function
 (setq _midpt (lambda (l) (mapcar '* (mapcar '+ (car l) (cadr l)) '(0.5 0.5 0.5))))

  
 (defun text_middle_point (base dx0 dx1 dy0 dy1 ang)
  (_midpt (mapcar
           (function
            (lambda (dx dy a0 a1)
             (polar (polar base a0 dx) a1 dy)
            )
           ); function
	   (list dx0 dx1) (list dy0 dy1) (list (+ ang pi) ang) (list (- ang (* pi 0.5)) (+ ang (* pi 0.5)))
          ); mapcar
  ); _midpt
 ); text_middle_point


 ; text box geometry
 (defun textbox_geo (ename norm base dx0 dx1 dy0 dy1 ang)
  (vl-sort
   (mapcar
    (function
     (lambda (t1)
      (setq t0 (vlax-curve-getClosestPointToProjection ename t1 norm))
      (list (distance t0 t1) t0 t1) 
     ); lambda
    ); function
    (text_boundary base dx0 dx1 dy0 dy1 ang)
   ); mapcar
   (function (lambda (e0 e1) (< (car e0) (car e1))))
  ); vl-sort
 ); textbox_geo

  
 (defun readable_angle (a0)
  (if (and (> a0 (* pi 0.5)) (< a0 (* pi 1.5)))
   (+ a0 pi)
   a0)
 ); readable_angle


 (defun exec_main (s1 s2 / normal ename1 ename2 elist2 p0 p1 p2 p3 p4 p5 hgt2 ang2 ang3 ang4
		           tb2 dx0 dx1 dy0 dy1 close_node prm v0 v1 geo^ bx AcDbText r0 r1)
   
  (setq ename1 (ssname s1 0) normal (cdr (assoc '210 (entget ename1))))
  (foreach ename2 (vl-remove-if 'listp (mapcar 'cadr (ssnamex s2)))
   (setq elist2 (entget ename2))
   (setq p0 (cdr (assoc '10 elist2)))
   (setq hgt2 (cdr (assoc '40 elist2)))
   (setq ang2 (cdr (assoc '50 elist2)))
   (setq tb2 (textbox elist2))
    
   (setq dx0 (caar  tb2) dx1 (caadr  tb2))
   (setq dy0 (cadar tb2) dy1 (cadadr tb2))
       
  ; (draw_boundary p0 dx0 dx1 dy0 dy1 ang2)
    
   (setq p1 (text_middle_point p0 dx0 dx1 dy0 dy1 ang2))
   (setq close_node (textbox_geo ename1 normal p0 dx0 dx1 dy0 dy1 ang2))
   (setq p2 (cadar close_node) p3 (caddar close_node))
   (setq ang3 (angle p2 p3))
       
   (setq prm (fix (vlax-curve-getParamAtPoint ename1 p2)))
   (setq v0 (vlax-curve-getPointAtParam ename1 prm))
   (setq v1 (vlax-curve-getPointAtParam ename1 (1+ prm)))
   (setq ang4 (angle v0 v1)) ; pline segment angle
   (setq p4 (_midpt (list v0 v1)))
       
   (setq geo^ (text_boundary p0 dx0 dx1 dy0 dy1 ang2))
   (setq bx (distance (car geo^) (cadr geo^)))
   (setq AcDbText (vlax-ename->vla-object ename2))

   (cond
    ((< bx (* (distance v0 v1) 0.9))
     (setq p5 (polar p4 ang3 hgt2))
     (setq r0 (vla-get-rotation AcDbText))
     (setq r1 (readable_angle ang4))
     (vla-rotate AcDbText (vlax-3d-point p1) (- r1 r0))
    ); case
    ( t
     (setq p5 (polar p4 ang3 (+ hgt2 (* bx 0.5))))
     (setq r0 (vla-get-rotation AcDbText))
     (setq r1 (readable_angle (+ ang4 (* pi 0.5))))
     (vla-rotate AcDbText (vlax-3d-point p1) (- r1 r0))
    ); case
   ); cond
    
   (vla-move AcDbText (vlax-3d-point p1) (vlax-3d-point p5))
   (vlax-release-object AcDbText)
  ); foreach
 ); exec_main

  
 ; here start (c:atp2)
 (setvar "cmdecho" 0)
 (command "._undo" "_begin")
 
 (if (setq ss0 (ssget '((0 . "polyline,lwpolyline,text"))))
  (progn
   ; process input
   (setq ss1 (ssadd) ss2 (ssadd))
   (foreach ename0 (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss0)))
    (setq elist0 (entget ename0))
    (cond
     ((wcmatch (cdr (assoc '0 elist0)) "POLYLINE,LWPOLYLINE")
      (ssadd ename0 ss1)
     ); case
     ( t
      (ssadd ename0 ss2)
     ); case
    ); cond
   ); foreach

   (cond
    ((= (sslength ss1) 0)
     (vlr-beep-reaction)
     (prompt "\nno polyline is selected.")
    ); case
    ((> (sslength ss1) 1)
     (vlr-beep-reaction)
     (prompt "\ntoo many polylines selected.")
    ); case
    ((= (sslength ss2) 0)
     (vlr-beep-reaction)
     (prompt "\nno text(s) selected.")
    ); case
    ( t
     (exec_main ss1 ss2)
    ); case
   ); cond
  
  ); progn
 ); if

 (command "._undo" "_end")
 (setvar "cmdecho" 1)
 
 (princ)
); c:atp2

 

0 Likes
Message 6 of 7

MEAN28
Participant
Participant

@Moshe-A , this works perfectly. 😊 Thank you so much for your help!

0 Likes
Message 7 of 7

Moshe-A
Mentor
Mentor
Accepted solution

@MEAN28 ,

 

thanks you for that 😀

 

i added  support to mtext (for mtext the attachment point is top left)

 

i notice an issue you have to be aware of:

on text being longer than the segment where the result should be vertical to the segment, if the text is laid aligned (at the same angle) the segment, it won't identify as close to this segment but to the next (or before) segment that is because my program gets the boundary of the text and throw a perpendicular from each node to the polyline and the shorted wins (identify the segment) i could take the middle point but it won't be fit for other cases. so to overcome this, make sure the text has a different angle (not aligned) from it's close segment.

 

Moshe

 

 

0 Likes