Загрузка данных


;; ============================================================
;; NVK_COORDS.LSP  v3.7
;; Кодировка: ANSI (CP1251). Блокнот -> Сохранить как -> ANSI
;; Команда: NVKCOORD
;; ============================================================
(vl-load-com)

;; ==================== НАСТРОЙКИ ====================
(setq NVK-LAYER      "НВК_Координаты точек")
(setq NVK-BLOCK-NAME "НВК_Координаты")
(setq NVK-SEARCH-R   2.0)
(setq NVK-PT-DIAM    0.5)
(setq NVK-TXT-HEIGHT 1.0)
(setq NVK-TXT-OFFSET 0.8)
(setq NVK-IDW-K      2.0)
(setq NVK-ZERO-EPS   0.001)
(setq NVK-MAX-PTS    7)
(setq NVK-TEXT-STYLE "Arial")

;; ==================== ВСПОМОГАТЕЛЬНЫЕ ====================
(defun nvk:doc () (vla-get-ActiveDocument (vlax-get-acad-object)))
(defun nvk:ms  () (vla-get-ModelSpace (nvk:doc)))
(defun nvk:p2d (p) (list (car p) (cadr p)))
(defun nvk:wcs (p) (trans p 1 0))   ; UCS -> WCS
(defun nvk:mcs (p) (trans p 0 1))   ; WCS -> UCS (для entmake)

(defun nvk:rtos2 (v / s)
  (setq s (vl-string-subst "," "." (rtos (abs v) 2 2)))
  (strcat (if (minusp v) "-" "+") s))

(defun nvk:fmt-x (v) (strcat "X= " (nvk:rtos2 v)))
(defun nvk:fmt-y (v) (strcat "Y= " (nvk:rtos2 v)))
(defun nvk:fmt-z (v) (strcat "Z= " (nvk:rtos2 v)))

;; Очистка от RTF/MTEXT кодов
(defun nvk:clean (s / i c res skip)
  (if (null s) (setq s ""))
  (setq res "" i 0 skip 0)
  (while (< i (strlen s))
    (setq c (substr s (1+ i) 1))
    (cond ((= c "{") (setq skip (1+ skip)))
          ((= c "}") (setq skip (max 0 (1- skip))))
          ((= skip 0) (setq res (strcat res c))))
    (setq i (1+ i)))
  (setq res (vl-string-subst "" "\\P" res))
  (setq res (vl-string-subst "" "\\p" res))
  (vl-string-trim " " res))

(defun nvk:numstr-p (s / t2)
  (and s (> (strlen s) 0)
       (progn (setq t2 (vl-string-trim " " (nvk:clean s)))
              (> (strlen t2) 0))
       (not (vl-catch-all-error-p
             (vl-catch-all-apply 'distof
               (list (vl-string-subst "." "," t2) 2))))))

(defun nvk:str->num (s)
  (distof (vl-string-subst "." "," (vl-string-trim " " (nvk:clean s))) 2))

(defun nvk:ensure-layer (/ lc lay)
  (setq lc (vla-get-Layers (nvk:doc)))
  (if (tblsearch "LAYER" NVK-LAYER)
    (setq lay (vla-Item lc NVK-LAYER))
    (setq lay (vla-Add lc NVK-LAYER)))
  (if (= (vla-get-Color lay) 7) (vla-put-Color lay 1)))

