;;; ---------------------------------------------------------------------
;;;  ALNCUT-bgol.lsp
;;;  Command:  ACUT
;;;
;;;  PURPOSE
;;;  Marks chainage points along a selected alignment polyline at a
;;;  fixed interval AND physically splits (breaks) the alignment into
;;;  separate polyline pieces at each of those chainage points, so
;;;  every resulting segment can be selected, plotted, or processed
;;;  independently.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   ACUT   at the command line and press Enter.
;;;    3. Select the alignment polyline to mark and cut.
;;;    4. Enter the chainage interval when prompted.
;;;    5. The routine walks the alignment at that interval, drops a
;;;       chainage label at each point (layer "BGOL-ACUT-CH"), and
;;;       breaks the polyline into separate pieces between consecutive
;;;       chainage points (layer "BGOL-ACUT-PIECE").
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of alignment-splitting
;;;      utilities that combine chainage marking with physical polyline
;;;      segmentation, common in road/rail/channel alignment 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:ACUT-EnsureLayer (lname colr / )
  (if (not (tblsearch "LAYER" lname))
    (entmake (list '(0 . "LAYER")
                   '(100 . "AcDbSymbolTableRecord")
                   '(100 . "AcDbLayerTableRecord")
                   (cons 2 lname)
                   '(70 . 0)
                   (cons 62 colr)
                   '(6 . "Continuous")))
  )
)

(defun BGOL:ACUT-MakeText (pt ht str lname / )
  (entmake (list '(0 . "TEXT")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbText")
                  (cons 10 pt)
                  (cons 40 ht)
                  (cons 1 str)
                  (cons 50 0.0)))
)

(defun BGOL:ACUT-MakePolyline (pointlist lname / dxfdata pt)
  (setq dxfdata (list '(0 . "LWPOLYLINE")
                       '(100 . "AcDbEntity")
                       (cons 8 lname)
                       '(100 . "AcDbPolyline")
                       (cons 90 (length pointlist))
                       '(70 . 0))
  )
  (foreach pt pointlist
    (setq dxfdata (append dxfdata (list (cons 10 pt))))
  )
  (entmake dxfdata)
)

(defun C:ACUT ( / ent obj chLayer pcLayer interval totalLen nSeg i
                  d1 d2 pt1 pt2 chStr subPts nSub j subD subPt)
  (setq chLayer "BGOL-ACUT-CH")
  (setq pcLayer "BGOL-ACUT-PIECE")
  (BGOL:ACUT-EnsureLayer chLayer 2)   ; yellow labels
  (BGOL:ACUT-EnsureLayer pcLayer 6)   ; magenta pieces

  (setq ent (car (entsel "\nSelect alignment polyline to cut: ")))
  (if (and ent (= (cdr (assoc 0 (entget ent))) "LWPOLYLINE"))
    (progn
      (setq obj (vlax-ename->vla-object ent))
      (setq interval (getreal "\nEnter chainage interval: "))
      (if (or (null interval) (<= interval 0)) (setq interval 30.0))

      (setq totalLen (vlax-curve-getDistAtParam obj (vlax-curve-getEndParam obj)))
      (setq nSeg (fix (/ totalLen interval)))

      ;; place chainage labels at each interval point
      (setq i 0)
      (while (<= i nSeg)
        (setq d1 (min totalLen (* i interval)))
        (setq pt1 (vlax-curve-getPointAtDist obj d1))
        (setq chStr (rtos d1 2 2))
        (BGOL:ACUT-MakeText (list (car pt1) (+ (cadr pt1) 1.0) 0.0) 0.9
                             (strcat "Ch. " chStr) chLayer)
        (setq i (1+ i))
      )

      ;; build a separate polyline "piece" between each consecutive chainage pair
      (setq i 0)
      (while (< i nSeg)
        (setq d1 (* i interval))
        (setq d2 (min totalLen (* (1+ i) interval)))
        (setq subPts '())
        (setq nSub 10)
        (setq j 0)
        (while (<= j nSub)
          (setq subD (+ d1 (* (- d2 d1) (/ (float j) nSub))))
          (setq subPt (vlax-curve-getPointAtDist obj subD))
          (setq subPts (append subPts (list subPt)))
          (setq j (1+ j))
        )
        (BGOL:ACUT-MakePolyline subPts pcLayer)
        (setq i (1+ i))
      )

      (princ (strcat "\nAlignment marked at " (itoa (1+ nSeg)) " chainage point(s) ("
                      chLayer ") and cut into " (itoa nSeg) " piece(s) (" pcLayer ")."))
    )
    (princ "\nNo LWPOLYLINE alignment selected. Nothing processed.")
  )
  (princ)
)

(princ "\nALNCUT-bgol.lsp loaded. Type ACUT to mark chainages and cut an alignment into pieces.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
