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


;; ============================================================
;; NVK_COORDS.LSP  v3.4
;; Кодировка: ANSI (CP1251). Блокнот -> Сохранить как -> ANSI
;; Команда: NVKCOORD
;; Исправлено:
;;   - перенос строк в MTEXT через entmake (DXF код 1) вместо "\P"
;;   - маска фона через entmake DXF 90/45/63 - без vla-put-usebackgroundcolor
;;   - MTEXT ставится строго над центром круга
;; ============================================================
(vl-load-com)

;; ==================== НАСТРОЙКИ ====================
(setq NVK-LAYER      "НВК_Координаты точек")
(setq NVK-BLOCK-NAME "НВК_Координаты")
(setq NVK-SEARCH-R   1.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")
(setq NVK-MASK-SCALE 1.1)

;; ==================== ВСПОМОГАТЕЛЬНЫЕ ====================
(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) (if (caddr p) (caddr 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)))

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

(defun nvk:str->num (s)
  (distof (vl-string-subst "." "," (vl-string-trim " " s)) 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")))

;; ==================== МАРКЕР ====================
(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))
  (entmake (list '(0 . "CIRCLE")
                 (cons 8 NVK-LAYER)
                 '(62 . 256) '(6 . "BYLAYER")
                 (cons 10 (list cx cy 0.0))
                 (cons 40 r)))
  (setq da (/ (* 2.0 pi) 8.0) rm (* r 0.98) i 0)
  (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))))))

