;;; ---------------------------------------------------------------------
;;;  APXMRK-bgol.lsp
;;;  Command:  APX
;;;
;;;  PURPOSE
;;;  Marks every internal vertex (apex / Point of Intersection) of one
;;;  or more selected alignment polylines, while visually distinguishing
;;;  the polyline's start and end points from the internal apex points.
;;;
;;;  USAGE
;;;    1. Load this file (APPLOAD or drag-drop onto the drawing window).
;;;    2. Type   APX   at the command line and press Enter.
;;;    3. Select one or more alignment polylines.
;;;    4. Every internal vertex is marked with a triangle (apex marker,
;;;       layer "BGOL-APX"); the first and last vertices of each
;;;       polyline are marked with a square (layer "BGOL-APX-END").
;;;
;;;  NOTES
;;;    - This is an original, independently written implementation.
;;;      It is INSPIRED by the general idea of apex/PI marking utilities
;;;      used in alignment design documentation, 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:APX-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")))
  )
)

;; small triangle marker centered at pt
(defun BGOL:APX-DrawTriangle (pt size lname / p1 p2 p3)
  (setq p1 (list (car pt) (+ (cadr pt) size) 0.0))
  (setq p2 (list (- (car pt) size) (- (cadr pt) size) 0.0))
  (setq p3 (list (+ (car pt) size) (- (cadr pt) size) 0.0))
  (entmake (list '(0 . "LWPOLYLINE")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbPolyline")
                  (cons 90 3)
                  (cons 70 1)
                  (cons 10 (list (car p1) (cadr p1)))
                  (cons 10 (list (car p2) (cadr p2)))
                  (cons 10 (list (car p3) (cadr p3)))
            )
  )
)

;; small square marker centered at pt
(defun BGOL:APX-DrawSquare (pt size lname / p1 p2 p3 p4)
  (setq p1 (list (- (car pt) size) (- (cadr pt) size)))
  (setq p2 (list (+ (car pt) size) (- (cadr pt) size)))
  (setq p3 (list (+ (car pt) size) (+ (cadr pt) size)))
  (setq p4 (list (- (car pt) size) (+ (cadr pt) size)))
  (entmake (list '(0 . "LWPOLYLINE")
                  '(100 . "AcDbEntity")
                  (cons 8 lname)
                  '(100 . "AcDbPolyline")
                  (cons 90 4)
                  (cons 70 1)
                  (cons 10 p1) (cons 10 p2) (cons 10 p3) (cons 10 p4)
            )
  )
)

(defun C:APX ( / ss n i ent obj coords npts k pt apexCount endCount)
  (BGOL:APX-EnsureLayer "BGOL-APX" 1)      ; red triangles = internal apex
  (BGOL:APX-EnsureLayer "BGOL-APX-END" 3)  ; green squares = start/end

  (setq ss (ssget '((0 . "LWPOLYLINE"))))
  (if ss
    (progn
      (setq apexCount 0)
      (setq endCount 0)
      (setq n (sslength ss))
      (setq i 0)
      (while (< i n)
        (setq ent (ssname ss i))
        (setq obj (vlax-ename->vla-object ent))
        (setq coords (vlax-safearray->list (vlax-variant-value (vlax-get obj 'Coordinates))))
        ;; coords is a flat list x1 y1 x2 y2 ... ; rebuild as point pairs
        (setq npts (/ (length coords) 2))
        (setq k 0)
        (while (< k npts)
          (setq pt (list (nth (* k 2) coords) (nth (1+ (* k 2)) coords)))
          (cond
            ((or (= k 0) (= k (1- npts)))
             (BGOL:APX-DrawSquare pt 1.2 "BGOL-APX-END")
             (setq endCount (1+ endCount))
            )
            (t
             (BGOL:APX-DrawTriangle pt 1.2 "BGOL-APX")
             (setq apexCount (1+ apexCount))
            )
          )
          (setq k (1+ k))
        )
        (setq i (1+ i))
      )
      (princ (strcat "\nAPX: " (itoa apexCount) " apex point(s) and "
                      (itoa endCount) " start/end point(s) marked across "
                      (itoa n) " polyline(s)."))
    )
    (princ "\nNo polylines selected.")
  )
  (princ)
)

(princ "\nAPXMRK-bgol.lsp loaded. Type APX to mark apex points along selected alignments.")
(princ "\n  -- Free & open-source, courtesy of BGol Community (https://bgol.in/) --")
(princ)
