;;; ---------------------------------------------------------------------
;;;  CHNMRK-bgol.lsp
;;;  Command:  CHM
;;;
;;;  PURPOSE
;;;  Marks regularly-spaced chainage cross-section lines along a selected
;;;  alignment polyline, labeling each with a formatted chainage value
;;;  (prefix + value + suffix). Cross-section geometry and chainage
;;;  labels are placed on separate layers for independent visibility
;;;  control.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   CHM   at the command line and press Enter.
;;;    3. Select the alignment polyline.
;;;    4. Answer the command-line prompts:
;;;         - Starting chainage
;;;         - Chainage increment
;;;         - Cross-section line length
;;;         - Prefix / Suffix text
;;;         - Precision (decimal places)
;;;    5. The routine walks the alignment at the given increment, drawing
;;;       a perpendicular cross-section line (layer "BGOL-CHM-CS") at
;;;       each chainage point, labeled with the formatted chainage value
;;;       (layer "BGOL-CHM-LBL").
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of dialog-driven chainage
;;;      marking utilities used in road/rail/channel alignment
;;;      drafting, but the code, command name and file name here are
;;;      new and are NOT copied from, nor identical to, any specific
;;;      third-party product. This version uses simple command-line
;;;      prompts instead of a compiled DCL dialog, so it works
;;;      immediately with no extra dialog file to distribute.
;;;
;;;  ---------------------------------------------------------------------
;;;  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:CHM-EnsureLayer (lname clr / )
  (if (not (tblsearch "LAYER" lname))
    (entmake (list '(0 . "LAYER")
                   '(100 . "AcDbSymbolTableRecord")
                   '(100 . "AcDbLayerTableRecord")
                   (cons 2 lname)
                   '(70 . 0)
                   (cons 62 clr)
                   '(6 . "Continuous")))
  )
)

(defun BGOL:CHM-DrawCSLine (pt dx dy halfLen lname / p1 p2)
  (setq p1 (list (- (car pt) (* dx halfLen)) (- (cadr pt) (* dy halfLen)) 0.0))
  (setq p2 (list (+ (car pt) (* dx halfLen)) (+ (cadr pt) (* dy halfLen)) 0.0))
  (entmake (list '(0 . "LINE")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbLine")
                  (cons 10 p1)
                  (cons 11 p2)
            )
  )
)

(defun BGOL:CHM-DrawLabel (pt txt lname / )
  (entmake (list '(0 . "TEXT")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbText")
                  (cons 10 pt)
                  (cons 40 2.0)
                  (cons 1 txt)
            )
  )
)

(defun C:CHM ( / ent obj totalLen startCh incr csLen prefix suffix prec
                 dist pt param deriv dx dy mag chval chstr n)
  (BGOL:CHM-EnsureLayer "BGOL-CHM-CS" 5)   ; blue cross-section lines
  (BGOL:CHM-EnsureLayer "BGOL-CHM-LBL" 2)  ; yellow chainage labels

  (setq ent (car (entsel "\nSelect alignment polyline: ")))
  (if ent
    (progn
      (setq obj (vlax-ename->vla-object ent))
      (setq totalLen (vlax-curve-getDistAtParam obj (vlax-curve-getEndParam obj)))
      (setq startCh (getreal "\nStarting chainage <0>: "))
      (if (null startCh) (setq startCh 0.0))
      (setq incr (getreal "\nChainage increment <30>: "))
      (if (null incr) (setq incr 30.0))
      (setq csLen (getreal "\nCross-section line length <20>: "))
      (if (null csLen) (setq csLen 20.0))
      (setq prefix (getstring "\nPrefix <Ch.>: "))
      (if (= prefix "") (setq prefix "Ch."))
      (setq suffix (getstring "\nSuffix <M>: "))
      (if (= suffix "") (setq suffix "M"))
      (setq prec (getint "\nPrecision <2>: "))
      (if (null prec) (setq prec 2))

      (setq n 0)
      (setq dist 0.0)
      (while (<= dist totalLen)
        (setq pt (vlax-curve-getPointAtDist obj dist))
        (setq param (vlax-curve-getParamAtPoint obj pt))
        (setq deriv (vlax-curve-getFirstDeriv obj param))
        ;; perpendicular direction = rotate tangent 90 degrees, normalized
        (setq dx (- (cadr deriv)))
        (setq dy (car deriv))
        (setq mag (sqrt (+ (* dx dx) (* dy dy))))
        (if (> mag 0.0)
          (progn
            (setq dx (/ dx mag))
            (setq dy (/ dy mag))
            (BGOL:CHM-DrawCSLine pt dx dy (/ csLen 2.0) "BGOL-CHM-CS")
            (setq chval (+ startCh dist))
            (setq chstr (strcat prefix " " (rtos chval 2 prec) " " suffix))
            (BGOL:CHM-DrawLabel (list (+ (car pt) (* dx (+ (/ csLen 2.0) 1.0)))
                                       (+ (cadr pt) (* dy (+ (/ csLen 2.0) 1.0)))
                                       0.0)
                                 chstr "BGOL-CHM-LBL")
            (setq n (1+ n))
          )
        )
        (setq dist (+ dist incr))
      )
      (princ (strcat "\nCHM: " (itoa n) " chainage point(s) marked along the alignment."))
    )
    (princ "\nNo entity selected.")
  )
  (princ)
)

(princ "\nCHNMRK-bgol.lsp loaded. Type CHM to mark chainages along an alignment.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
