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


;;; ============================================================
;;; DIMFIX.LSP v7
;;; XDATA хранится на INSERT (вхождении блока) — не на DIMENSION
;;; Формат XDATA на INSERT:
;;;   (1000 . "DIMFIX")         ; маркер начала блока данных
;;;   (1000 . "handle_размера") ; handle объекта DIMENSION
;;;   (1000 . "префикс")
;;;   (1000 . "суффикс")
;;;   ... повторяется для каждого размера в блоке
;;; ============================================================

(vl-load-com)

(setq *DIMFIX_APP* "DIMFIX_APP")
(if (null *DIMFIX_REACTORS*) (setq *DIMFIX_REACTORS* '()))

;;; ============================================================
;;; БЛОК 1: XDATA на INSERT
;;; ============================================================

(defun DIMFIX_XDATA_REGISTER ()
  (if (null (tblsearch "APPID" *DIMFIX_APP*))
    (entmake (list '(0 . "APPID") (cons 2 *DIMFIX_APP*)))))

;;; Прочитать все записи из XDATA вхождения блока
;;; Возвращает список: (("handle" "преф" "суфф") ...)
(defun DIMFIX_READ_ALL (ins_ent / dxf xdata app_data result
                                  i item h p s)
  (setq dxf   (entget ins_ent (list *DIMFIX_APP*)))
  (setq xdata (assoc -3 dxf))
  (setq result '())
  (if xdata
    (progn
      (setq app_data (cdr (assoc *DIMFIX_APP* (cdr xdata))))
      ;; Пропустить маркер "DIMFIX" и читать тройки
      (setq i 0)
      (while (< i (length app_data))
        (setq item (nth i app_data))
        (if (and (= (car item) 1000)
                 (= (cdr item) "DIMFIX"))
          (progn
            ;; Следующие три: handle, префикс, суффикс
            (if (< (+ i 3) (length app_data))
              (progn
                (setq h (cdr (nth (+ i 1) app_data)))
                (setq p (cdr (nth (+ i 2) app_data)))
                (setq s (cdr (nth (+ i 3) app_data)))
                (setq result (append result (list (list h p s))))
                (setq i (+ i 4)))
              (setq i (1+ i))))
          (setq i (1+ i))))))
  result)

;;; Сохранить запись для конкретного handle в XDATA вхождения
(defun DIMFIX_WRITE_ONE (ins_ent dim_handle pre suf
                         / dxf records new_records found
                           xdata_list rec)
  (DIMFIX_XDATA_REGISTER)
  ;; Прочитать существующие записи
  (setq records (DIMFIX_READ_ALL ins_ent))
  ;; Обновить или добавить запись для этого handle
  (setq found nil)
  (setq new_records
    (mapcar '(lambda (r)
               (if (= (car r) dim_handle)
                 (progn (setq found T) (list dim_handle pre suf))
                 r))
            records))
  (if (null found)
    (setq new_records (append new_records (list (list dim_handle pre suf)))))
  ;; Собрать XDATA список заново
  (setq xdata_list (list *DIMFIX_APP*))
  (foreach rec new_records
    (setq xdata_list
      (append xdata_list
              (list (cons 1000 "DIMFIX")
                    (cons 1000 (nth 0 rec))
                    (cons 1000 (nth 1 rec))
                    (cons 1000 (nth 2 rec))))))
  ;; Записать на INSERT
  (setq dxf (entget ins_ent (list *DIMFIX_APP*)))
  (setq dxf (vl-remove-if '(lambda (x) (= (car x) -3)) dxf))
  (setq dxf (append dxf (list (cons -3 (list xdata_list)))))
  (entmod dxf))

;;; Удалить запись для конкретного handle
(defun DIMFIX_DELETE_ONE (ins_ent dim_handle / dxf records new_records xdata_list rec)
  (setq records (DIMFIX_READ_ALL ins_ent))
  (setq new_records
    (vl-remove-if '(lambda (r) (= (car r) dim_handle)) records))
  (setq dxf (entget ins_ent (list *DIMFIX_APP*)))
  (setq dxf (vl-remove-if '(lambda (x) (= (car x) -3)) dxf))
  (if new_records
    (progn
      (setq xdata_list (list *DIMFIX_APP*))
      (foreach rec new_records
        (setq xdata_list
          (append xdata_list
                  (list (cons 1000 "DIMFIX")
                        (cons 1000 (nth 0 rec))
                        (cons 1000 (nth 1 rec))
                        (cons 1000 (nth 2 rec))))))
      (setq dxf (append dxf (list (cons -3 (list xdata_list)))))))
  (entmod dxf))

;;; Прочитать преф/суфф для конкретного handle из INSERT
(defun DIMFIX_READ_ONE (ins_ent dim_handle / records rec)
  (setq records (DIMFIX_READ_ALL ins_ent))
  (setq rec (assoc dim_handle records))
  (if rec
    (list (cadr rec) (caddr rec))
    nil))

;;; ============================================================
;;; БЛОК 2: ОБНОВЛЕНИЕ ТЕКСТА в *D...
;;; ============================================================

(defun DIMFIX_UPDATE_TEXT (dim_ent pre suf
                           / anon_name anon_def src obj_dxf)
  (setq anon_name (cdr (assoc 2 (entget dim_ent))))
  (if (and anon_name (= (substr anon_name 1 2) "*D"))
    (progn
      (setq anon_def (tblobjname "BLOCK" anon_name))
      (if anon_def
        (progn
          (setq src (entnext anon_def))
          (while (and src
                      (/= (cdr (assoc 0 (entget src))) "ENDBLK"))
            (setq obj_dxf (entget src))
            (if (member (cdr (assoc 0 obj_dxf)) '("TEXT" "MTEXT"))
              (progn
                (entmod (subst (cons 1 (strcat pre "<>" suf))
                               (assoc 1 obj_dxf)
                               obj_dxf))
                (entupd src)))
            (setq src (entnext src))))))))

;;; ============================================================
;;; БЛОК 3: РЕАКТОРЫ на INSERT
;;; ============================================================

(defun DIMFIX_INS_CHANGED_CB (reactor params / ins_ent records dim_ent)
  ;; Реактор на изменение INSERT — восстанавливаем все преф/суфф
  (setq ins_ent (vlr-owner reactor))
  (if (and ins_ent (not (vlax-erased-p ins_ent)))
    (progn
      (setq records (DIMFIX_READ_ALL ins_ent))
      (foreach rec records
        (setq dim_ent (handent (car rec)))
        (if dim_ent
          (progn
            (DIMFIX_UPDATE_TEXT dim_ent (cadr rec) (caddr rec))
            (entupd dim_ent)))))))

(defun DIMFIX_ATTACH_REACTOR (ins_ent / handle reactor)
  (setq handle (cdr (assoc 5 (entget ins_ent))))
  (if (null (assoc handle *DIMFIX_REACTORS*))
    (progn
      (setq reactor
        (vlr-object-reactor
          (list ins_ent)
          *DIMFIX_APP*
          '((:vlr-modified . DIMFIX_INS_CHANGED_CB))))
      (setq *DIMFIX_REACTORS*
            (append *DIMFIX_REACTORS*
                    (list (cons handle reactor)))))))

(defun DIMFIX_DETACH_REACTOR (ins_ent / handle entry reactor)
  (setq handle (cdr (assoc 5 (entget ins_ent))))
  (setq entry  (assoc handle *DIMFIX_REACTORS*))
  (if entry
    (progn
      (setq reactor (cdr entry))
      (vlr-remove reactor)
      (setq *DIMFIX_REACTORS*
            (vl-remove entry *DIMFIX_REACTORS*)))))

;;; ============================================================
;;; БЛОК 4: ВОССТАНОВЛЕНИЕ — ищем INSERT с нашими XDATA
;;; ============================================================

(defun DIMFIX_RESTORE ( / ent dxf records dim_ent)
  (setq *DIMFIX_REACTORS* '())
  (setq ent (entnext))
  (while ent
    (setq dxf (entget ent (list *DIMFIX_APP*)))
    (if (and (= (cdr (assoc 0 dxf)) "INSERT")
             (assoc -3 dxf))
      (progn
        (setq records (DIMFIX_READ_ALL ent))
        (if records
          (progn
            (DIMFIX_ATTACH_REACTOR ent)
            (foreach rec records
              (setq dim_ent (handent (car rec)))
              (if dim_ent
                (progn
                  (DIMFIX_UPDATE_TEXT dim_ent (cadr rec) (caddr rec))
                  (entupd dim_ent))))))))
    (setq ent (entnext ent)))
  (princ))

(defun DIMFIX_ON_OPEN (reactor params)
  (DIMFIX_RESTORE))

(defun DIMFIX_ON_COMMAND_END (reactor params)
  (if (and params (listp params) (car params) (stringp (car params)))
    (if (member (strcase (car params))
                '("REGEN" "REGENALL" "REGENVISIBLE"))
      (DIMFIX_RESTORE))))

(vlr-dwg-reactor    nil '((:vlr-endDwgOpen   . DIMFIX_ON_OPEN)))
(vlr-editor-reactor nil '((:vlr-commandEnded . DIMFIX_ON_COMMAND_END)))

;;; ============================================================
;;; БЛОК 5: ПОИСК БЛИЖАЙШЕГО РАЗМЕРА В БЛОКЕ
;;; ============================================================

(defun DIMFIX_DIST2D (p1 p2)
  (sqrt (+ (expt (- (car p1)  (car p2))  2)
           (expt (- (cadr p1) (cadr p2)) 2))))

(defun DIMFIX_DIM_TEXTPOS (dim_ent / dxf anon_name anon_def src obj_dxf pt)
  (setq dxf       (entget dim_ent))
  (setq anon_name (cdr (assoc 2 dxf)))
  (setq pt nil)
  (if (and anon_name (= (substr anon_name 1 2) "*D"))
    (progn
      (setq anon_def (tblobjname "BLOCK" anon_name))
      (if anon_def
        (progn
          (setq src (entnext anon_def))
          (while (and src
                      (/= (cdr (assoc 0 (entget src))) "ENDBLK"))
            (setq obj_dxf (entget src))
            (if (and (null pt)
                     (member (cdr (assoc 0 obj_dxf)) '("TEXT" "MTEXT")))
              (setq pt (cdr (assoc 10 obj_dxf))))
            (setq src (entnext src)))))))
  (if (null pt)
    (setq pt (cdr (assoc 11 (entget dim_ent)))))
  pt)

(defun DIMFIX_FIND_NEAREST_DIM (blk_name click_pt
                                / blk_def src obj_dxf
                                  best_ent best_dist cur_pt cur_dist)
  (setq blk_def (tblobjname "BLOCK" blk_name))
  (if (null blk_def)
    (progn
      (princ (strcat "\nОшибка: определение блока \""
                     blk_name "\" не найдено."))
      nil)
    (progn
      (setq best_ent nil  best_dist nil)
      (setq src (entnext blk_def))
      (while (and src
                  (/= (cdr (assoc 0 (entget src))) "ENDBLK"))
        (setq obj_dxf (entget src))
        (if (= (cdr (assoc 0 obj_dxf)) "DIMENSION")
          (progn
            (setq cur_pt (DIMFIX_DIM_TEXTPOS src))
            (if cur_pt
              (progn
                (setq cur_dist (DIMFIX_DIST2D click_pt cur_pt))
                (if (or (null best_dist) (< cur_dist best_dist))
                  (progn
                    (setq best_ent  src)
                    (setq best_dist cur_dist)))))))
        (setq src (entnext src)))
      (if (null best_ent)
        (progn
          (princ (strcat "\nОшибка: в блоке \""
                         blk_name "\" не найден ни один DIMENSION."))
          nil)
        best_ent))))

;;; ============================================================
;;; БЛОК 6: ВЫБОР БЛОКА
;;; ============================================================

(defun DIMFIX_GET_DIM_FROM_CLICK ( / sel ins_ent dxf blk_name
                                     click_pt dim_ent)
  (setq sel (entsel "\nКликните на блок с размером: "))
  (if (null sel)
    (progn (princ "\nОтмена.") nil)
    (progn
      (setq ins_ent  (car sel))
      (setq click_pt (cadr sel))
      (setq dxf      (entget ins_ent))
      (if (/= (cdr (assoc 0 dxf)) "INSERT")
        (progn
          (princ (strcat "\nОшибка: выбран объект типа \""
                         (cdr (assoc 0 dxf))
                         "\", нужен блок (INSERT)."))
          nil)
        (progn
          (setq blk_name (cdr (assoc 2 dxf)))
          (setq dim_ent  (DIMFIX_FIND_NEAREST_DIM blk_name click_pt))
          (if (null dim_ent)
            nil
            (progn
              (princ (strcat "\nНайден размер: "
                             (rtos (cdr (assoc 42 (entget dim_ent)))
                                   2 2)))
              (list dim_ent ins_ent))))))))

;;; ============================================================
;;; БЛОК 7: АВТОУСТАНОВКА
;;; ============================================================

(defun DIMFIX_INSTALL ( / lsp_path support_dir acaddoc_path
                          f line found load_line lsp_path_fwd file_dir)
  (setq lsp_path (findfile "dimfix.lsp"))
  (if (null lsp_path)
    (progn
      (setq lsp_path (getfiled "Укажите dimfix.lsp" "" "lsp" 0))
      (if (null lsp_path)
        (progn (princ "\nУстановка отменена.") (exit)))))
  (setq *DIMFIX_LSP_PATH* lsp_path)
  (setq file_dir    (vl-filename-directory lsp_path))
  (setq support_dir (vl-filename-directory (findfile "acad.pat")))
  (if (null support_dir) (setq support_dir file_dir))
  (setq acaddoc_path (strcat support_dir "acaddoc.lsp"))
  (setq lsp_path_fwd (vl-string-subst "/" "\\" lsp_path))
  (setq load_line
    (strcat "(if (findfile \""  lsp_path_fwd
            "\") (load \""     lsp_path_fwd "\"))"))
  (setq found nil)
  (if (findfile acaddoc_path)
    (progn
      (setq f (open acaddoc_path "r"))
      (while (setq line (read-line f))
        (if (vl-string-search "dimfix" line) (setq found T)))
      (close f)))
  (if found
    (princ "\nDimFix уже установлен в acaddoc.lsp.")
    (progn
      (setq f (open acaddoc_path "a"))
      (write-line "" f)
      (write-line ";; === DimFix autoload ===" f)
      (write-line load_line f)
      (close f)
      (princ (strcat "\nУстановлен в: " acaddoc_path))
      (princ "\nПри следующем запуске AutoCAD загрузится автоматически.")))
  (setq cur_paths (getenv "ACAD"))
  (if (null (vl-string-search
              (strcase file_dir)
              (strcase (if cur_paths cur_paths ""))))
    (setenv "ACAD"
            (strcat (if cur_paths cur_paths "") ";" file_dir)))
  (princ))

(if (null *DIMFIX_INSTALLED*)
  (progn
    (DIMFIX_INSTALL)
    (setq *DIMFIX_INSTALLED* T)))

;;; ============================================================
;;; КОМАНДА: SETDIMFIX
;;; ============================================================

(defun c:SETDIMFIX ( / result dim_ent ins_ent dim_handle
                       cur_data cur_pre cur_suf new_pre new_suf)
  (setq result (DIMFIX_GET_DIM_FROM_CLICK))
  (if (null result) (exit))
  (setq dim_ent   (car result))
  (setq ins_ent   (cadr result))
  (setq dim_handle (cdr (assoc 5 (entget dim_ent))))

  (setq cur_data (DIMFIX_READ_ONE ins_ent dim_handle))
  (setq cur_pre  (if cur_data (car  cur_data) ""))
  (setq cur_suf  (if cur_data (cadr cur_data) ""))

  (princ (strcat "\nРазмер: "
                 (rtos (cdr (assoc 42 (entget dim_ent))) 2 2)
                 "  Преф: \""   cur_pre
                 "\"  Суфф: \"" cur_suf "\""))

  (setq new_pre
    (getstring T (strcat "\nПрефикс [" cur_pre
                          "] (Enter = без изменений): ")))
  (setq new_suf
    (getstring T (strcat "\nСуффикс [" cur_suf
                          "] (Enter = без изменений): ")))
  (if (= new_pre "") (setq new_pre cur_pre))
  (if (= new_suf "") (setq new_suf cur_suf))
  (if (and (= new_pre cur_pre) (= new_suf cur_suf))
    (progn (princ "\nИзменений нет.") (exit)))

  ;; Сохранить на INSERT (не на DIMENSION!)
  (DIMFIX_WRITE_ONE   ins_ent dim_handle new_pre new_suf)
  (DIMFIX_ATTACH_REACTOR ins_ent)
  (DIMFIX_UPDATE_TEXT dim_ent new_pre new_suf)
  (entupd dim_ent)
  (princ (strcat "\nГотово! \"" new_pre "<>" new_suf "\""))
  (princ))

;;; ============================================================
;;; КОМАНДА: CLEARDIMFIX
;;; ============================================================

(defun c:CLEARDIMFIX ( / result dim_ent ins_ent dim_handle records)
  (setq result (DIMFIX_GET_DIM_FROM_CLICK))
  (if (null result) (exit))
  (setq dim_ent    (car result))
  (setq ins_ent    (cadr result))
  (setq dim_handle (cdr (assoc 5 (entget dim_ent))))

  (DIMFIX_DELETE_ONE  ins_ent dim_handle)
  (DIMFIX_UPDATE_TEXT dim_ent "" "")
  (entupd dim_ent)

  ;; Если записей больше нет — снять реактор
  (setq records (DIMFIX_READ_ALL ins_ent))
  (if (null records)
    (DIMFIX_DETACH_REACTOR ins_ent))

  (princ "\nПреф/суфф сброшены.")
  (princ))

;;; Восстановить при загрузке если чертёж уже открыт
(if (/= (getvar "DWGNAME") "") (DIMFIX_RESTORE))

(princ "\nDimFix загружен. Команды: SETDIMFIX / CLEARDIMFIX")
(princ)
;;; EOF