일부 사용자에 대해 Autolisp가 블록 속성을 올바르게 설정하지 않음

Dec 29 2020

처음 질문을했기 때문에 문제를 충분히 설명하고 있습니다.

우리 회사에는 동일한 버전의 AutoCAD를 사용하는 여러 개인이 사용하는 Autolisp 코드가 있지만 일부 사용자의 경우 lisp가 올바르게 작동하지 않습니다.

lisp의 기능은 다음과 같습니다.

  • 사용자가 lisp를 실행합니다.
  • 프로그램은 다음 사항을 요구합니다.
    • 블록의 규모
    • 블록의 텍스트 접두사
    • 첫 번째 블록 엔티티의 실행 번호
    • 러닝 숫자의 증가
    • 첫 번째 블록을 배치 할 위치

이것은 마커가있는 블록과 다음 형식 (접두사) (번호가 세 개의 숫자로 구성되지 않은 경우 중간 섹션 가능) (실행중인 번호), 예를 들어 PT001 또는 PX100의 텍스트로 이어져야합니다.

그러나 이렇게하는 대신 일부 사용자는 접두사와 번호가 부족하여 앞서 언급 한 텍스트의 중간 부분 만보기 시작했으며 다른 경우에는 동일한 사용자가 접두사 만 표시되는 것을 경험할 수 있습니다. 마커는 정상적으로 표시되지만 텍스트는 예상대로 작동하지 않습니다.

아래 코드에서 결함을 분석하는 데 도움을 주시면 대단히 감사하겠습니다.

코드가 "완벽한"것처럼 보이면 블록이나 그 속성에 문제가 있다고 가정합니다.

-이자형

(defun c:pointnumber()
(setvar "ATTDIA" 0)
(setq sc (getreal "\nEnter scale: "))
(setq px (getstring "\nSet prefix for point number: "))
(setq nr (getint "\nThe number for the first point: "))
(setq ic (getint "\nIncrement of the number: "))
(setq point 1)
(while (/= point nil)
    (setq point (getpoint "\nChoose a point: "))
    (if (/= point nil)
        (progn
        (setq inr (itoa nr))
        (if (< nr 100) (setq md "0"))
        (if (< nr 10) (setq md "00"))
        (if (> nr 99) (setq md ""))
        (setq ph (strcat px md inr))
        (command "insert" "pointnumber" point sc sc 0 ph)
        (setq nr (+ nr ic))
        )
    )
)
(setvar "ATTDIA" 1)(princ)
)

답변

1 LeeMac Dec 30 2020 at 01:21

현재 코드에는 여러 가지 문제가 있습니다.이 중 일부는 단순히 나쁜 습관으로 간주 될 수 있고, 일부는 사용자가 잘못된 데이터로 응답 할 경우 프로그램이 실패하게하고, 다른 일부는 프로그램에 따라 프로그램이 실패하거나 예기치 않게 작동하도록합니다. 프로그램이 실행되는 AutoCAD 환경의 설정.

1. ATTREQ

설명한 동작의 주된 원인 ATTREQ은 사용자가 INSERT명령의 일부로 속성 값에 대한 프롬프트를 받을지 여부를 결정 하는 시스템 변수 일 수 있습니다 . 경우 ATTREQ=0프로그램이 실행될 때, 블록은 기본 속성 값을 삽입 할 것입니다.

이 시스템 변수의 현재 값을 저장하고 명령 1을 호출 하기 전에 INSERT(속성 프롬프트가 실행되는지 확인하기 위해) 설정 한 다음 명령 다음에 또는 마지막에 원래 값을 복원하여 환경간에 일관된 동작을 보장 할 수 있습니다 . 프로그램.

예를 들면 :

