;;; ---------------------------------------------------------------------
;;;  BLKALN-bgol.lsp
;;;  Command:  BALN
;;;
;;;  PURPOSE
;;;  Places a numbered point marker (attribute-style block, simulated
;;;  here with an ENTMAKE INSERT + free-standing text attributes since
;;;  no external block definition is assumed) at a picked point on or
;;;  near a selected alignment polyline. Each marker automatically
;;;  records the point's Easting, Northing and Chainage (distance along
;;;  the alignment measured from its start), which is exactly the kind
;;;  of structured data infrastructure projects need for valve, manhole
;;;  or fitting schedules.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   BALN   at the command line and press Enter.
;;;    3. Select the alignment polyline.
;;;    4. Pick (or near-pick) the point along/near the alignment where
;;;       the marker belongs.
;;;    5. Enter the marker/block number when prompted.
;;;    6. A numbered marker (circle + number/Chainage/Easting/Northing
;;;       text) is created on layer "BGOL-BALN" at the nearest point on
;;;       the alignment to the pick.
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of attributed point-marker
;;;      routines used to place numbered features (valves, manholes,
;;;      fittings) along an alignment, common in survey/infrastructure
;;;      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:BALN-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:BALN-MakeCircle (cen rad lname / )
  (entmake (list '(0 . "CIRCLE")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbCircle")
                  (cons 10 cen)
                  (cons 40 rad)))
)

(defun BGOL:BALN-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 C:BALN ( / ent obj pick nearPt param dist
                   blkNum easting northing chStr
                   lname txtht circR mkrPt lblPt1 lblPt2 lblPt3)
  (setq lname "BGOL-BALN")
  (BGOL:BALN-EnsureLayer lname)
  (setq ent (car (entsel "\nSelect alignment polyline: ")))
  (if (and ent (wcmatch (cdr (assoc 0 (entget ent))) "LWPOLYLINE,POLYLINE"))
    (progn
      (setq obj (vlax-ename->vla-object ent))
      (setq pick (getpoint "\nPick point on/near alignment for marker: "))
      (if pick
        (progn
          (setq param  (vlax-curve-getParamAtPoint obj (vlax-curve-getClosestPointTo obj pick)))
          (setq nearPt (vlax-curve-getPointAtParam obj param))
          (setq dist   (vlax-curve-getDistAtParam obj param))
          (setq blkNum (getstring T "\nEnter marker/block number: "))
          (if (= blkNum "") (setq blkNum "1"))
          (setq easting  (rtos (car nearPt) 2 3))
          (setq northing (rtos (cadr nearPt) 2 3))
          (setq chStr    (rtos dist 2 3))

          (setq circR  1.2)
          (setq txtht  0.9)
          (setq mkrPt  nearPt)
          (setq lblPt1 (list (+ (car mkrPt) (* circR 1.6)) (+ (cadr mkrPt) (* txtht 1.6)) 0.0))
          (setq lblPt2 (list (+ (car mkrPt) (* circR 1.6)) (cadr mkrPt) 0.0))
          (setq lblPt3 (list (+ (car mkrPt) (* circR 1.6)) (- (cadr mkrPt) (* txtht 1.6)) 0.0))

          (BGOL:BALN-MakeCircle mkrPt circR lname)
          (BGOL:BALN-MakeText lblPt1 txtht (strcat "No: " blkNum) lname)
          (BGOL:BALN-MakeText lblPt2 txtht (strcat "Ch: " chStr) lname)
          (BGOL:BALN-MakeText lblPt3 txtht (strcat "E:" easting " N:" northing) lname)

          (princ (strcat "\nMarker No." blkNum " placed at Chainage " chStr
                          " on layer " lname "."))
        )
        (princ "\nNo point picked.")
      )
    )
    (princ "\nNo alignment polyline selected. Nothing created.")
  )
  (princ)
)

(princ "\nBLKALN-bgol.lsp loaded. Type BALN to place a numbered marker block along an alignment.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
