;;; ---------------------------------------------------------------------
;;;  ALTX-bgol.lsp
;;;  Command:  ATXP
;;;
;;;  PURPOSE
;;;  Aligns a selection of TEXT entities so each one is rotated to match
;;;  the local tangent direction of the nearest LINE/LWPOLYLINE found in
;;;  the drawing. Useful for cleaning up scattered-angle labels (house
;;;  numbers, elevation callouts, chainage values, etc.) so they read
;;;  along the curve or alignment they sit next to.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   ATXP   at the command line and press Enter.
;;;    3. Select the TEXT entities to realign, press Enter to finish.
;;;    4. Select one or more LINE/LWPOLYLINE entities to use as the
;;;       reference alignment geometry, press Enter to finish.
;;;    5. Each selected text is rotated in place to match the tangent
;;;       angle of its nearest point on the nearest reference line.
;;;       A copy marker is placed on layer "BGOL-ATXP" at each text's
;;;       original insertion point so the previous position/angle can
;;;       be reviewed.
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of "align text parallel to
;;;      nearest line" utilities common in survey/CAD drafting workflows,
;;;      but the code, command name and file name here are new and are
;;;      NOT copied from, nor identical to, any specific third-party
;;;      product.
;;;
;;;  ---------------------------------------------------------------------
;;;  Developed and shared for the CAD community by:  BGol Community
;;;  Community website:                              https://bgol.in/
;;;  License:  Open-source & free to use, modify, and share for all.
;;;            Provided "as is", without warranty of any kind.
;;;  ---------------------------------------------------------------------

(vl-load-com)

(defun BGOL:ATXP-EnsureLayer (lname / )
  (if (not (tblsearch "LAYER" lname))
    (entmake (list '(0 . "LAYER")
                   '(100 . "AcDbSymbolTableRecord")
                   '(100 . "AcDbLayerTableRecord")
                   (cons 2 lname)
                   '(70 . 0)
                   '(62 . 5)          ; blue
                   '(6 . "Continuous")))
  )
)

(defun BGOL:ATXP-MarkOrigin (pt lname / )
  (entmake (list '(0 . "POINT")
                 (cons 8 lname)
                 (cons 10 pt)))
)

(defun BGOL:ATXP-NearestLineData (pt lineobjs / bestobj bestdist bestpt lo cpt d)
  (setq bestobj nil bestdist nil bestpt nil)
  (foreach lo lineobjs
    (setq cpt (vlax-curve-getClosestPointTo lo pt))
    (if cpt
      (progn
        (setq d (distance pt cpt))
        (if (or (null bestdist) (< d bestdist))
          (setq bestdist d bestobj lo bestpt cpt)
        )
      )
    )
  )
  (if bestobj (list bestobj bestpt) nil)
)

(defun C:ATXP ( / txSS lnSS n ent obj txpt lineobjs nearest lo cpt param
                  deriv ang i edata)
  (BGOL:ATXP-EnsureLayer "BGOL-ATXP")
  (princ "\nSelect TEXT entities to align: ")
  (setq txSS (ssget '((0 . "TEXT"))))
  (if txSS
    (progn
      (princ "\nSelect reference LINE/LWPOLYLINE entities: ")
      (setq lnSS (ssget '((0 . "LINE,LWPOLYLINE"))))
      (if lnSS
        (progn
          (setq lineobjs '())
          (setq i 0)
          (repeat (sslength lnSS)
            (setq lineobjs (cons (vlax-ename->vla-object (ssname lnSS i)) lineobjs))
            (setq i (1+ i))
          )
          (setq n 0)
          (setq i 0)
          (repeat (sslength txSS)
            (setq ent (ssname txSS i))
            (setq edata (entget ent))
            (setq obj (vlax-ename->vla-object ent))
            (setq txpt (vlax-get obj 'InsertionPoint))
            (BGOL:ATXP-MarkOrigin txpt "BGOL-ATXP")
            (setq nearest (BGOL:ATXP-NearestLineData txpt lineobjs))
            (if nearest
              (progn
                (setq lo (car nearest))
                (setq cpt (cadr nearest))
                (setq param (vlax-curve-getParamAtPoint lo cpt))
                (setq deriv (vlax-curve-getFirstDeriv lo param))
                (setq ang (angle '(0.0 0.0) deriv))
                (vlax-put obj 'Rotation ang)
                (setq n (1+ n))
              )
            )
            (setq i (1+ i))
          )
          (princ (strcat "\nATXP: " (itoa n) " text entit"
                         (if (= n 1) "y" "ies") " aligned to nearest line."))
        )
        (princ "\nNo reference line selected. Nothing aligned.")
      )
    )
    (princ "\nNo text selected.")
  )
  (princ)
)

(princ "\nALTX-bgol.lsp loaded. Type ATXP to align text parallel to the nearest line.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
