AutoLISP 강좌 [4]


1. 입문(I) - AutoLISP의 기본 개념
2. 입문(II) - 사용자 정의 함수 제작
3. 입문(III) - 그 밖의 기본 기능들
4. 응용(I) - Entity와 Selection-Set
5. 응용(II) - Symbol table과 Device 제어
6. 응용(III) - Dialogue box 제어
7. 활용예제


4. Entity와 Selection-Set

4.1 기본적인 entity 처리

이번에는 entity와 selection-set 조작 함수를 사용하여 이미 그려진 선을 선택한 후 OFFSET하는 프로그램을 작성해 보겠다. 먼저, 선을 그려보자.

Command: LINE
From point: 1,1
To point: 2,2
To point:

그럼, 이제 그 선이 어떤 형태로 AutoCAD의 도면 데이타 베이스내에 저장되어 있는지 알아보자. 그러기 위해서 ENTSEL 함수를 사용하여 다음과 같이 entity를 선택한다.

Command: (setq ent (entsel))
Select object: 1.5,1.5 <= 중심점을 선택한다.
(<Entity name: XXXXXXXX> (1.5 1.5 0.0))

위의 과정을 통해서 얻을 수 있는 것은 각각의 도면요소가 가지는 번호와 선택할 때 사용된 좌표점이다. 번호는 그 도면요소에 대한 정보를 알아낼 때 사용되는 중요한 사항이며 좌표점 또한 유용하게 사용되는 사항이다. 이제, ENTSEL 함수를 통해 얻어낸 도면요소의 번호를 사용하여 도면요소에 대한 정보를 알아내 보자.

Command : (setq elist (entget (car ent)))
((-1 . <Entity name: XXXXXXXX>) <= 도면요소의 이름
 (0 . "LINE") <= 도면요소의 종류
 (8 . "0") <= 존재하는 레이어명
 (10 1.0 1.0 0.0) <= 선의 시작점
 (11 2.0 2.0 0.0) <= 선의 끝점
 (210 0.0 0.0 1.0)) <= UCS의 Z축의 방향

위와 같은 정보는 AutoCAD의 도면 데이타 베이스내에 저장되어 있는데 각각의 정보앞에 나오는 정보코드는 각 정보가 무엇을 뜻하는 지를 알려준다.

범위 자료형
0 - 9 문자열(string)
10 - 59 실수(float)
60 - 79 정수(int)
140 - 175 실수
170 - 175 정수
210 - 239 실수
999 주석(문자열)
1000 - 1009 문자열
1010 - 1059 실수
1060 - 1079 정수

표 1. 코드의 범위와 자료형

0 도면요소의 종류
5 도면요소 핸들(handle)
6 선의 종류
7 문자 스타일 이름
8 레이어 이름
38 높이(elevation)
39 두께(thickness)
62
67 0이면 모델 스페이스
210 UCS의 Z축의 방향
999 주석
1000~ 확장 도면요소에 관한 자료

표 2. 고정적인 DXF 코드

LINE 10 시작점
  11 끝점
POINT 10 점의 위치
CIRCLE 10 중심점
  40 반경
ARC 10 중심점
  40 반경
  50 시작각
  51 끝각
TRACE 10, 11, 12, 13 4개의 모서리점
SOLID 10, 11, 12, 13 4개의 모서리점
TEXT 10 위치
  40 높이
  1 문자열 내용
  50 회전각
  51 기운각
  7 문자열 스타일
  71 방향
  72 수평 정렬 형식
  73 수직 정렬 형식
  11 정렬 좌표점
SHAPE 10 위치
  40 크기
  2 쉐이프 이름
  50 회전각
  41 X, Y 스케일
  51 기운각
INSERT 66 attribute 관련 flag
  2 블럭 이름
  10 위치
  41 X 스케일
  42 Y 스케일
  43 Z 스케일
  50 회전각
  70 열의 수
  71 행의 수
  44 열의 간격
  45 행의 간격
POLYLINE 66 vertex 존재 flag
  10 polyline의 높이
  70 polyline 종류 flag
  40 시작 두께
  41 끝 두께
  71 polygon mesh의 M vertex 수
  72 polygon mesh의 N vertex 수
  73 smooth surface의 M 밀도
  74 smooth surface의 N 밀도
  75 curve와 smooth surface의 종류