;; ==================== ОПРЕДЕЛЕНИЕ БЛОКА ====================
(defun nvk:make-block-def (/ tp)
  (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)))
      (setq tp '(0.0 0.0 0.0))
      (foreach tag '("X_COORD" "Y_COORD" "Z_COORD")
        (entmake (list '(0 . "ATTDEF") (cons 8 NVK-LAYER)
                       '(100 . "AcDbEntity") '(100 . "AcDbText")
                       (cons 10 tp) (cons 40 NVK-TXT-HEIGHT) (cons 1 "")
                       (cons 7 NVK-TEXT-STYLE) (cons 72 0) (cons 11 tp)
                       '(100 . "AcDbAttributeDefinition")
                       (cons 3 tag) (cons 2 tag) (cons 70 1) (cons 74 2))))
      (entmake '((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)))))

;; ==================== MTEXT через entmake ====================
;; DXF 90: флаги маски фона (бит 1=включена, бит 2=цвет фона)
;; DXF 45: масштаб рамки маски (>= 1.0)
;; DXF 63: цвет маски (256 = по слою/фону)
;; Перенос строк в DXF коде 1: символ \P (в entmake нужен реальный \n в строке кода)

(defun nvk:mtext-str (x y z)
  ;; Формируем строку с переносом через \P (MTEXT-коды)
  (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 ename)
  (setq ins (list (car p)
                  (+ (cadr p) (/ NVK-PT-DIAM 2.0) NVK-TXT-OFFSET)
                  (caddr p)))
  (entmake (list '(0 . "MTEXT")
                 (cons 8 NVK-LAYER)
                 '(62 . 256) '(6 . "BYLAYER")
                 (cons 10 ins)           ; точка вставки
                 (cons 40 NVK-TXT-HEIGHT) ; высота текста
                 (cons 41 0.0)           ; ширина = 0 (авто)
                 (cons 71 1)             ; выравнивание: левый верх
                 (cons 72 5)             ; направление: слева направо
                 (cons 1 (nvk:mtext-str x y z)) ; текст с \P
                 (cons 7 NVK-TEXT-STYLE)
                 ;; Маска фона:
                 (cons 90 3)             ; 1+2: маска вкл + цвет фона чертежа
                 (cons 45 NVK-MASK-SCALE) ; масштаб рамки
                 (cons 63 256)           ; цвет маски = фон чертежа
                 ))
  (entlast))

(defun nvk:update-mtext (en x y z / ed)
  (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:obj-center (obj / mn mx p1 p2)
  (cond
    ((vlax-property-available-p obj 'InsertionPoint)
     (nvk:wcs (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint obj)))))
    ((and (vlax-method-applicable-p obj 'GetBoundingBox)
          (not (vl-catch-all-error-p
                (vl-catch-all-apply 'vla-GetBoundingBox (list 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)))

(defun nvk:block-num-attrs (obj / out)
  (setq out '())
  (if (and (= (vla-get-ObjectName obj) "AcDbBlockReference")
           (= :vlax-true (vla-get-HasAttributes obj)))
    (foreach a (vlax-safearray->list (vlax-variant-value (vla-GetAttributes obj)))
      (if (nvk:numstr-p (vla-get-TextString a))
        (setq out (cons (list (vla-get-TagString a)
                              (vla-get-TextString a)
                              (nvk:str->num (vla-get-TextString a))) out)))))
  (reverse out))

(defun nvk:text-num (obj / s)
  (and (member (vla-get-ObjectName obj) '("AcDbText" "AcDbMText"))
       (nvk:numstr-p (setq s (vla-get-TextString obj)))
       (list s (nvk:str->num s))))

(defun nvk:candidates-from (obj / p z attrs tv cands)
  (setq cands '() p (nvk:obj-center obj))
  (if p
    (progn
      (setq z (caddr p) attrs (nvk:block-num-attrs obj))
      (if attrs
        (foreach a attrs
          (cond
            ((and (/= (abs z) 0.0) (not (equal z (caddr a) 0.01)))
             (setq cands (cons (list 'ASK z (caddr a)
                                (strcat "Блок Z=" (rtos z 2 2) " | Атрибут " (car a) "=" (cadr a)))
                               cands)))
            (t (setq cands (cons (list 'VAL (caddr a)
                                  (strcat "Атрибут " (car a) "=" (cadr a))) cands))))))
      (if (and (null attrs) (= (vla-get-ObjectName obj) "AcDbBlockReference") (/= (abs z) 0.0))
        (setq cands (cons (list 'VAL z (strcat "Z блока=" (rtos z 2 2))) cands)))
      (setq tv (nvk:text-num obj))
      (if tv (setq cands (cons (list 'VAL (cadr tv) (strcat "Текст=" (car tv))) cands)))))
  (reverse cands))

(defun nvk:resolve (cand)
  (cond
    ((null cand) nil)
    ((= (car cand) 'ASK)
     (if (nvk:yesno (strcat "Z и атрибут не совпадают.\n\n" (cadddr cand)
                            "\n\nДа = Z объекта\nНет = значение атрибута")
                    "НВК_Координаты")
       (cadr cand) (caddr cand)))
    ((= (car cand) 'VAL) (cadr cand))
    (t nil)))

(defun nvk:pick-value (pick / eres ename obj cands all ss i en dist p msg idx)
  (setq eres (nentselp "" pick))
  (if eres
    (progn
      (setq ename (car eres) obj (vlax-ename->vla-object ename)
            cands (nvk:candidates-from obj) p (nvk:obj-center obj))
      (if (and p (> (distance (list (car pick) (cadr pick) 0.0)
                               (list (car p)  (cadr p)  0.0)) NVK-SEARCH-R))
        (setq cands '())))
    (progn
      (setq cands '() all '())
      (setq ss (ssget "_C"
                      (list (- (car pick) NVK-SEARCH-R) (- (cadr pick) NVK-SEARCH-R))
                      (list (+ (car pick) NVK-SEARCH-R) (+ (cadr pick) NVK-SEARCH-R))))
      (if ss
        (progn
          (setq i 0)
          (repeat (sslength ss)
            (setq en (ssname ss i) obj (vlax-ename->vla-object en) p (nvk:obj-center obj))
            (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 c (nvk:candidates-from obj)
                    (setq all (cons (list dist c) all))))))
            (setq i (1+ i)))
          (setq all (vl-sort all '(lambda (a b) (< (car a) (car b)))))
          (if all (setq cands (list (cadr (car all)))))))))
  (cond
    ((null cands) nil)
    ((= (length cands) 1) (nvk:resolve (car cands)))
    (t
     (setq msg "Найдено несколько значений:\n\n" idx 1)
     (foreach c cands
       (setq msg (strcat msg (itoa idx) ". "
                         (if (= (car c) 'ASK) (cadddr c) (caddr c)) "\n") idx (1+ idx)))
     (alert msg)
     (initget 6)
     (setq idx (getint (strcat "\nНомер [1-" (itoa (length cands)) "]: ")))
     (if (and idx (>= idx 1) (<= idx (length cands)))
       (nvk:resolve (nth (1- idx) cands)) 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))
      (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" "")
      (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 "\n[НВК] Данные не найдены. Попробуйте ещё раз или нажмите ESC."))
             (t
              (setq pts (append pts (list (list (car pick) (cadr pick) zval))))
              (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))))
              (if (>= (length pts) NVK-MAX-PTS) (setq done T)))))))
      (vla-Update br)))
  (setvar 'CMDECHO olde)
  (princ))

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