(defun nvk:ensure-style (/ sc sty)
  (setq sc (vla-get-TextStyles (nvk:doc)))
  (if (tblsearch "STYLE" NVK-TEXT-STYLE)
    (setq sty (vla-Item sc NVK-TEXT-STYLE))
    (setq sty (vla-Add sc NVK-TEXT-STYLE)))
  (vl-catch-all-apply 'vla-put-FontFile (list sty "arial.ttf")))

;; ==================== МАРКЕР ====================
(defun nvk:draw-marker (pwcs / r cx cy da rm i a1 a2 pm)
  ;; pwcs - точка в МСК (WCS)
  ;; Для entmake нужны координаты в текущей ПСК
  (setq pm (nvk:mcs pwcs)
        cx (car pm) cy (cadr pm)
        r  (/ NVK-PT-DIAM 2.0)
        da (/ (* 2.0 pi) 8.0)
        rm (* r 0.98) i 0)
  (entmake (list '(0 . "CIRCLE") (cons 8 NVK-LAYER)
                 '(62 . 256) '(6 . "BYLAYER")
                 (cons 10 (list cx cy 0.0)) (cons 40 r)))
  (repeat 8
    (setq a1 (* i da) a2 (* (1+ i) da) i (1+ i))
    (entmake (list '(0 . "SOLID") (cons 8 NVK-LAYER) '(62 . 256) '(6 . "BYLAYER")
                   (cons 10 (list (+ cx (* rm (cos a1))) (+ cy (* rm (sin a1))) 0.0))
                   (cons 11 (list (+ cx (* rm (cos a2))) (+ cy (* rm (sin a2))) 0.0))
                   (cons 12 (list cx cy 0.0))
                   (cons 13 (list cx cy 0.0))))))

;; ==================== MTEXT горизонтально в МСК ====================
;; group 11 = вектор X-направления текста В МСК
;; group 10 = точка вставки В МСК (WCS coords для entmake при extrusion 001)
;; ВАЖНО: при (210 . (0 0 1)) - стандартная экструзия МСК,
;;        group 10 и 11 задаются в МСК напрямую

(defun nvk:mtext-str (x y z)
  (if z
    (strcat (nvk:fmt-x y) "\\P" (nvk:fmt-y x) "\\P" (nvk:fmt-z z))
    (strcat (nvk:fmt-x y) "\\P" (nvk:fmt-y x))))

(defun nvk:add-mtext (pwcs x y z / ins en)
  ;; ins - точка над маркером В МСК
  (setq ins (list (car pwcs)
                  (+ (cadr pwcs) (/ NVK-PT-DIAM 2.0) NVK-TXT-OFFSET)
                  0.0))
  (setq en (entmakex (list
    (cons 0 "MTEXT")
    (cons 100 "AcDbEntity")
    (cons 8 NVK-LAYER)
    (cons 62 256)
    (cons 100 "AcDbMText")
    (cons 10 ins)                  ; вставка в МСК
    (cons 40 NVK-TXT-HEIGHT)
    (cons 41 0.0)
    (cons 71 1)
    (cons 72 5)
    (cons 1 (nvk:mtext-str x y z))
    (cons 7 NVK-TEXT-STYLE)
    (cons 210 '(0.0 0.0 1.0))     ; нормаль = ось Z МСК
    (cons 11 '(1.0 0.0 0.0))      ; X-вектор = горизонталь МСК
    (cons 90 3)
    (cons 45 1.1)
    (cons 63 256)
  )))
  en)

(defun nvk:update-mtext (en x y z / ed)
  (if (and en (entget en))
    (progn
      (setq ed (entget en))
      (setq ed (subst (cons 1 (nvk:mtext-str x y z)) (assoc 1 ed) ed))
      (entmod ed) (entupd en))))

;; ==================== БЛОК ====================
;; Минимальная структура ATTDEF без subclass - надёжнее работает

(defun nvk:make-block-def (/)
  (if (not (tblsearch "BLOCK" NVK-BLOCK-NAME))
    (progn
      (entmake (list '(0 . "BLOCK") (cons 2 NVK-BLOCK-NAME) '(70 . 0) '(10 0.0 0.0 0.0)))
      (foreach tag '("X_COORD" "Y_COORD" "Z_COORD")
        (entmake (list
          '(0 . "ATTDEF")
          (cons 8 NVK-LAYER)
          '(10 0.0 0.0 0.0)
          (cons 40 NVK-TXT-HEIGHT)
          '(1 . "")
          (cons 7 NVK-TEXT-STYLE)
          (cons 2 tag)
          (cons 3 tag)
          '(70 . 1)               ; невидимый
        )))
      (entmake '((0 . "ENDBLK"))))))

(defun nvk:insert-block (pwcs / br)
  ;; InsertBlock принимает точку в МСК
  (setq br (vla-InsertBlock (nvk:ms)
             (vlax-3d-point pwcs) NVK-BLOCK-NAME 1.0 1.0 1.0 0.0))
  (vla-put-Layer br NVK-LAYER)
  br)

(defun nvk:set-att (br tag val)
  (if (= :vlax-true (vla-get-HasAttributes br))
    (foreach a (vlax-safearray->list (vlax-variant-value (vla-GetAttributes br)))
      (if (= (strcase (vla-get-TagString a)) (strcase tag))
        (vla-put-TextString a val)))))

;; ==================== ПОИСК ОБЪЕКТОВ ====================
;; ssget "_X" с фильтром по пространству - работает на заблокированных слоях

(defun nvk:obj-pt (en / obj ip bb mn mx)
  (setq obj (vl-catch-all-apply 'vlax-ename->vla-object (list en)))
  (if (vl-catch-all-error-p obj) (setq obj nil))
  (if obj
    (cond
      ((vlax-property-available-p obj 'InsertionPoint)
       (trans (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint obj))) 0 0))
      ((and (vlax-method-applicable-p obj 'GetBoundingBox)
            (not (vl-catch-all-error-p
                  (vl-catch-all-apply 'vla-GetBoundingBox (list obj 'mn 'mx)))))
       (setq mn (vlax-safearray->list mn) mx (vlax-safearray->list mx))
       (mapcar '(lambda (a b) (/ (+ a b) 2.0)) mn mx))
      (t nil))
    nil))

(defun nvk:vals-from-en (en / obj nm s out z)
  (setq obj (vl-catch-all-apply 'vlax-ename->vla-object (list en)))
  (if (vl-catch-all-error-p obj) (setq obj nil))
  (setq out '())
  (if obj
    (progn
      (setq nm (vla-get-ObjectName obj))
      (cond
        ;; Блок с атрибутами
        ((and (= nm "AcDbBlockReference")
              (= :vlax-true (vla-get-HasAttributes obj)))
         (foreach a (vlax-safearray->list (vlax-variant-value (vla-GetAttributes obj)))
           (setq s (vla-get-TextString a))
           (if (nvk:numstr-p s)
             (setq out (cons (list (nvk:str->num s)
                               (strcat (vla-get-TagString a) "=" (nvk:clean s)))
                             out)))))
        ;; Текст / MTEXT
        ((member nm '("AcDbText" "AcDbMText"))
         (setq s (vla-get-TextString obj))
         (if (nvk:numstr-p s)
           (setq out (list (list (nvk:str->num s) (strcat "Текст=" (nvk:clean s)))))))
      )))
  out)

(defun nvk:pick-value (pick / tab ss i en p dist all cands msg idx)
  (setq tab  (getvar "CTAB")
        all  '())
  ;; ssget "_X" - работает на заблокированных слоях, фильтр по пространству
  (setq ss (ssget "_X" (list (cons 410 tab))))
  (if ss
    (progn
      (setq i 0)
      (repeat (sslength ss)
        (setq en (ssname ss i)
              p  (nvk:obj-pt en))
        (if p
          (progn
            (setq dist (distance (list (car pick) (cadr pick))
                                  (list (car p)   (cadr p))))
            (if (<= dist NVK-SEARCH-R)
              (foreach v (nvk:vals-from-en en)
                (setq all (cons (list dist (car v) (cadr v)) all))))))
        (setq i (1+ i)))))
  (setq all (vl-sort all '(lambda (a b) (< (car a) (car b)))))
  (cond
    ((null all) nil)
    ((= (length all) 1) (cadr (car all)))
    (t
     (setq msg "Найдено несколько значений:\n\n" idx 1)
     (foreach item all
       (setq msg (strcat msg (itoa idx) ". " (caddr item)
                         "  расст.=" (rtos (car item) 2 2) "\n")
             idx (1+ idx)))
     (alert msg)
     (initget 6)
     (setq idx (getint (strcat "\nНомер [1-" (itoa (length all)) "]: ")))
     (if (and idx (>= idx 1) (<= idx (length all)))
       (cadr (nth (1- idx) all)) nil))))

;; ==================== IDW ====================
(defun nvk:idw (base pts / num den d z)
  (setq num 0.0 den 0.0)
  (foreach p pts
    (setq d (distance (nvk:p2d base) (nvk:p2d p))
          z (caddr p))
    (if (< d NVK-ZERO-EPS)
      (progn (setq num z den 1.0) (setq pts nil))
      (progn (setq num (+ num (/ z (expt d NVK-IDW-K))))
             (setq den (+ den (/ 1.0 (expt d NVK-IDW-K)))))))
  (if (> den 0.0) (/ num den)))

;; ==================== ГЛАВНАЯ КОМАНДА ====================
(defun c:NVKCOORD (/ *error* olde olderr basew baseucs br mt-en pts done pick zval zw xw yw)
  (defun *error* (msg)
    (if olde   (setvar "CMDECHO"   olde))
    (if olderr (setvar "ERRNO"     0))
    (if (and msg (not (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")))
      (princ (strcat "\nОшибка: " msg)))
    (princ))
  (setq olde (getvar "CMDECHO"))
  (setvar "CMDECHO" 0)
  (nvk:ensure-layer)
  (nvk:ensure-style)
  (nvk:make-block-def)
  ;; Получаем точку в ПСК, конвертируем в МСК
  (setq baseucs (getpoint "\nУкажите базовую точку: "))
  (if baseucs
    (progn
      (setq basew  (nvk:wcs baseucs)   ; МСК (WCS)
            xw     (car  basew)
            yw     (cadr basew))
      (nvk:draw-marker basew)
      (setq br    (nvk:insert-block basew))
      (setq mt-en (nvk:add-mtext basew xw yw nil))
      (nvk:set-att br "X_COORD" (nvk:fmt-x yw))
      (nvk:set-att br "Y_COORD" (nvk:fmt-y xw))
      (nvk:set-att br "Z_COORD" "")
      (if (null mt-en) (princ "\n[НВК] Предупреждение: MTEXT не создан"))
      (if (null br)    (princ "\n[НВК] Предупреждение: блок не создан"))
      (setq pts '() done nil)
      (while (not done)
        (setq pick (getpoint "\nESC - завершить, укажите соседнюю точку: "))
        (cond
          ((null pick) (setq done T))
          (t
           (setq pick (nvk:wcs pick)   ; конвертируем в МСК
                 zval (nvk:pick-value pick))
           (cond
             ((null zval)
              (princ (strcat "\n[НВК] Не найдено в радиусе " (rtos NVK-SEARCH-R 2 1) " ед.")))
             (t
              (setq pts (append pts (list (list (car pick) (cadr pick) zval))))
              (princ (strcat "\n[НВК] Z=" (rtos zval 2 3) "  (точек: " (itoa (length pts)) ")"))
              (if (>= (length pts) 2)
                (progn
                  (setq zw (nvk:idw basew pts))
                  (nvk:update-mtext mt-en xw yw zw)
                  (nvk:set-att br "Z_COORD" (nvk:fmt-z zw))
                  (princ (strcat "  Z_IDW=" (rtos zw 2 3)))))
              (if (>= (length pts) NVK-MAX-PTS) (setq done T)))))))
      (if br (vla-Update br))))
  (setvar "CMDECHO" olde)
  (princ))

(princ "\nНВК_Координаты v3.7 загружена. Команда: NVKCOORD")
(princ)