VERTEX 10 위치
  40 시작 두께
  41 끝 두께
  42 arc 구간의 내각의 1/4의 tangent
  70 vertex flag
  50 curve fit 접선 방향
SEQEND 필드 없음. POLYLINE VERTEX의 끝을 나타냄.
3DFACE 10, 11, 12, 13 4개의 모서리점

표 3. 중요 도면요소에 대한 DXF 코드

(그 밖의 DXF 코드값이나 보다 자세한 의미는 매뉴얼을 참고하시기 바랍니다.)

그럼, 위에서 얻은 도면요소에 관한 정보와 DXF 코드 표를 참조하여 선의 시작점과 끝점을 알아내보자.

Command: (setq sp (assoc 10 elist))
(10 1.0 1.0 0.0)
Command: (setq ep (assoc 11 elist))
(11 2.0 2.0 0.0)

위와 같이 ASSOC 함수를 사용하면 주어진 항목에 해당하는 리스트를 찾아서 그 리스트 전체를 반환한다. 다만, 여기서 우리에게 필요한 것은 코드 이후의 좌표값만이므로 다음과 같이 CDR 함수를 사용하여 좌표값만을 얻어낸다.

Command: (setq sp (cdr sp))
(1.0 1.0 0.0)

우리가 이번에 만들고자 하는 프로그램에서는 선의 시작점과 끝점만을 알면되므로 다음과 같이 선택된 선의 시작점과 끝점만을 알려주는 함수를 다음과 같이 제작하였다

(defun p-line (en)
  (setq en (entget en))
  (list (cdr (assoc 10 en))
        (cdr (assoc 11 en))
  )
)

먼저, 위의 함수가 정상적으로 작동하는지 확인해 보자.

Command: (p-line (car (entsel)))
Select object: 1.5,1.5
((1.0 1.0 0.0) (2.0 2.0 0.0))

정상적으로 작동한다면 다음과 같이 간단히 이번 프로그램을 완성해 보자.

(defun draw-offline (po off / ang dis sp ep)
  (setq ang (angle (car po) (cadr po)))
  (setq dis (distance (car po) (cadr po)))
  (setq sp (polar (car po) (+ ang (/ PI 2.0)) off))
  (setq ep (polar sp ang dis))
  (command "LINE" sp ep "")
  (setq sp (polar (car po) (- ang (/ PI 2.0)) off))
  (setq ep (polar sp ang dis))
  (command "LINE" sp ep "")
)

(defun draw-offset (en off / ename)
 (setq ename (cdr (assoc 0 (entget (car en)))))
 (cond ((= "LINE" ename) (draw-offline (p-line (car en)) off))
       (T (princ "\nIt is not a line."))
 )
)

(defun C:OLINE ( / en)
  (setq *OFFSET* 1.0)
  (setq en (entsel))
  (draw-offset en *OFFSET*)
  (princ)
)

프로그램이 완성되었으면 앞서 그린 선을 이용하여 다음과 같이 수행해 보자.

Command: OLINE
Select object: 1.5,1.5

4.2 다중 entity 처리

이제 앞서 제작한 프로그램으로 POLYLINE도 처리할 수 있도록 수정해 보겠다. 먼저, POLYLINE 하나를 그려서 앞에서와 같은 방법으로 분석해 보자.

Command: PLINE
From point: 3,3
Current line-width is 0.0000
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: 5,3
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: 5,5
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: 3,5
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: C

이번에는 새로 그린 POLYLINE이 도면상에 맨 마지막으로 그려진 도면요소라는 점을 이용하여 다음과 같이 도면요소의 이름을 얻어냈다.

Command: (setq ent (entlast))
<Entity name: XXXXXXXX>

그리고, 앞서와 같은 방법으로 도면요소의 정보를 알아낸다.

Command: (setq elist (entget ent))
((-1 . <Entity name: XXXXXXXX>)
 (0 . "POLYLINE")
 (8 . "0")
 (66 . 1)
 (10 0.0 0.0 0.0)
 (70 . 1) <= closed polyline
 (40 . 0.0)
 (41 . 0.0)
 (210 0.0 0.0 1.0)
 (71 . 0)
 (72 . 0)
 (73 . 0)
 (74 . 0)
 (75 . 0))

