;;; ºÎÀç ÀÌ¸§ - TORVA ¹«·á ¸®½À (torva.kr/lisp.html)
;;; BN : º¸ ÀÌ¸§. º¸(4Á¡ Æú¸®¼± »ç°¢Çü, ¼±, Ä¡¼ö¼±)¸¦ °í¸£¸é ºÎÀç ¹æÇâÀ» µû¶ó º¸ À§¿¡ ÀÌ¸§À» ¾´´Ù
;;; CN : ±âµÕ ÀÌ¸§. ±âµÕ ¿Ü°ûÀ» °í¸£¸é Å©±â°¡ Å« °ÍºÎÅÍ C1, C2 ... ·Î ¹øÈ£¸¦ ¸Å°Ü ¿ÞÂÊ À§¿¡ ¾´´Ù
;;; ÀÌ¸§À» ¹¯´Â ÀÚ¸®¿¡¼­ H(±ÛÀÚ ³ôÀÌ)¸¦ ¹Ù²Ü ¼ö ÀÖ´Ù. ¹Ù²Û °ªÀº µµ¸éÀ» ´ÝÀ» ¶§±îÁö À¯ÁöµÈ´Ù
;;; ±ÛÀÚ ³ôÀÌ ±âº»°ª = 3.5 x DIMSCALE (1:100 µµ¸éÀÌ¸é 350). ºÎÀç¿Í ±ÛÀÚ »çÀÌ = 1 x DIMSCALE
;;; ·¹ÀÌ¾î MEMBER-NAME (¾øÀ¸¸é ¸¸µç´Ù). ±Û²ÃÀº ÇöÀç ¹®ÀÚ ½ºÅ¸ÀÏ

(vl-load-com)

(if (null *TV-MN-BEAM*) (setq *TV-MN-BEAM* "G1"))
(if (null *TV-MN-COL*)  (setq *TV-MN-COL* "C"))
(setq *TV-MN-LAYER* "MEMBER-NAME")

(defun tv-mn-ds ()
  (if (> (getvar "DIMSCALE") 0) (getvar "DIMSCALE") 1.0))

;; ±ÛÀÚ ³ôÀÌ - Á÷Á¢ Á¤ÇÑ °ªÀÌ ¾øÀ¸¸é µµ¸é ÃàÃ´¿¡ ¸ÂÃá´Ù
(defun tv-mn-h ()
  (cond (*TV-MN-H*) ((* 3.5 (tv-mn-ds)))))