(defun c:test ( / atr )
    (setq atr (getvar 'attreq))
    (setvar 'attreq 1)

    ;; ... Do your thing

    (setvar 'attreq atr)
    (princ)
)

2. OSMODE

AutoLISP를 통해 명령에 점 데이터를 제공하면 점이 제공 될 때 활성화 된 모든 객체 스냅 모드의 영향을받습니다. 나는 여기 에 내 대답에 더 자세히 설명합니다 .

이를 방지하는 가장 쉬운 방법은 "_non"또는 "_none"객체 스냅 수정자를 사용하여 AutoCAD가 후속 점 입력에 대해 모든 객체 스냅 모드를 무시하도록 지시하는 것입니다. 예 :

(command "insert" "pointnumber" "_non" point sc sc 0 ph)

3. 사용자 입력

프로그램 실행 중 오류를 방지하려면 사용자 입력 부족 또는 유효하지 않은 사용자 입력을 고려해야합니다. 이는 if명령문 또는 initget함수를 사용하여 쉽게 달성 할 수 있습니다 . 예 :

(initget 7) ;; Prevents Enter, zero, or negative numbers
(setq sc (getreal "\nEnter scale: "))

또는:

(initget 6)
(if
    (and
        (setq sc (getreal "\nEnter scale: "))
        (setq px (getstring "\nSet prefix for point number: "))
        (setq nr (getint "\nThe number for the first point: "))
        (setq ic (getint "\nIncrement of the number: "))
    )
    ;; ... Do your thing
)

또는 기본 옵션 으로 프롬프트에 대한 튜토리얼에서 설명하는 방법 중 하나를 사용하여 이러한 각 프롬프트에 대한 기본값을 구성 할 수 있습니다 . 예를 들면 다음과 같습니다.

(setq sc (cond ((getreal "\nSpecify scale <1.0>: ")) (1.0)))

4. 지역 변수와 전역 변수

현재 프로그램의 모든 변수는 전역 변수입니다. 즉, 문서 (그리기) 네임 스페이스 내에 정의되고 프로그램 실행이 완료된 후에도 해당 값이 유지됩니다.

Localising Variables 에 대한 자습서에서 설명했듯이 이러한 변수가 다른 프로그램에서 사용하는 전역 변수와 이름을 실수로 공유하거나 프로그램이 루프 내에서 목록 또는 기타 누적 데이터 구조를 구성 할 때 잠재적으로 문제가 발생할 수 있습니다.

프로그램의 올바른 작동을 위해 전역 변수를 사용해야하는 경우가 아니라면 해당 변수를 함수에 로컬로 선언하는 것이 좋습니다. 예 :

(defun c:pointnumber ( / ic inr md nr ph point px sc ) ;; Local variables

    ;; ...

)

5. 블록 존재 여부 확인

INSERT명령에 블록 이름을 직접 제공하면 해당 블록 의 정의가 활성 도면 내에 이미 존재하거나 해당 파일 이름의 도면이 작업 디렉토리 또는 AutoCAD 지원 파일 검색 경로 내에 존재한다고 가정합니다. 조건이 충족되지 않는 경우 INSERT명령은 프로그램 실행 중에 오류가됩니다.

따라서 이러한 조건을 미리 테스트하여 블록을 찾을 수없는 경우 사용자에게 알리고 나머지 작업을 계속 실행할 수 있습니다.

(if
    (or
        (tblsearch "block" "pointnumber") ;; Checks for existing definition
        (findfile "pointnumber.dwg")      ;; Checks for drawing file
    )
    ;; ...
)

cond일련의 if/else식 대신 함수를 사용할 수도 있습니다 .

6. 오류시 환경 재설정

프로그램 실행 중에 시스템 변수 값을 변경하기 때문에 프로그램 실행 중 오류가 발생하는 경우 사용자의 AutoCAD 환경이 원래 상태로 재설정되었는지 확인해야합니다. 사용자가 프로그램 Esc을 종료하기 위해 누르는 경우에도 오류.

오류 처리 자습서에서 설명한대로 로컬 오류 처리기를 정의하여이를 수행 할 수 있습니다 . 프로그램 실행 중에 오류가 발생하면 로컬 오류 함수가 평가되므로이 함수 정의 내에 표현식을 포함하여 AutoCAD 환경을 원래 상태로 재설정 할 수 있습니다.이 경우에는 원래 값을 재설정해야합니다. ATTDIA시스템 변수.

함께 모아서

;; Define function, declare local variables
(defun c:pointnumber ( / *error* bn ic nr ns pt px sc vl vr )

    ;; Define local error function to reset system variables on error
    (defun *error* ( msg )
        (mapcar 'setvar vr vl) ;; Reset list of system variables
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        ) ;; end if
        (princ)
    ) ;; end defun

    ;; Define block name
    (setq bn "pointnumber")

    (if (or (tblsearch "block" bn)        ;; Definition in drawing
            (findfile (strcat bn ".dwg")) ;; Drawing file in support path
        ) ;; end or
        (progn
            (initget 6) ;; Prevents 0 & negatives
            (setq sc (cond ((getreal "\nSpecify scale <1.0>: ")) (1.0))
                  px (getstring "\nSpecify prefix <none>: ")
            ) ;; end setq
            (initget 4) ;; Prevents negatives
            (setq nr (cond ((getint "\nSpecify starting number <1>: ")) (1)))
            (initget 6) ;; Prevents 0 & negatives
            (setq ic (cond ((getint "\nSpecify increment <1>: ")) (1)))

            (setq vr '(attreq attdia cmdecho) ;; List of system variables
                  vl  (mapcar 'getvar vr)     ;; Store current values
            ) ;; end setq
            (mapcar 'setvar vr '(1 0 0)) ;; Set system variables appropriately
            (while (setq pt (getpoint "\nSpecify point <exit>: "))
                (setq ns (itoa nr)
                      nr (+ nr ic)
                )
                (repeat (- 3 (strlen ns)) (setq ns (strcat "0" ns))) ;; Pad to 3 digits
                (command "_.-insert" bn "_S" sc "_R" "0" "_non" pt (strcat px ns))
            ) ;; end while
            (mapcar 'setvar vr vl) ;; Reset list of system variables to their original values
        ) ;; end progn
        ;; Else the block was not defined/found
        (princ (strcat "\nThe block \"" bn "\" is not defined in the active drawing and cannot be found."))
    ) ;; end if
    (princ) ;; Suppress the value returned by the last evaluated expression
) ;; end defun

다음과 같이 구현할 수있는 다른 가능한 개선 사항이 있습니다.

  • INSERTActiveX insertblock메서드 또는 entmake/ entmakex함수를 사용하여 DXF 데이터를 도면 데이터베이스에 직접 작성 하여 표준 AutoCAD 명령 (이 경우 명령) 에 대한 호출에 대한 의존성을 제거 합니다.

  • 블록 참조 내에서 속성 참조가 발견되는 순서에 대한 종속성을 제거하기 위해 속성 태그 이름을 참조하여 속성 채우기 ( BATTMAN명령을 사용하여 도면별로 수정할 수 있음 ).

  • '동적 기본값'(내 튜토리얼 에서 설명 )을 사용하고 잠재적으로 드로잉 세션간에 기본값 값을 저장합니다.