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


;; ============================================================
;; NVK_COORDS.LSP  v3.6
;; Кодировка: 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:sa3 (p) (vlax-3d-point (list (car p) (cadr p) 0.0)))
(defun nvk:wcs (p) (trans p 1 0))

(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)))

;; Очистить строку от MText RTF-кодов вида {\f...|...; текст}
(defun nvk:strip-mtext (s / i c out in-brace depth)
  (if (not s) (setq s ""))
  ;; Если нет { - строка чистая
  (if (not (vl-string-search "{" s))
    s
    ;; Иначе: берём содержимое после последней ; внутри скобок
    (progn
      (setq out "" depth 0 in-brace nil)
      (setq i 0)
      (while (< i (strlen s))
        (setq c (substr s (1+ i) 1))
        (cond
          ((= c "{") (setq depth (1+ depth) in-brace T))
          ((= c "}") (setq depth (max 0 (1- depth))) (if (= depth 0) (setq in-brace nil)))
          ((and in-brace (= c ";"))
           ;; После ; идёт чистый текст до следующего { или }
           (setq out ""))
          ((not in-brace)
           (setq out (strcat out c)))
          ((and in-brace (> depth 0) (not (= c ";")))
           ;; накапливаем после ; 
           nil)
        )
        (setq i (1+ i)))
      (vl-string-trim " " out))))

;; Упрощённый вариант: берём всё что не в скобках и не управляющие символы
(defun nvk:clean-text (s / res i c skip)
  (if (not 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)))
  ;; Убрать \P и \p (переносы строк MText)
  (setq res (vl-string-subst " " "\\P" res))
  (setq res (vl-string-subst " " "\\p" res))
  (vl-string-trim " " res))

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

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

(defun nvk:yesno (msg ttl / sh r)
  (setq sh (vlax-create-object "WScript.Shell"))
  (setq r (vlax-invoke sh 'Popup msg 0 ttl (+ 4 32)))
  (vlax-release-object sh)
  (= r 6))

(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")))

;; ==================== МАРКЕР (круг + SOLID-веер) ====================
(defun nvk:draw-marker (p / r cx cy da rm i a1 a2)
  (setq cx (car p) cy (cadr p) 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 (отдельный объект, перемещаемый) ====================
;; Создаём MTEXT вне блока - у него есть собственная ручка для перемещения
;; Угол всегда 0, экструзия (0,0,1) = горизонтальный текст в МСК

(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 (p x y z / ins en)
  (setq ins (list (car p)
                  (+ (cadr p) (/ NVK-PT-DIAM 2.0) NVK-TXT-OFFSET)
                  0.0))
  (setq en (entmakex
    (list
      (cons 0 "MTEXT")
      (cons 8 NVK-LAYER)
      (cons 62 256)
      (cons 6 "BYLAYER")
      (cons 100 "AcDbEntity")
      (cons 100 "AcDbMText")
      (cons 10 ins)          ; точка вставки в МСК
      (cons 40 NVK-TXT-HEIGHT)
      (cons 41 0.0)          ; ширина = авто
      (cons 71 1)            ; выравнивание: левый верх
      (cons 72 5)            ; направление: слева направо
      (cons 210 '(0.0 0.0 1.0))  ; экструзия = МСК, угол = 0
      (cons 11 '(1.0 0.0 0.0))   ; вектор X-направления = горизонталь
      (cons 1 (nvk:mtext-str x y z))
      (cons 7 NVK-TEXT-STYLE)
      (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))))

;; ==================== БЛОК С АТРИБУТАМИ ====================
(defun nvk:make-block-def (/ tp)
  (if (not (tblsearch "BLOCK" NVK-BLOCK-NAME))
    (progn
      (entmake (list (cons 0 "BLOCK") (cons 2 NVK-BLOCK-NAME) (cons 70 0) (cons 10 '(0.0 0.0 0.0))))
      (setq tp '(0.0 0.0 0.0))
      (foreach tag '("X_COORD" "Y_COORD" "Z_COORD")
        (entmake (list
          (cons 0 "ATTDEF")
          (cons 100 "AcDbEntity")
          (cons 8 NVK-LAYER)
          (cons 62 256)
          (cons 100 "AcDbText")
          (cons 10 tp)
          (cons 40 NVK-TXT-HEIGHT)
          (cons 1 "")
          (cons 7 NVK-TEXT-STYLE)
          (cons 50 0.0)
          (cons 72 0)
          (cons 11 tp)
          (cons 100 "AcDbAttributeDefinition")
          (cons 280 0)
          (cons 3 tag)
          (cons 2 tag)
          (cons 70 1)     ; невидимый
          (cons 74 0)
          (cons 280 0))))
      (entmake (list (cons 0 "ENDBLK"))))))

(defun nvk:insert-block (p / br)
  (setq br (vla-InsertBlock (nvk:ms) (nvk:sa3 p) 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)))))

;; ==================== ПОИСК (включая заблокированные слои) ====================
(defun nvk:obj-center (en / obj mn mx p1 p2 r)
  (setq r (vl-catch-all-apply
    '(lambda (/ obj)
      (setq obj (vlax-ename->vla-object en))
      (cond
        ((vlax-property-available-p obj 'InsertionPoint)
         (nvk:wcs (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint obj)))))
        ((vlax-method-applicable-p obj 'GetBoundingBox)
         (vla-GetBoundingBox obj 'mn 'mx)
         (setq p1 (vlax-safearray->list mn) p2 (vlax-safearray->list mx))
         (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2))
        (t nil)))
    nil))
  (if (vl-catch-all-error-p r) nil r))

(defun nvk:get-num-vals (en / obj nm out s z)
  ;; Возвращает список числовых значений из объекта
  (setq out '())
  (setq obj (vl-catch-all-apply 'vlax-ename->vla-object (list en)))
  (if (vl-catch-all-error-p obj) (setq obj nil))
  (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-text s)))
                             out))))
         ;; Если нет числовых атрибутов - проверить Z вставки
         (if (null out)
           (progn
             (setq z (caddr (nvk:obj-center en)))
             (if (and z (/= (abs z) 0.0))
               (setq out (list (list z (strcat "Z блока=" (rtos z 2 2)))))))))
        ;; Текст / 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-text s)))))))
        ;; Блок без атрибутов - Z
        ((= nm "AcDbBlockReference")
         (setq z (caddr (nvk:obj-center en)))
         (if (and z (/= (abs z) 0.0))
           (setq out (list (list z (strcat "Z=" (rtos z 2 2)))))))
      )))
  out)

