;;; ===========================================================================
;;; Command: LText
;;; Description: Labels a selected line with its angle (DMS) and length (meters).
;;; Licence: GNU General Public License v3.0 (GPLv3)
;;;          Copyright (c) 2026 Muneeb Abid. All rights reserved.
;;;          Contact via provided email for commercial license 
;;;          or a workflow automation custom to your needs.
;;; Author: Muneeb Abid
;;; Contact: madcad@muneeb.au
;;; Version: v0.01
;;; Date: 2026-05-07
;;; ===========================================================================

;|
  Splits a string into a list using a specified delimiter.
  @Param  str - [str] The string to be partitioned
  @Param  delim - [str] The delimiter used for splitting
  @Returns A list of substrings
|;
(defun MNB:splitstr ( str delim / pos )
  (if (setq pos (vl-string-search delim str))
    (cons (substr str 1 pos) 
    (MNB:splitstr (substr str (+ pos 1 (strlen delim))) delim))
    (list str)
  )
)

;|
  Pad '0' to its left of 'val' till it has 'len' characters
  @Param val string to be padded
  @Param len minimum length to achieve
  @Returns padded string
|;
(defun pad-zeros (val len / str)
  (setq str (itoa val))
  (while (< (strlen str) len)
    (setq str (strcat "0" str))
  )
  str
)


;|
  Creates a toriented MTEXT annotation for a selected LINE.
  Text Content = 'Bearing(dms)  Distance(m)'
  >>
      1. Command 'LTEXT'
      2. Select LINE entity
      3. Bing bang boom you're done
      4. Profit??!
  @Param pick selected entity reference. should be a line.
  @Returns MTEXT entity aligned to line
|;
(defun c:LText (/ pick ent data p1 p2 dist ang mid)
  (setq pick (entsel "\nSelect line: "))
  (if (and pick (= (cdr (assoc 0 (setq data (entget (car pick))))) "LINE"))
    (progn
      (setq p1 (cdr (assoc 10 data))
            p2 (cdr (assoc 11 data))
            dist (distance p1 p2)
            ang (angle p1 p2)
            mid (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2))

      
      ;; Flip angle if text would be upside down
      (if (and (> ang (/ pi 2)) (<= ang (* pi 1.5)))
        (setq tori_ang (+ ang pi))
        (setq tori_ang ang)
      )

      ; (setq ang tori_ang)
      
      ;;; Calculate perpendicular angle (90 degrees up)
      (setq perp_ang (+ tori_ang (/ pi 2.0)))
      
      ;;; Create a new point 2 units away from the midpoint
      (setq offset_pt (polar mid perp_ang 2))

      (princ (strcat "ang:" (angtos ang)))
      (princ (strcat "tori_ang:" (angtos tori_ang)))
      ; (princ (strcat  "deg_ang:" (rtos deg_ang 2))) ;(rtos [number] [mode] [precision])
      
      (setq ang_str (angtos ang 1 4))
      (princ (strcat "ang_str:" ang_str))
      
      
      (setq splitto (MNB:splitstr ang_str "d"))
      (setq deg_only (nth 0 splitto))
      (princ (strcat "deg_only:" deg_only))
      
      (setq splitto (MNB:splitstr (nth 1 splitto) "'"))      
      (setq min_only (nth 0 splitto))
      
      (setq min_only (pad-zeros (atoi min_only) 2))
      (princ (strcat "min_only:" min_only))
      
      (setq splitto (nth 1 splitto))      
      (princ (strcat "splitto" splitto))
      (substr splitto 1 (1- (strlen splitto)))      ;remove the " char
      
      
      (setq sec_only (rtos (atof splitto) 2 0))
      (setq sec_only (pad-zeros (atoi sec_only) 2))
      
      
      (setq isMilli (MNB:splitstr splitto "."))
      (if (> (length isMilli) 1)
        (
         (setq splitto (rtos (atof splitto) 2 2))
         (setq sec_only (strcat sec_only "." (nth 1 (MNB:splitstr splitto "."))))
        )
      )
      
      (princ (strcat "sec_only:" sec_only))
      
      (setq str_ang (strcat deg_only "%%d" min_only "'" sec_only "\""))
      (setq str_len (rtos dist 2 3)) ; The distance string 
      
      (entmake
        (list
          '(0 . "TEXT")
          (cons 10 mid)           ; Insertion point
          (cons 40 2.5)           ; Text Height (Change 2 to your preference)
          (cons 1 (strcat str_ang "  " str_len)); The distance string 
          (cons 50 tori_ang)           ; Rotation in Radians
          '(72 . 1)               ; Horizontal alignment: Centered
          '(73 . 2)               ; Vertical alignment: Middle
          (cons 11 offset_pt)           ; Alignment point (required for centering)
        )
      )
    )
    (princ "\nNo line selected.")
  )
  (princ)
)
;rtos [number] [mode] [precision]