그러나, 위와 같이 POLYLINE 자체에는 각 정점(vertex)에 대한 자료는 담고 있지 않다. 이들 각 정점에 대한 자료는 각각의 sub entity에 저장되어 있으며 그것은 다음과 같이 구해낼 수 있다.

Command: (setq ent (entnext ent))
<Entity name: XXXXXXXX>

첫번째 정점의 부 도면요소의 이름을 얻어낸다.

Command: (setq elist (entget ent))
((-1 . <Entity name: XXXXXXXX>)
 (0 . "VERTEX")
 (8 . "0")
 (10 3.0 3.0 0.0) <= 정점의 좌표값
 (40 . 0.0)
 (41 . 0.0)
 (42 . 0.0)
 (70 . 0)
 (50 . 0.0)
 (71 . 0)
 (72 . 0)
 (73 . 0)
 (74 . 0))
Command: (setq ent (entnext ent))
Command: (setq ent (entnext ent))
Command: (setq ent (entnext ent))
Command: (setq ent (entnext ent))
Command: (setq elist (entget ent))
((-1 . <Entity name: XXXXXXXX)
 (0 . "SEQEND")
 (8 . "0")
 (-2 . <Entity name: XXXXXXXX)) <= main entity의 이름

이상과 같이 SEQEND가 나올때까지 VERTEX의 좌표값을 얻어내는 과정을 되풀이하는 함수를 작성해 두면 편리하다.

(defun p-pline (en / po)
  (setq en (entnext en))
  (while (/= (cdr (assoc 0 (entget en))) "SEQEND")
    (setq po (append po (list (cdr (assoc 10 (entget en))))))
    (setq en (entnext en))
  )
  po
)

이 함수를 위에서 그린 POLYLINE에 사용해 보면 다음과 같은 결과를 얻을 수 있다.

Command: (p-pline (entlast))
((3.0 3.0 0.0) (5.0 3.0 0.0) (5.0 5.0 0.0) (3.0 5.0 0.0))

즉, POLYLINE 상의 모든 vertex의 좌표값을 하나의 리스트로 반환한다. 그러나, 이것은 각 구간이 직선인지 호인지를 알 수 없고 이런 POLYLINE에 대해 일반적인 OFFSET 함수를 제작하는 것이 간단하지 않으므로 이번 예제에서는 이들 좌표중 앞에 있는 두개만을 사용하고 기존의 OFFSET 명령을 사용하여 간단하게 구현해 보고자 한다.

OFFSET 명령에는 두가지 수행방식이 있다. 첫번째는 물체를 선택한 후에 그 물체가 OFFSET되어 지나갈 점을 지정하는 방식이고 두번째는 OFFSET 간격을 지정한 후에 물체를 선택하고 OFFSET 방향을 지정하는 방식이다. 이번 경우에는 POLYLINE의 처음 두 점을 이용하여 OFFSET되어 지나갈 두점을 알아낼 수 있으므로 첫번째 방식을 이용하기로 하겠다. 앞에서 선을 OFFSET하던 함수를 응용하여 POLYLINE의 OFFSET 함수를 완성해 보자.

(defun draw-offpline (en po off / ang dis sp1 sp2)
  (setq ang (angel (car po) (cadr po)))
  (setq dis (distance (car po) (cadr po)))
  (setq sp1 (polar (car po) (+ ang (/ PI 2.0)) off))
  (setq sp2 (polar (car po) (- ang (/ PI 2.0)) off))
  (command "OFFSET" "T" en sp1 en sp2 "")
)

(defun draw-offset (en off / ename)
  (setq ename (cdr (assoc 0 (entget (car en)))))
  (cond ((= "LINE" ename) (draw-offline (p-line (car en)) off))
        (( = "POLYLINE" ename) (draw-offpline en (p-pline (car en)) off))
        (T (princ "\nIt is not a line or a polyline."))
  )
)

위와 같이 앞서 제작했던 draw-offset 함수에도 POLYLINE 처리부분을 추가해 주기 바란다.

4.3 Selection-Set 처리

마지막으로 이제까지 작성한 프로그램을 하나의 도면요소가 아닌 여러개의 도면요소의 묶음인 SELECTION-SET을 처리할 수 있도록 확장시켜 보겠다.