(defun nvk:pick-value (pick / all ss i en p dist vals msg idx)
  (setq all '())
  ;; Поиск в квадрате NVK-SEARCH-R вокруг точки клика, все объекты включая заблок.слои
  (setq ss (ssget "_C"
                  (list (- (car pick) NVK-SEARCH-R) (- (cadr pick) NVK-SEARCH-R) 0.0)
                  (list (+ (car pick) NVK-SEARCH-R) (+ (cadr pick) NVK-SEARCH-R) 0.0)))
  (if (null ss)
    ;; Если ssget "_C" не нашёл - пробуем "_X" (все объекты)
    (setq ss (ssget "_X" nil)))
  (if ss
    (progn
      (setq i 0)
      (repeat (sslength ss)
        (setq en (ssname ss i) p (nvk:obj-center en))
        (if p
          (progn
            (setq dist (distance (list (car pick) (cadr pick) 0.0)
                                  (list (car p)   (cadr p)   0.0)))
            (if (<= dist NVK-SEARCH-R)
              (foreach v (nvk:get-num-vals 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 (list (car base) (cadr base) 0.0) (list (car p) (cadr p) 0.0))
          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 basew br mt-en pts done pick zval zw xw yw)
  (defun *error* (msg)
    (if olde (setvar 'CMDECHO olde))
    (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 basew (getpoint "\nУкажите базовую точку: "))
  (if basew
    (progn
      (setq basew (nvk:wcs basew)
            xw    (car  basew)
            yw    (cadr basew))
      ;; Маркер
      (nvk:draw-marker basew)
      ;; Блок с невидимыми атрибутами (точка = центр)
      (setq br (nvk:insert-block basew))
      ;; MTEXT - отдельный объект с собственной ручкой, горизонтальный
      (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"))
      ;; Цикл выбора соседних точек
      (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)
                             " ед. Попробуйте ещё раз или ESC.")))
             (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)))))))
      (vla-Update br)))
  (setvar 'CMDECHO olde)
  (princ))

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