(defun tv-mn-layer ()
  (if (null (tblsearch "LAYER" *TV-MN-LAYER*))
    (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")
                   (cons 2 *TV-MN-LAYER*) '(70 . 0) '(62 . 3) '(6 . "Continuous")))))

;; ÀÌ¸§ ¹¯±â - H ¸¸ ÀÔ·ÂÇÏ¸é ±ÛÀÚ ³ôÀÌ¸¦ ¹Ù²Ù°í ´Ù½Ã ¹¯´Â´Ù. ¿£ÅÍ¸é ±âº»°ª
(defun tv-mn-name (msg def / r v)
  (setq r "H")
  (while (= (strcase r) "H")
    (setq r (getstring (strcat "\n" msg " [±ÛÀÚ ³ôÀÌ(H)] <" def ", ³ôÀÌ " (rtos (tv-mn-h) 2 0) ">: ")))
    (if (= (strcase r) "H")
      (if (setq v (getdist (strcat "\n±ÛÀÚ ³ôÀÌ <" (rtos (tv-mn-h) 2 0) ">: "))) (setq *TV-MN-H* v))))
  (if (= r "") def r))

(defun tv-mn-text (pt h str ang h72)
  (entmakex (list '(0 . "TEXT") '(100 . "AcDbEntity") (cons 8 *TV-MN-LAYER*) '(100 . "AcDbText")
                  (cons 10 pt) (cons 11 pt) (cons 40 h) (cons 1 str) (cons 50 ang)
                  (cons 7 (getvar "TEXTSTYLE")) (cons 72 h72) '(73 . 2))))

;; Àá±ä ·¹ÀÌ¾î¸é T
(defun tv-mn-locked (en / d)
  (setq d (tblsearch "LAYER" (cdr (assoc 8 (entget en)))))
  (and d (= 4 (logand 4 (cdr (assoc 70 d))))))

(defun c:BN (/ *error* old ce ss i en ed typ pts p1 p2 p3 c ang bw h gap n name)
  (setq ce (getvar "CMDECHO") old *error*)
  (defun *error* (msg)
    (setvar "CMDECHO" ce) (setq *error* old)
    (if (not (wcmatch (strcase msg) "*CANCEL*,*QUIT*,*BREAK*")) (princ (strcat "\n¿À·ù: " msg)))
    (princ))
  (setvar "CMDECHO" 0)
  (setq name (tv-mn-name "º¸ ÀÌ¸§" *TV-MN-BEAM*) *TV-MN-BEAM* name)
  (princ "\nÀÌ¸§À» ºÙÀÏ º¸ ¼±ÅÃ (»ç°¢ Æú¸®¼±, ¼±, Ä¡¼ö¼±): ")
  (if (setq ss (ssget '((-4 . "<OR") (-4 . "<AND") (0 . "LWPOLYLINE") (90 . 4) (-4 . "AND>")
                        (0 . "LINE") (0 . "DIMENSION") (-4 . "OR>"))))
    (progn
      (tv-mn-layer)
      (setq i 0 n 0 h (tv-mn-h) gap (tv-mn-ds))
      (repeat (sslength ss)
        (setq en (ssname ss i) ed (entget en) typ (cdr (assoc 0 ed)) i (1+ i))
        (if (not (tv-mn-locked en))
          (progn
            (if (= typ "LWPOLYLINE")
              (progn
                ;; »ç°¢ º¸: ³× Á¡ °¡¿îµ¥, ±ä º¯ ¹æÇâ, ÂªÀº º¯ÀÌ º¸ Æø
                (setq pts nil)
                (foreach x ed (if (= (car x) 10) (setq pts (append pts (list (cdr x))))))
                (setq p1 (nth 0 pts) p2 (nth 1 pts) p3 (nth 2 pts))
                (setq c (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p3))
                (if (> (distance p1 p2) (distance p2 p3))
                  (setq ang (angle p1 p2) bw (distance p2 p3))
                  (setq ang (angle p2 p3) bw (distance p1 p2))))
              (progn
                ;; ¼±¡¤Ä¡¼ö¼±: Æø 0
                (if (= typ "DIMENSION")
                  (setq p1 (cdr (assoc 13 ed)) p2 (cdr (assoc 14 ed)))
                  (setq p1 (cdr (assoc 10 ed)) p2 (cdr (assoc 11 ed))))
                (setq c (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2) ang (angle p1 p2) bw 0.0)))
            ;; ±ÛÀÚ°¡ µÚÁýÈ÷Áö ¾Ê°Ô -90 ~ 90 µµ·Î
            (while (>= ang pi) (setq ang (- ang pi)))
            (if (> ang (/ pi 2.0)) (setq ang (- ang pi)))
            (if (equal ang (/ pi -2.0) 0.001) (setq ang (/ pi 2.0)))
            (tv-mn-text (polar (list (car c) (cadr c) 0.0) (+ ang (/ pi 2.0)) (+ (/ bw 2.0) gap (/ h 2.0))) h name ang 1)
            (setq n (1+ n)))))
      (princ (strcat "\nº¸ " (itoa n) "°³¿¡ " name))))
  (setvar "CMDECHO" ce) (setq *error* old)
  (princ))

(defun c:CN (/ *error* old ce doc ss i en obj mn mx a b big small pt all sizes k n h gap done dup pre)
  (setq ce (getvar "CMDECHO") old *error* doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  (defun *error* (msg)
    (setvar "CMDECHO" ce) (setq *error* old) (vla-EndUndoMark doc)
    (if (not (wcmatch (strcase msg) "*CANCEL*,*QUIT*,*BREAK*")) (princ (strcat "\n¿À·ù: " msg)))
    (princ))
  (vla-StartUndoMark doc)
  (setvar "CMDECHO" 0)
  (setq pre (tv-mn-name "±âµÕ ÀÌ¸§ ¾Õ±ÛÀÚ" *TV-MN-COL*) *TV-MN-COL* pre)
  (princ "\nÀÌ¸§À» ºÙÀÏ ±âµÕ ¿Ü°û ¼±ÅÃ: ")
  (if (setq ss (ssget))
    (progn
      (tv-mn-layer)
      (setq i 0 h (tv-mn-h) gap (tv-mn-ds))
      ;; 1. ±âµÕ¸¶´Ù ¿Ü°û Å©±â(±ä º¯, ÂªÀº º¯)¿Í ±ÛÀÚ ÀÚ¸®(¿ÞÂÊ À§ ¹Ù±ù)
      (repeat (sslength ss)
        (setq en (ssname ss i) i (1+ i) obj (vlax-ename->vla-object en))
        (if (and (not (tv-mn-locked en))
                 (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-GetBoundingBox (list obj 'mn 'mx)))))
          (progn
            (setq mn (vlax-safearray->list mn) mx (vlax-safearray->list mx))
            (setq a (- (car mx) (car mn)) b (- (cadr mx) (cadr mn)))
            (setq big (fix (+ (max a b) 0.5)) small (fix (+ (min a b) 0.5)))
            (setq pt (list (- (car mn) gap) (+ (cadr mx) gap (/ h 2.0)) 0.0))
            (setq all (cons (list big small pt) all))
            (if (not (member (list big small) sizes)) (setq sizes (cons (list big small) sizes))))))
      ;; 2. Å« °ÍºÎÅÍ ¹øÈ£: ±ä º¯, °°À¸¸é ÂªÀº º¯
      (setq sizes (vl-sort sizes '(lambda (x y) (if (= (car x) (car y)) (> (cadr x) (cadr y)) (> (car x) (car y))))))
      ;; 3. ±ÛÀÚ ¾²±â. °°Àº ÀÚ¸®(±ÛÀÚ ³ôÀÌÀÇ 1/10 ¾È)¿¡ ÀÌ¹Ì ½èÀ¸¸é °Ç³Ê¶Ú´Ù
      (setq n 0)
      (foreach e all
        (setq dup nil)
        (foreach p done (if (< (distance (caddr e) p) (* 0.1 h)) (setq dup T)))
        (if (not dup)
          (progn
            (setq k (1+ (vl-position (list (car e) (cadr e)) sizes)))
            (tv-mn-text (caddr e) h (strcat pre (itoa k)) 0.0 2)
            (setq done (cons (caddr e) done) n (1+ n)))))
      (princ (strcat "\n±âµÕ " (itoa n) "°³, Å©±â " (itoa (length sizes)) "Á¾·ù"))))
  (setvar "CMDECHO" ce) (setq *error* old) (vla-EndUndoMark doc)
  (princ))

(princ "\nºÎÀç ÀÌ¸§: BN (º¸) / CN (±âµÕ) / torva.kr")
(princ)

;;; ---- ´ÜÃàÅ° ¹Ù²Ù±â (TVKEY) - TORVA ¸®½À °øÅë, torva.kr/lisp-guide.html ----
;;; TVKEY -> ¸í·É -> »õ ´ÜÃàÅ°. ¿ø·¡ ¸í·É¾îµµ ±×´ë·Î ¾´´Ù
;;; Á¤ÇÑ ´ÜÃàÅ°´Â ÀÌ PC ¿¡ TORVA-KEYS ·Î ÀúÀåµÇ°í, ¸®½ÀÀ» ºÒ·¯¿Ã ¶§¸¶´Ù µÇ»ì¾Æ³­´Ù
;;; (TORVA ¸®½À ÆÄÀÏ¸¶´Ù °°Àº ÄÚµå°¡ µé¾î ÀÖ´Ù. ¿©·¯ °³¸¦ ºÒ·¯¿Íµµ °°Àº Á¤ÀÇ¸¦ µ¤¾î¾µ »ÓÀÌ´Ù)

;; "A1=PY;B2=CN;" -> (("A1" . "PY") ("B2" . "CN"))
(defun tv-key-list (/ s i out)
  (setq s (cond ((getenv "TORVA-KEYS")) ("")) out nil)
  (while (setq i (vl-string-search ";" s))
    (setq out (cons (substr s 1 i) out) s (substr s (+ i 2))))
  (if (/= s "") (setq out (cons s out)))
  (vl-remove nil
    (mapcar '(lambda (x / j) (if (setq j (vl-string-search "=" x)) (cons (substr x 1 j) (substr x (+ j 2)))))
            (reverse out))))

(defun tv-key-save (lst)
  (setenv "TORVA-KEYS" (apply 'strcat (mapcar '(lambda (p) (strcat (car p) "=" (cdr p) ";")) lst))))

;; ºÒ·¯¿Â ¸®½À ¸í·ÉÀÎ°¡
(defun tv-key-cmd-p (cmd)
  (member (type (eval (read (strcat "C:" cmd)))) '(SUBR USUBR EXRXSUBR)))

(defun tv-key-def (key cmd)
  (eval (list 'defun (read (strcat "C:" key)) '() (list (read (strcat "C:" cmd))) '(princ))))

;; acad.pgp ¿¡ °°Àº º°ÄªÀÌ ÀÖ³ª ("L,   *LINE")
(defun tv-key-pgp-p (key / f h l hit)
  (if (setq f (findfile "acad.pgp"))
    (progn
      (setq h (open f "r"))
      (while (and (not hit) (setq l (read-line h)))
        (if (and (not (wcmatch l ";*")) (wcmatch (strcase l) (strcat key ",*"))) (setq hit T)))
      (close h)))
  hit)

;; ¾µ ¼ö ¾ø´Â ´ÜÃàÅ°¸é ±î´ßÀ», ¾µ ¼ö ÀÖÀ¸¸é nil
(defun tv-key-bad (key lst)
  (cond
    ((not (vl-every '(lambda (c) (or (<= 48 c 57) (<= 65 c 90))) (vl-string->list key))) "¿µ¹®°ú ¼ýÀÚ¸¸ ¾¹´Ï´Ù")
    ((getcname key) "AutoCAD ¸í·É°ú °°Àº ÀÌ¸§ÀÔ´Ï´Ù")
    ((tv-key-pgp-p key) "AutoCAD ´ÜÃàÅ°(acad.pgp)¿Í °°Àº ÀÌ¸§ÀÔ´Ï´Ù")
    ((and (tv-key-cmd-p key) (not (assoc key lst))) "ÀÌ¹Ì ÀÖ´Â ¸®½À ¸í·ÉÀÔ´Ï´Ù")))

(defun c:TVKEY (/ cmd key lst why)
  (setq lst (tv-key-list)
        cmd (strcase (getstring "\n´ÜÃàÅ°¸¦ ºÙÀÏ ¸í·É [¸ñ·Ï(?)]: ")))
  (cond
    ((= cmd ""))
    ((= cmd "?")
     (if lst
       (foreach p lst (princ (strcat "\n  " (car p) " = " (cdr p))))
       (princ "\nÁ¤ÇÑ ´ÜÃàÅ°°¡ ¾ø½À´Ï´Ù")))
    ((not (tv-key-cmd-p cmd)) (princ (strcat "\n" cmd " ´Â ºÒ·¯¿Â ¸®½À ¸í·ÉÀÌ ¾Æ´Õ´Ï´Ù")))
    (T
     (setq key (strcase (getstring (strcat "\n" cmd " ÀÇ »õ ´ÜÃàÅ° [Áö¿ì±â(-)]: "))))
     (cond
       ((= key ""))
       ((= key "-")
        (foreach p lst
          (if (= (cdr p) cmd) (set (read (strcat "C:" (car p))) nil)))
        (tv-key-save (vl-remove-if '(lambda (p) (= (cdr p) cmd)) lst))
        (princ (strcat "\n" cmd " ÀÇ ´ÜÃàÅ°¸¦ Áö¿ü½À´Ï´Ù")))
       ((= key cmd))
       ((setq why (tv-key-bad key lst)) (princ (strcat "\n" key ": " why)))
       (T
        (tv-key-save (cons (cons key cmd) (vl-remove-if '(lambda (p) (= (car p) key)) lst)))
        (tv-key-def key cmd)
        (princ (strcat "\nÀÌÁ¦ " key " ·Îµµ " cmd " °¡ ½ÇÇàµË´Ï´Ù"))))))
  (princ))

;; ºÒ·¯¿Ã ¶§ - ÀúÀåµÈ ´ÜÃàÅ° Áß ¸í·ÉÀÌ ºÒ·¯¿ÍÁ® ÀÖ´Â °ÍÀ» µÇ»ì¸°´Ù
(foreach p (tv-key-list)
  (if (tv-key-cmd-p (cdr p)) (tv-key-def (car p) (cdr p))))
(princ "\n´ÜÃàÅ° ¹Ù²Ù±â: TVKEY")
(princ)