SELECTION-SET을 만들때는 SSGET 함수를 사용하는데 이 함수에는 미리 옵션을 주어서 도면요소를 선택하게 할 수도 있고 "Select objects: " 문장을 출력한 후 사용자가 도면요소를 선택하게 할 수도 있는데 이 경우에는 AutoCAD 명령상에서 사용하던 "C", "L", "P", "W" 등의 옵션을 사용하여 손쉽게 도면요소를 선택할 수 있다.

현재 도면 상의 모든 도면요소를 지운 후에 다음과 같이 몇개의 도면요소를 그려보자.

Command: LINE
From point: 1,1
To point: 7,1
To point:
Command: PLINE
From point: 4,2
Current line-width is 0.0000
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: 4,6
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>: 8,6
Arc/Close/Halfwidth/Length/Undo/Width/<Endpoint 
of line>:
Command: CIRCLE
3P/2P/TTR/<Center point>: 11,6
Diameter/<Radius>: 2
Command: ARC
Center/<Start point>: C
Center: 11,1
Start point: 13,1
Angle/Length of chord/<End point>: 
9,1

이제 방금 그린 도면요소들을 하나의 SELECTION-SET으로 묶기위해 SSGET 함수를 사용해 보자.

Command: (setq ss (ssget))
Select objects: C
First corner : 0,0
Other corner : 14,9
4 found
Select objects:
<Selection set: X>

위와 같이 하나로 묶인 SELECTION-SET에서 하나의 도면요소를 추출해 내기 위해서 SSNAME 함수를 사용하게 되는데 이 때 필요한 것이 몇개의 도면요소가 포함되어있는가를 알아보기 위한 SSLENGTH 함수이다. 다음을 보자.

Command: (sslength ss)
4
Command: (entget (ssname ss 0))
<<< POLYLINE에 관한 정보>>>
Command: (entget (ssname ss 1))
<<< LINE에 관한 정보>>>
Command: (entget (ssname ss 2))
<<< CIRCLE에 관한 정보>>>
Command: (entget (ssname ss 3))
<<< ARC에 관한 정보>>>

도면요소를 그린 순서에 따라 약간의 차이를 보이겠지만 앞서 선택했던 4개의 도면요소에 대한 정보를 얻을 수 있었으리라 생각된다. 이를 통해 SELECTION-SET 내의 도면요소를 처리하는 방식을 정리하면 다음과 같다.

(defun do-entity (ss / len index ent)
  (setq len (sslength ss) index 0)
  (while (index < len)
    (setq ent (ssname ss index))
    <<< entity에 따른 작업 수행>>>
    (setq index (1+ index))
  )
)

위의 방식을 처음에 작성했던 C:OLINE 함수를 수정하여 적용해 본 것이 리스트 1에 있는 C:OLINE 함수이다. 그리고, 수정된 함수에는 ENTITY 이름을 넘겨줄 때 좌표값을 같이 묶어서 넘겨주는 형태로 되어 있는데 이것은 OFFSET 함수가 ENTITY 이름뿐만 아니라 선택된 좌표값을 필요로 하기 때문인데 이번 프로그램의 경우에는 그 좌표값이 특별한 의미를 갖지 않으므로 임의의 좌표값(원점)을 지정하여 사용하였다.

완성된 프로그램을 앞서 그린 도면요소들에 대해 적용해 보자.

Command: OLINE
Select objects: C
First corner: 0,0
Other corner: 14,9
4 found
Select objects:
It is not a line or a polyline.
It is not a line or a polyline.

LINE과 POLYLINE에 대해서는 수행이 되고 ARC와 CIRCLE에 대해서는 수행이 되지 않음을 알 수 있다.



관련 자료
disk [1] OLINE.LSP : OFFSET을 그려주는 프로그램

1. 입문(I) - AutoLISP의 기본 개념
2. 입문(II) - 사용자 정의 함수 제작
3. 입문(III) - 그 밖의 기본 기능들
4. 응용(I) - Entity와 Selection-Set
5. 응용(II) - Symbol table과 Device 제어
6. 응용(III) - Dialogue box 제어
7. 활용예제


Last updated 2002-09-06 by choi@moon-sun.com
This page has been accessed : Counter times.
Home