본문 바로가기
autocad

Entity.Auto lisp (펌)

by kmlab 2021. 6. 16.

감사합니다. 다음 블로그의 너울님, VBCAD의 이혁진님.

"다음블로그가 서비스 종료되었습니다." ㅠㅠ;; 애석하게도 아래 너울님의 블로그 링크는 닫혔습니다.

 

Auto lisp 세번째 야그...(펌)

------ 리습강의 (21) ------ ▶ 문자관련 함수 (4) ◀ (substr <문자> <시작위치> [<길이>])     <문자>를 <시작위치>부터 <길이>만큼만 뽑아낸다. 1. 예제   (substr "I am a boy" 3 2)   이렇게 타이핑 해..

blog.daum.net

------ 리습강의 (21) ------

▶ 문자관련 함수 (4) ◀

(substr <문자> <시작위치> [<길이>])

<문자>를 <시작위치>부터 <길이>만큼만 뽑아낸다.

1. 예제

(substr "I am a boy" 3 2)

이렇게 타이핑 해보자..
결과값은 "am" 이다..
위에서 3번째 글자부터 2글자를 취하라는 뜻이므로
"am"이 결과값이 된다. 빈칸도 한자로 처리함을 주의하자.

(substr "I am a boy 6 4) 결과값은 "a bo"

2. 주의사항

<시작위치>와 <길이>를 더한값이 <문자>의 길이를 초과하면
에러가 난다.

(substr "I am a boy" 11 3)

문자의 길이는 10자인데 시작위치가 11이므로
문자길이 10보다 크므로 에러다.

(substr "I am a boy" 8 5)

시작위치 8부터 5자를 취할수 없다.. 8번째 글자는 "b" 인데
"b"부터 3자인 "boy"만 존재하고 4번째, 5번째 글자는 없으므로
에러가 난다.

위에서와 같이 문자를 보면서 하면 에러가 보이지만
문자대신 변수를 써서 리습을 작성하면 에러가 나기 마련이다.
아래와 같이 에러에 대처할 리습을 구성하기 바란다.

3번째 글자부터 5개의 문자를 취하는 리습
선택한 글자가 없으면 "not string" 를 표시한다.

(defun c:test1(/ str len a b c)
(setq str (getstring "\nInput String : ") ;문자를 입력받는다.
len (strlen str) ;문자의 길이
a 3 ;시작위치
b 5 ;취할 문자의 길이
)
(if (< len (+ a b)) (prompt "not string") ; 취할 문자길이를 비교
(setq c (substr str a b))
)
)


------ 리습강의 (22) ------

▶ 시스템 변수 ◀

(getvar <시스템변수>)
(setvar <시스템변수> <변수값>)

<시스템변수> 값을 얻어오거나 변경할때 사용합니다.

1. (getvar)

시스템 변수값을 얻어올때 사용합니다.

(1) 캐드의 명령중에 setvar 를 타이핑해보자
(2) ? 타이핑
(3) * 타이핑

위에처럼 타이핑해보면 현재의 시스템 변수값을 볼수 있다.
그 중에서 어느 한부분 값을 알아볼때 사용하는 명령이다.

<예제>
(getvar "acadver") ;캐드의 버전을 얻어오는 리습
(getvar "osmode") ;현재의 osnap 설정값을 가져오는 리습

2. (setvar)

시스템 변수값을 변경할때 사용한다.
시스템 변수값이 <읽기전용>이 아닌경우 모든 변수값을 변경할 수 있습니다.

<예제>
(setvar "osmode" 0) ;현재의 osnap 설정을 모두 해제한다.
(setvar "dimzin" 8) ;소수점 이하의 0의 표현은 삭제한다.
(setvar "dimzin" 0) ;소수점 이하의 0의 표현을 모두한다

------ 리습강의 (23) ------

▶ Entity(객체)의 갯수 ◀

(sslength <선택그룹>)

<선택그룹> 의 존재하는 객체의 갯수를 표시

1. (sslength)

사용자로 하여금 어떤 객체를 선택하게 한후
그 객체의 갯수를 알고자 할때 사용하는 함수다.

2. 예제

(defun c:test1(/ ent n)
(setq ent (ssget)) ; 객체 선택 요구
(setq n (sslength ent)) ; 선택 객체 갯수
(prompt "Entity numbers #") ; "Entity numbers #" 화면에 출력
(princ n) ; 선택 갯수를 화면에 출력
(princ)
)

3. 응용

이 함수는 (repeat) (while) 문등과 함께 객체의 수만큼 반복할때
많이 사용될 함수이다.
강의 30회가 넘어가면 실전예제에서 빈번하게 사용되므로
그때 다시한번 익혀보자.

------ 리습강의 (24) ------

▶ 객체의 특정속성 변경 (1) ◀

글자의 크기, 글자의 폭, 글자의 스타일, 라인의 시작(끝)위치, 폴리라인의 두께등
객체의 특정부분을 변경하고자 할때 사용하는 함수들이다.
이 함수들을 아예 한 셋트로 기억하기 바란다.
다음 함수들은 꼭 어울려서 사용되기 때문에 초보자들이라면
우선 암기해 두고 천천히 이해하기 바란다.

(setq var (entget (ssname e i))
old (assoc 41 var)
new (cons 41 tw)
chg (subst new old var)
)
(entmod chg)

1. (ssname <객체그룹> <객체번호>)

<객체그룹>에서 <객체번호>의 객체이름을 알려준다.
객체를 선택하면 0번부터 객체갯수만큼의 번호가 주어진다.
캐드화면에 무언가를 그리거나 쓴다음 다음 예제를 해보자

(defun c:test1(/ a b)
(setq a (ssget)) ;객체를 선택하도록 요구 -> a
(setq b (ssname a 0)) ;객체중 0번째의 객체이름 -> b
)

위에서 객체를 여러개 선택하였으면 숫자 0 을 1 , 2 , 3 ...
등으로 바꾸어 가면서 실행해 보자.

2. (entget <객체이름>)

<객체이름>의 각 속성등을 알려준다.

(defun c:test2(/ a b c)
(setq a (ssget))
(setq b (ssname a 0))
(setq c (entget b))
)

위에서도 객체를 여러개 선택하면 숫자 0 을 1 , 2 , 3 ...
등으로 바꾸어 가면서 실행해 보자.

다음 예제는 객체 한개만을 선택하여 객체 속성을 알아보는 리습이다.
(entsel)명령은 [Entity name]과 [위치]를 그대로 반환하므로 (ssname) 명령이 필요없다.
명령어를 info 로 정의한것은 앞으로 빈번히 사용될 리습이기 때문이다.
앞으로 거론될 dxf 코드를 알기 위해서도 꼭 필요한 리습이다.

(defun c:info(/ ent dxf)
(setq ent (entsel))
(setq dxf (entget (car ent)))
)

위에서 (car ent) 란?
캐드화면에서 그냥 (entsel) 이라고 한번 타이핑해보고 객체하나를
선택해보라. 그러면 응답값이 entity name 하고 point 인걸 확인할 수 있다.
ent 가 변수이기 때문에 (car (entsel)) 과 같은 말이다.
(entsel) 명령은 entity name 과 선택한 포인트를 리스트 형태로
반환한다. 따라서 entity name 만을 얻으려면
(car (entsel))명령으로 쉽게 구할수 있다


------ 리습강의 (25) ------

▶ 객체의 특정속성 변경 (2) ◀

글자의 크기, 글자의 폭, 글자의 스타일, 라인의 시작(끝)위치, 폴리라인의 두께등
객체의 특정부분을 변경하고자 할때 사용하는 함수들이다.
이 함수들을 아예 한 셋트로 기억하기 바란다.
다음 함수들은 꼭 어울려서 사용되기 때문에 초보자들이라면
우선 암기해 두고 천천히 이해하기 바란다.

(setq var (entget (ssname e i))
old (assoc 41 var)
new (cons 41 tw)
chg (subst new old var)
)
(entmod chg)

1. DXF코드란?

앞선 리습강의에서 info 리습을 만들어 보았다.
캐드에서 글자크기 3, 글자내용 "test" 라는 텍스트를 하나 작성하고
info 를 실행해서 그 글자 하나를 선택해 보자.
그러면 아래와 같이 나올것이다. (폰트와 좌표는 다르게 나타날 수 있음)

((-1 . ) (0 . "TEXT") (5 . "20") (100 .
"AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbText") (10 . 121.584 158.415 0.0)
(40 . 3.0) (1 . "test") (50 . 0.0) (41 . 1.0) (51 . 0.0) (7 . "STANDARD") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (100 . "AcDbText") (73 . 0))

여기서 중요한것 몇가지만 살펴보겠다.

(-1 . ) ; 객체 이름
(0 . "TEXT") ; 객체 종류
(10 . 121.584 158.415 0.0) ; 글자의 x,y,z 좌표
(1 . "test") ; 글자의 내용
(40 . 3.0) ; 글자의 크기
(41 . 1.0) ; 글자의 폭
(7 . "STANDARD") ; 글자폰트 스타일

이런것들이 있다. 이것을 DXF CODE 라 하고
다른 성분들도 다양하게 변경하면서 info 리습으로 찍어보면
내용을 쉽게 알 수 있을 것이다.

괄호()안의 첫번째 숫자가 <코드번호>라 칭하고 그 다음 점(.)뒤의
내용을 <코드내용>으로 칭하자.
항상 괄호와 내용 사이에 점이 존재함을 눈여겨 보자.

2. (assoc <코드번호> )

(entget)으로 구해진 값들 (위에 지저분하게 나열된 리스트들) 중에서
원하는 <코드번호>의 값을 얻어오는 함수이다.

앞에서 설명한 info 리습을 이용해서 지금 선택한 객체의 종류를
알아내는 리습을 만들어 보자

(defun c:test1(/ ent dxf)
(setq ent (entsel))
(setq dxf (entget (car ent)))
(setq name1 (assoc 0 dxf))
(setq name2 (cdr name1))
)

위의 리습을 실행하고 만약 글자를 찍어보면
name1 = (0 . "TEXT")
name2 = "TEXT"
의 값을 가진다.

객체의 종류는 코드번호 0 번이므로 (assoc 0 dxf)를 사용했다.
리스트객체이기 때문에 (cdr) 함수를 사용하여 코드내용만을 발췌했다.
이 리습을 실행하고 원, 선, 글자등을 찍어보면
그 종류를 알 수 있다.

아래는 만약 글자를 선택하였으면 글자의 크기를 알아내는 리습이다.

(defun c:test2(/ ent dxf name th)
(setq ent (entsel))
(setq dxf (entget (car ent)))
(setq name (cdr (assoc 0 dxf))) ; 종류를 알아내는 부분
(if (= name "TEXT") (setq th (cdr (assoc 40 dxf))))
(prompt "\nText Height = ")
(princ th)
(princ)
)

3. (cons <코드번호> <코드내용>)

이 함수는 위의 dxf code 형태로 만들어 주는 함수다.
(list) 함수와 비슷하지만 가운데 점이 있는 dxf code 형태로 된다는 점이
다른 내용이다.
예를 통해서 쉽게 알아보자

(cons 0 "TEXT") -> (0 . "TEXT")
(cons "123" "345") -> ("123" . "345")
(cons 41 2) -> (41 . 2)



------ 리습강의 (26) ------

▶ 객체의 특정속성 변경 (3) ◀

글자의 크기, 글자의 폭, 글자의 스타일, 라인의 시작(끝)위치, 폴리라인의 두께등
객체의 특정부분을 변경하고자 할때 사용하는 함수들이다.
이 함수들을 아예 한 셋트로 기억하기 바란다.
다음 함수들은 꼭 어울려서 사용되기 때문에 초보자들이라면
우선 암기해 두고 천천히 이해하기 바란다.

(setq var (entget (ssname e i))
old (assoc 41 var)
new (cons 41 tw)
chg (subst new old var)
)
(entmod chg)

1. (subst <신코드> <구코드> )

에서 특정 DXF코드를 변경하고 싶을때
<구코드>를 <신코드>로 바꾸는 명령입니다.

예를 들어서 글자크기를 변경할때 글자크기를 3.456이라고 가정하면
DXF코드는 (40 . 3.456) 입니다.
이걸 글자크기 5.678로 바꾸려면

(setq old (cons 40 3.456))
(setq new (cons 40 5.678))
(setq chg (subst new old var)

이런식으로 하면 됩니다. 여기서 var 은 entget 된 객체입니다.
리습강의 (27) 부터는 실전예제를 통한 강의가 있을겁니다.
그때 한번더 이해하시기 바랍니다.

2. (entmod)

DXF코드를 (subst)로 갱신하거나, 새로운 객체가 포함, 삭제되면
캐드명령어 regen, redraw 처럼 변경된 사항을 적용, 갱신하라는
뜻입니다.
캐드도 데이터베이스(DB) 개념입니다.
각 코드를 데이터화하여 저장, 생성, 재생시킵니다.
(entmod)가 각 데이터를 갱신함으로서, 비로서 눈으로 변경된 사항을
보실수 있는것입니다.

<끝으로...>
객체의 특정속성변경(1~3)까지는 어느정도만 이해하시고
위의 구문을 그냥 한셋트처럼 보아 두십시오.
항상 같이 붙어 다니니까.. 예제강의를 보시면
이해 안되던 부분도 쉽게 파악 될것입니다.

3. !!중요 명령들을 끝내며..

이제...중요 명령들의 강의는 마치겠습니다.
나머지 명령들은 실전예제를 통해서 간간히 나오면 그때마다
설명하겠습니다.
장기간에 걸쳐서 읽어 주셔서 감사하고,
지금부터가 중요합니다. 실무에 적용할 수 있는 예제를 중심으로
리습강의를 하고, 그 강의를 보시면,
다른 사람이 짜놓은 리습을 자기 실무에 변경하여 사용하기에는
어렵지 않을것입니다.
간단한 리습구현도 쉽게 될 것이구요.
그럼 27회에서 다시뵙죠...^^


----리습강의(27)실습예제*글자의 크기를 바꾸어보자

(defun c:ts (/ e ts n i var old new chg)
(setq e (ssget)
ts (getreal "Enter new text height : ")
n (sslength e)
i 0
)

(repeat n
(setq var (entget (ssname e i))
old (assoc 40 var)
new (cons 40 ts)
chg (subst new old var)
)
(entmod chg)
(setq i (1+ i))
)
(princ))


[사용방법]
1. 리습의 load
2. ts(엔터) - 이 리습의 작동 명령은 ts 입니다.
3. 캐드 화면상의 글자선택
4. 글자크기 입력

[설 명]
글자크기를 변경하는 리습입니다.
이 리습은 글자만 선택해야 에러가 나지 않습니다.
리습강의(28) 에서는 다른것을 선택했을때의 처리방법을 기술하겠습니다.
아래는 한줄씩 내용을 설명한 것입니다.

(setq e (ssget) ;객체를 선택하도록 합니다.
ts (getreal "Enter new text height : ") ;화면에 "Enter new text height" 라고 메세지를 보내며, 숫자(real)입력을 받아들입니다.
n (sslength e) ;선택된 객체의 갯수를 알아냅니다.
i 0 ;반복문을 사용하기 위해서 변수값을 0으로 초기화합니다.
)

(repeat n ;선택된 객체의 수 만큼 반복합니다.

(setq var (entget (ssname e i)) ;객체의 성분(DXF CODE)을 알아냅니다.
old (assoc 40 var) ;글자크기는 코드번호 40입니다. 글자크기 성분만 알아냅니다.
new (cons 40 ts) ;사용자가 입력한 크기를 코드번호 40으로 DXF 코드화 합니다.
chg (subst new old var) ;성분을 새로운 코드로 교체합니다.
)
(entmod chg) ;갱신명령
(setq i (1+ i)) ;다음 객체를 선택하기 위해서 반복값(i)를 1만큼 증가합니다.
) ;반복(repeat)의 끝입니다.

 

리습강의 (28) ***실전예제(2) 숫자의 합을 구해보자 ***

연말이라 저도 좀 바쁘네요..
강의 올리는 빈도가 적어지는데..이해들 해주세요..!!
그리고, 시간 좀 되시는 분.. 강의를 모아서 올려주시면 감사..^^

화면에 써놓은 숫자들의 합을 구하여 화면상에 글자로 써주는
리습을 만들어 보겠다.

(defun c:sum (/ e Pnt n i var)
(setq e (ssget '((-4 . "")))
Pnt (getPoint "\nPick Point : ")
th (getdist "\nText Height : ")
n (sslength e)
i 0
sum 0
)

(repeat n
(setq var (entget (ssname e i))
num1 (assoc 1 var)
num2 (cdr num1)
num3 (atof num2)
sum (+ sum num3)
i (1+ i)
)
)
(setq sumtext (rtos sum))
(command "text" pnt th "0" sumtext)
(princ))

<설명>

(setq e (ssget ~ ) : TEXT or MTEXT 만을 식별하여 선택함
pnt (getPoint ~ ) : 숫자의 합을 표시할 위치 지정
th (getdist ~ ) : 합을 표시할 글자의 크기 입력
(getdist)대시 (getreal)을 써도 좋다
num1 (assoc 1 var) : 글자의 내용은 DXF CODE 1 번이다
num2 (cdr num1) : (1 . "내용") 에서 "내용"만을 끄집어 낸다
num3 (atof num2) : num2의 내용은 문자이다. 문자를 실수로 변경

위에서 초보를 위해 이해하기 쉽게 num1 num2 num3 로 나누었으나,
num3 (atof (cdr (assoc 1 var)))
이렇게 한줄로 표현할 수 있다.

(setq sumtext (rtos sum)) : 숫자를 글자로 바꾸는 (rtos) 인데
(rtos sum 옵션1 옵션2) 에서
옵션1,2가 생략되면 캐드의 units로 설정된 상태로
결과값이 표시된다.

(command "text" pnt th "0" sumtext) : 글자를 써주는데 각도는 "0"으로 지정했다.

리습강의 (29) ***실전예제(3) 선들의 길이를 구해보자 ***

조금은 중급정도의 예제일지는 몰라도
너무 쉬운 강의를 하면 지루할것 같아서요,
이정도는 해야겠다 싶어서 올립니다.
초보분들은 예제가 너무 어려우시면 말씀하세요..

이번에는 캐드상의 라인의 길이를 알아보는 리습을 제작해보자.

<사용방법>
선을 사용자가 선택하게 하고, 화면상에 쓰여질 글자크기,
글자각도를 입력하면 각선의 길이를 자동으로 화면에 써주는거다.
명령어는 le

<리습흐름>

1. LINE 만을 선택하게 한다.
2. 시작점(start)과 끝점(end)의 좌표를 구한다.
3. 시작점의 좌표를 (x1,y1) 이라고 하고 끝점의 좌표를 (x2,y2)라 한다.
4. X간의거리 x1-x2 를 dx라 칭하고, y간의 거리 y1-y1를 dy 로 칭한다.
5. 선의 길이는 √(dx²+dy²)로 구하고 변수 len 이라고 칭한다.
6. 선의 길이를 시작점(start)에 글자로 써준다.
7. 각선에 대해서 반복하여 실행한다.

<리습소스>

(defun c:le(/ e h r n i x1 y1 dx len)

(setq e (ssget '((0 . "LINE"))) ;선들만 선택
h (getdist "\nText Height : ") ;글자크기 입력
r (getreal "\nText rotate : ") ;글자각도 입력
n (sslength e) ;현재 선택되어진 객체 갯수
i 0 ;반복변수 '0'으로 셋팅
)

(repeat n
(setq var (entget (ssname e i)) ;선택객체 DXF 가져오기
start (assoc 10 var) ;시작점의 성분
end (assoc 11 var) ;끝점의 성분
x1 (cadr start) ;x1의 값
x2 (cadr end) ;x2의 값
y1 (caddr start) ;y1의 값
y2 (caddr end) ;y2의 값
dx (- x2 x1) ;x간의 거리
dy (- y2 y1) ;y간의 거리
len (sqrt (+ (* dx dx) (* dy dy))) ;두 점의 거리
)
(command "text" (cdr start) h r (rtos len)) ;화면상에 글자쓰기
(setq i (1+ i)) ;반복변수 +1
)
(princ))

<주의사항>
이 리습은 osnap 이 꺼져 있어야 한다.
osnap이 on 되어 있으면 결과값이 다르게 나타난다.
osnap을 자동으로 off 시키려면
(command "osnap" "none")을 시작부에 추가시키면 된다.

이 내용을 노트패드에서 복사해서 보면 줄이 잘 맞추어 보인다.



리습강의 (30) ***실전예제(4) 좌표를 화면에 글자로 출력***

가끔 좌표를 구할때가 있다. 캐드명령으로는 ID 인데
텍스트창에만 보이고, 그 좌표를 도면에 표시하려면
글자를 다시 써주어야 하는 불편함이 있다.
이 불편함을 한번 해소해 보려 한다.

<사용방법>
명령어는 ID2, 화면상에 한점을 찍으면 좌표를 찍은점에 써준다.

<리습소스>
(defun c:id2(/ sf p x y osmode th)
(setq osmode (getvar "osmode"))
(setq p (getpoint "\nPick Point : "))
(setq th 3)
(while (/= p nil)
(setvar "osmode" 0)
(setq x (rtos (car p) 2))
(setq y (rtos (cadr p) 2))
(command "text" p th "0" (strcat "X:" x))
(command "text" (list (car p) (- (cadr p) th)) th "0" (strcat "Y:" y))
(setvar "osmode" osmode)
(setq p (getpoint "\nPick Point : "))
)
(princ))

<내용분석>
(setq osmode (getvar "osmode"))
현재 사용자가 지정해둔 osnap 형태를 osmode라는 변수에 기억하고 있는다.

(setq p (getpoint "\nPick Point : "))
사용자가 좌표를 알고싶은 점을 선택하게 하여 변수 p 에 저장

(setq th 3)
입력받게 하면 귀찮을 수도 있으므로 글자크기는 일단 3으로 했다.
사용자가 나중에 원하는 크기로 변경하기 바란다.
글자크기 3을 변수 th에 저장

(while (/= p nil)
만일 선택한점이 없다면 (그냥 스페이스나 엔터를 쳐버리면)
리습을 종료하고, 점이 선택되어지면 반복

(setvar "osmode" 0)
osnap 을 none 상태로 만들어 준다.

(setq x (rtos (car p) 2))
점 p 의 X좌표를 변수 x 에 저장
rtos 에 대해서는 리습강의를 참조바람. 현재는 units 명령에 의한
소숫점 자리수까지 표현한다.

(setq y (rtos (cadr p) 2))
점 p 의 Y좌표를 변수 y 에 저장

(command "text" p th "0" (strcat "X:" x))
x 좌표를 p 위치에 글자로 작성
(strcat "X:" x) 란 글자"X:" 와 x 좌표를 묶어 주는 명령이다.

(command "text" (list (car p) (- (cadr p) th)) th "0" (strcat "Y:" y))
y 좌표를 (p의 x좌표, p의 y좌표 - 글자크기) 위치에 글자로 작성
(- (cadr p) th)를 (- y (cadr p) 1)정도로 하면 한결 보기 좋을 것이다.
작성자가 위치를 조정하기 바란다.

(setvar "osmode" osmode)
사용자가 처음 작성한 osnap 형태로 다시 환원

(setq p (getpoint "\nPick Point : "))
다음 좌표를 선택할 수 있게 한다.

<참고사항>

토목에서는 x와 y 좌표가 바뀌어져 있다.
이럴땐
(setq x (rtos (car p) 2))
(setq y (rtos (cadr p) 2))

이 부분을
(setq y (rtos (car p) 2))
(setq x (rtos (cadr p) 2))

위처럼 x y 변수값을 서로 바꾸어 주면된다.



출처 : 이혁진의 VBCAD

 

이혁진의 VBCAD

 

vbcad.co.kr

 

반응형

'autocad' 카테고리의 다른 글

List x-values of Vertex of LWPOLYLINE  (0) 2021.06.30
Autodesk DXF Entities Section  (0) 2021.06.29
Update sheet; xr, -la s 0, pu, pdf, saveas 2000, Close  (0) 2021.04.06
PDF 자동출력  (0) 2021.04.06
Overkill  (0) 2021.04.05