autolisp - plm.or.kr · Ø Þ È q ñ Þ × j i > Þ Þ î i × q ñ w > Â w x 8 x é Ñ Ë...

137
제2장 AutoLISP 앞장에서는 퍼블릭 도메인인 XLISP을 소개하였고 이를 사용하여 일반적인 LISP 프로그래밍에 대하여 살펴 보았다. 2장에서는 오토캐드에서 사용되는 AutoLISP의 기능에 대하여 비교 설명하고 이를 이용하여 필자가 개발한 객체지향 개발환경 프로그램인 OOPACAD를 공개하고 이용법을 설명하도록 한다.

Upload: doanbao

Post on 21-Sep-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

제2장

AutoLISP

앞장에서는 퍼블릭 도메인인 XLISP을 소개하 고

이를 사용하여 일반적인 LISP 프로그래밍에

대하여 살펴 보았다.

2장에서는 오토캐드에서 사용되는 AutoLISP의

기능에 대하여 비교 설명하고 이를 이용하여

필자가 개발한 객체지향 개발환경 프로그램인

OOPACAD를 공개하고 이용법을 설명하도록 한다.

Page 2: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

1. AutoLISP의 기능

대부분 경우에 오토캐드에 의한 설계 작업은 대상에 따라서 두 가지 서로 다

른 형태의 작업으로 구분되며 모든 설계 작업은 이것을 배합한 형태로 진행된

다. 그 하나는 주어진 작업이 완전하게 독창적인 것으로 기존의 데이터를 참고

할 필요없이 한 번으로 종료되는 프로젝트 작업 형태이고, 이와는 대조적으로

몇 가지의 반복적인 설계 부품의 재조합으로써 작업이 완성되는 경우인데, 이

는 기존의 부품 설계를 그대로 이용하여 작업이 완성된다.

산업 현장에서의 생산 작업은 일반적으로 기존 부품을 이용하게 되는 경우

가 가장 많고, 그 다음이 약간의 수정을 가한 부품을 이용하는 경우, 가장 적

은 경우가 새로운 부품을 쓰게 되는 경우인 것으로 알려져 있다. 이와 같은 생

산, 제조 방식의 비중은 설계에 대해서도 마찬가지의 양상을 갖고 있음을 알

수 있다. 즉, 기존의 부품을 이용하여 설계를 하거나 혹은 설계에 약간의 수정

을 가하여 이용하는 것이 가장 많은 설계 작업 양식이라는 것이다.

하나의 제품을 생산하려면 많은 단계의 설계 수정을 거쳐야 한다. 단순한 선

과 면의 집합이 아닌 각각의 설계 요소가 어떠한 이유로 현재의 모양으로 그

곳에 위치하게 되었는가 하는 디자인의 개념을 도면 설계에 포함시킬 수 있다

면, 설계를 수정하여 사용하는 데 편리하고 또한 전체 도면을 다시 설계하는데

용이하다. 여기에서 우리는 기하학적인 정보 뿐만이 아닌, 설계 프로세스 즉,

설계 배경의 정보까지 포함한 대상을 생각할 수 있는데, 이를 설계 도면의 수

준에서 향상된 수준의 정보를 갖춘 "생산 모델"이라는 개념으로 정의할 수 있

다. 단순히 도면에 관한 정보 이상의 정보를 갖추고 있는 생산 모델을 만드는

것이 현재 고급 CAD 프로그램의 추세이다. 이를 달성하기 위한 가장 손쉬운

방법은 프로그램 언어 수준에서의 생산 모델을 만드는 것이다.

오토캐드에서 이러한 작업을 실현하기 원한다면 AutoLISP을 사용할 수 있

다. 많은 경우 AutoLISP을 시스템을 운용하거나 데이터의 관리 및 부분적인

170

제2 장 AutoLISP

Page 3: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

설계의 자동화를 위하여 사용하고 있으나 순수한 설계 목적으로 이용하는 것

또한 가능하다. 물론 프로그래밍 언어를 사용함으로써 높은 기능의 생산 모델

을 만들 수 있는 것이지만 CAD에서의 또 하나의 장벽인 사용자가 사용하기

편해야 한다는 사항을 고려할 때에는 모든 설계자가 프로그래밍 언어 전문가

가 되어야 한다는 무리한 사실을 요구하게 된다. 또한 이렇게 프로그램으로 생

산 모델을 작성하게 되었을 때 부품을 수정하여 사용하는 경우 프로그램을 수

정하는 작업을 거쳐야 한다는 것이다.

여기에서 우리는 더욱 쉬운 생산 모델의 제작 방법은 없는가와 주어진 생산

모델의 수정을 용이하게 할 수 없을 것인가의 의문점을 제기하게 된다.

첫번째 문제인 쉬운 생산 모델을 만들기 위해서는 일반 프로그래밍 언어보

다는 설계 환경 위주로 되어 있는 개발 환경을 지원하는 운 체계를 만드는

것이다. 즉 도형의 정의, 위치, 일반적인 설계 정보를 지원하는 환경을 만들어

주는 것이다.

두번째의 문제점은 Object Oriented Programming(OOP)의 개념을 이용

함으로써 해결할 수 있다. OOP의 특성인 코드의 재사용은 바로 주어진 생산

모델을 재구성하는데 강력한 장점으로 이용될 수 있는 것이다.

1장에서 공부한 LISP의 내용에서 객체를 처리하는 기능을 상기하여 보자.

하나의 프로그램을 객체 지향 방식으로 작성한 경우에 얻을 수 있는 장점에 대

하여는 이미 언급한 바가 있고 이러한 기능은 Defclass, Definst, Defmehod

등의 명령어를 사용하여 가능하다는 것을 예시하 다. 불행히도 AutoLISP은

이러한 객체 지향 프로그램 개발 도구를 지원하지 않는다.

그러면 어떻게 OOP를 실현할 수 있는가? 오토캐드에서 제공하는

AutoCAD Development System(ADS)은 C++의 OOP 기능을 그대로 이용

할 수 있도록 되어 있다. 그러나 이는 컴파일러 형태의 언어로서 수많은 수정

과 부분적인 교정을 손쉽고 빠르게 처리하는 측면에서는 인터프리터 형태의

언어인 AutoLISP만 하지 못하다. AutoLISP으로 객체 지향 프로그램의 기

171

AutoLISP의기능

Page 4: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

능을 활용할 수 있는 개발 환경을 만들어 보도록 하자.

OOP의 실현에 앞서서 먼저 일반적인 AutoLISP을 활용하는 방법과 LISP

과의 차이점을 설명하도록 한다. 대부분의 기본적인 명령어가 활용이 가능하

고 AutoLISP에만 부가되어 있는 특별 함수들에 대하여 먼저 설명하도록 하

고, 일반적인 AutoLISP 기능을 이용하여 버스를 설계하는 프로그램을 만들

고 이를 수정하여 봄으로써 비 OOP 프로그램 방식이 비효율적이라는 사실을

확인하여 보겠다. 이후에 OOP의 기능을 활용할 수 있는 프로그램의 개발 방

법을 설명하고, 이를 사용자의 측면에서 용이하게 사용할 수 있도록 개발한

OOPACAD 패키지의 사용법에 대하여 알아보도록 한다.

172

제2 장 AutoLISP

Page 5: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

2. AutoLISP 프로그래밍

(1) AutoLISP의활용방법

1) 입력 방법과 함수 정의 활용

AutoLISP은 오토캐드의 커맨드(Command) 레벨에서 사용할 수 있다. 그

러므로 단순한 오토캐드의 명령어와 AutoLISP의 표현식을 구분하여 인식할

수 있는 방법이 요구된다. 오토캐드에서 '('의 시작은 이것이 AutoLISP 표현

식임을 나타내는 것을 뜻한다.(이는 이미 1장에서 배운 LISP의 표현식에 대

한 설명과 다를 바가 없다.) 매번 괄호가 시작될 때마다 이는 하나의 표현식으

로 AutoLISP에 전달된다. AutoLISP은 이를 평가하고 결과를 오토캐드로

출력한다. 오토캐드는 그 결과를 사용하고 계속된다. 다음의 명령어를 입력하

여 오토캐드에서 AutoLISP이 어떻게 활용되는가를 알아보자.

command: (prompt "Hello everybody")

Hello everybody.nil

AutoLISP은 Prompt 함수를 평가하는데, 이는 그 인수를 화면에 출력하는

기능의 함수이다. 그리고 nil을 출력한다. 이 함수는 "Hello everybody"라는

스트링 인수를 취하여 이를 화면에 출력한다. 이미 설명하 듯이 스트링은 "

마크 사이에 선언된 문자의 열이다. 표현 식을 입력하는 중에 이를 취소할 경

우에는 Ctrl-C를 입력하면 된다. 이는 현재 진행 중인 표현식 입력 상태를 취

소시키고 새로이 시작할 수 있도록 한다.

입력중 하나의 표현식은 정확하게 매칭되는 괄호로서 묶여져야 한다. 만약

에 묶여지지 않은 괄호가 있는 상태에서 행이 바뀌어 진다면 커서에 숫자가 나

타나는데 이는 현재 표현식을 마무리 지우기 위하여 필요한 오른쪽 괄호의 개

수를 표시한다. 표현식 입력 시에 길이가 길어지는 경우에는 256 자까지 연

173

AutoLISP 프로그래밍

Page 6: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

속하여 입력하는 것이 가능하다. 이는 입력자가 엔터 자판을 칠 때까지 연속하

여 받아들일 수 있는 최대 길이이다.

스트링을 입력하는 경우에도 표현 식에서의 괄호 사용과 마찬가지로 "로 매

칭되는 부분이 명확하게 표시되어야 한다. 괄호 사용과 "의 사용이 오토캐드의

커맨드(Command)의 커서를 통하여 입력하는 경우 가장 유의하여야 할 부분

이다.

표현식 혹은 함수를 입력하는 다른 한 가지의 방법은 파일을 이용하여도 가

능하다. 커맨드 커서에서 (load "test.lsp")를 입력하게 되면, Load 함수는 현

재의 디렉토리에서 test.lsp 파일을 찾아서 이 파일의 내용을 평가한다. 이 함

수는 일반적인 표현식들 혹은 함수를 포함할 수 있는데 하나 하나 수동으로 입

력하는 것보다 표현식의 시퀀스를 한번에 입력할 수도 있고, 자주 사용되는 함

수들을 정의하여 사용하는 데도 사용될 수 있다.

<예>

다음 내용의 텍스트 파일을 만들고 오토캐드의 커맨드 레벨에서 (load "c:test")를 실행

한다. 파일의 편집 방법은 커맨드 레벨에서 sh 명령어를 사용하여 도스로 나온 후 임의의

에티터를 사용하고, 오토캐드로 돌아가기 위해서는 exit를 입력한다.

(print "This is test")

(print "How are you?")

(defun test ()

(print "this is function test"))

파일test.lsp의내용

Command: (load "c:test")

174

제2 장 AutoLISP

Page 7: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

"This is test"

"How are you?" TEST

AutoLISP은 파일 Test의 두개의 Print 명령문을 수행하 고 최종적으로는

함수 Test를 만들었다. 실행 결과는 순서대로 출력되고 함수는 그 이름을 출력

한다. 이 상태에서 함수 Test를 확인하기 위하여 다음과 같은 방법을 취한다.

Command: (test)

"this is function test" "this is function test"

Command:

첫번째 문자열은 함수를 수행한 결과를 두번째 문자열은 그함수에서의 마지

막 표현식을 평가한 결과를 나타낸다.

2) AutoLISP에서의 변수 설정

오토캐드에는 여러 가지의 시스템 변수가 있다. 이러한 변수를 일반적인 심

볼과 달리 취급하고 보호하기 위하여 LISP에서 사용되는 setq 혹은 set의 함

수 대신에 setvar 함수를 사용하도록 되어 있다. getvar 함수는 이에 대비되

는 기능의 함수로서 원하는 시스템 변수의 값을 알아내는데 사용된다. 그 사용

법은 다음과 같다.

<시스템 변수>는 스트링의 형태로 주어지며, 이에 해당하는 시스템 변수의 현

재값을 출력한다.

175

AutoLISP 프로그래밍

(getvar <시스템 변수>)

Page 8: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

<시스템 변수>의 값을 <값>으로 변경하며 변경된 값을 출력한다. 역시 <시스템

변수>의 값은 스트링의 형태로 주어진다.

<예>

Command: (getvar "CLAYER")

"0"

3) 오토캐드에서의 매크로 사용

오토캐드에서도 매크로라는 말이 사용되는데 이는 LISP에서 사용되는 기능

하고는 다르다. 원래 매크로라는 것은 서브루틴에 대응되는 말로서, 서브루틴

이 프로그램의 실행 도중 필요한 인수들만을 가지고 실행한 결과를 주프로그

램에 반환하는 것에 반하여 매크로는 직접 주프로그램에 반복되는 사용 명령

어 구들의 집합을 직접 삽입한다. 서브루틴은 일정한 메모리의 역을 확보하

고 호출시 프로그램의 흐름이 이곳으로 점프하는 반면, 매크로는 삽입된 곳마

다 정의된 메모리 역을 확보하여 실행된다.

LISP에서의 Defun은 서브루틴의 정의 함수로, Defmacro는 매크로를 정의

하는 방법으로 사용된다. AutoLISP에서의(엄 하게 말하자면 오토캐드에서

의) 매크로라는 것은 CAD 운용상 반복되는 여러 가지 CAD 명령의 반복적 수

행을 뜻한다. AutoLISP에서의 매크로로서 메뉴 매크로라는 표현이 더욱 적합

한 것은 이러한 이유에서이다.(앞으로의 표현에서는 메뉴 매크로라는 말을 사용

하도록 한다.) 적용은 다소 다르지만 기능 면에서 매크로라는 용어는 오토캐드

의 메뉴 매크로나 LISP에서의 매크로로서 이러한 배경에서 붙여진 것이다.

메뉴 매크로는 하나의 매크로 기능으로 여러 가지의 CAD 명령어를 순차적

으로 연속하여 사용할 수 있도록 한다. 하나의 메뉴를 선택할 때 이를 매크로

로서 표현하면 하나의 선택 동작으로 여러 가지의 연속 CAD 명령 처리가 가

176

제2 장 AutoLISP

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

Page 9: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

능하고, AutoLISP의 기능까지 첨가하여 사용한다면 고도의 연속 CAD 작업

을 수행하는 것이 가능하다.

오토캐드에서의 메뉴 매크로 기능을 소개하면 다음과 같다.

; 리턴의 역할을 한다

\ 입력을 기다린다

+ 다음 줄로 계속한다

space 공간을 발생시킨다.

* 자체 반복 혹은 페이지를 마크한다

' 명령어를 외형적으로 실행한다

$ 메뉴 부분을 로드하거나, DIESEL 함수를 사용한다

- 오토캐드 명령어나 키워드를 번역한다

. 기본으로 정의된 오토캐드 명령어나 키워드를 사용한다

[ ] 표식(매크로 이름)을 나타낸다

B 스냅을 켜거나 끈다

C *Cancel*

^D 좌표 표시를 켜거나 끈다

E ISOPLANE 을 켜거나 끈다

^G 그리드를 켜거나 끈다

H 백 스페이스를 발생한다

^I 탭을 발생한다

^M 리턴을 발생한다

^O ORTHO를 켜거나 끈다

P MENUECHO를 켜거나 끈다

^Q Printer echo를 켜거나 끈다

T 표사용을 켜거나 끈다

177

AutoLISP 프로그래밍

Page 10: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

^V 다음 번의 viewpoint로 변환한다

^X 버퍼의 입력을 지운다

Z 줄 끝에 자동 생성되는 스페이스를 억제한다

메뉴 매크로의 예는 다음과 같다.

[BUBBLE2] C^C^C(setq y (getvar "CLAYER"))_.LAYER_M OBJ01;;+

_.CIRCLE\0.25_.LAYER_M TXT01 ;_.TEXT_S STD _M@ .25 0 \+

_.LAYER_S OBJ01;;_.LINE_QUA\\_.LAYER_S !Y;;

178

제2 장 AutoLISP

<그림 2-1> 매크로와 서브루틴

주 프로그램

주 프로그램 주 프로그램

주 프로그램

매크로 A 호출 서브루틴 A 호출

서브루틴 A 호출

컴파일 전

컴파일 후 실행

매크로 A 호출

매크로 A 서브루틴 A

Page 11: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

이상의 내용을 메뉴 파일에 넣고 이를 실행하면 BUBBLE2의 내용이 메뉴

창에 나타난다. 이를 마우스로 선택하면 [BUBBLE2]에 따르는 내용을 순차

적으로 실행하게 된다. 즉 현재의 레이어의 이름을 변수 y에 저장하고 OBJ01

의 새로운 레이어를 만들고 이것에 원을 만들고, 또 새로운 레이어 TXT01을

만드는 일을 진행한다. 마지막으로 현재의 레이어는 처음 시작한 레이어를 선

택한 상태로 끝을 내도록 되어 있다. 이상에서 설명된 Layer, Circle, Line

등의 명령어는 오토캐드의 명령어이다. 매크로를 이용한 메뉴의 이용법의 자

세한 내용은 오토캐드 매뉴얼을 참고하도록 한다.

4) AutoLISP을 이용한 오토캐드 입력

오토캐드에 AutoLISP을 입력시키는 방법에는 Command:에서의 입력과

파일을 이용하여 load 함수를 이용하는 두 가지 방법이 있음을 설명하 다.

이와 반대로 AutoLISP 내에서 오토캐드의 명령어들을 사용하는 방법이 가능

한가를 알아보자.

Command 함수를 사용하여 이와 같은 역할을 수행할 수 있으며 그 사용법

은 다음과 같다.

(command <인수> ...)

<인수>들을 오토캐드의 입력으로 보낸다. 스트링과 수는 있는 그대로 전달되

며, 다른 종류의 인수들은 그 표현식의 평가 결과가 전달된다. <인수>가 없이

(command)로 사용되는 경우는 Ctrl-C를 발생하고, (command "")는 리턴

신호를 발생한다. pause를 사용하는 경우(command "LINE" pause "2,2")

는 입력 신호가 발생할 때까지 대기한다. 오토캐드의 명령어 중 원을 생성하는

방식은 "circle" 명령어를 보내고 중심의 좌표와 반지름의 길이를 입력하여야

하는데, 이는 AutoLISP 내에서 (command "circle" "2,2" 0.25) 의 표현식

179

AutoLISP 프로그래밍

Page 12: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

으로 원하는 목적을 수행할 수 있다.

AutoLISP 프로그램의 함수가 일반적인 LISP의 함수와 어떻게 다른지 혹

은 추가, 삭제된 함수는 무엇인가를 기능별로 살펴보도록 하자.

(2) AutoLISP 함수들

1) 입력 관련 함수들

대부분의 프로그램 언어가 입력을 받아들여서 데이터의 값을 설정하는 기능

을 필요로 한다. AutoLISP에서는 GET 함수가 이 기능을 담당한다. 이 함수

를 이용하여 사용자는 선택한 점의 위치, 점간의 거리, 스트링, 수 등의 데이

터 값을 입력할 수 있다. 다음은 데이터에 따른 사용 함수에 대한 설명이다.

점을 출력한다. getpoint 단독으로 사용되어 화면에 선택한 점의 위치를 입력받

180

제2 장 AutoLISP

Command: (print “abc”)“abc”“abc”Command: (+1 2)3Command: (foreach a ‘(1 2 3) (print a))

123 3

Command: (defun test ( )

1> (print “abc”)

1> (Command “line”“0, 0, 0”“1, 1, 1”“”))TESTCommand: (test)

“abc”line From point: 0, 0, 0To point: 1, 1, 1To point:Command: nil

Command:

AutoLISP AutoCAD

<그림 2-2> AutoLISP과 오토캐드의

명령어 사용

(getpoint <기준점> <프롬프트 출력>)

Page 13: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

는다. <기준점>을 정의하면 점을 선택하는 순간까지 <기준점>으로부터 마우스의

위치로 고무줄 모양으로 점선이 표시된다. <프롬프트 출력>은 입력하는 점이 무

슨 용도로 사용되는가에 대한 정보를 사용자 편의를 위하여 설정하여 사용된다.

Command:(setq pt1 (getpoint "Center point: "))

Center point: 1,2,3

(1.0 2.0 3.0)

Command:!pt1

(1.0 2.0 3.0)

예제는 한 점의 위치를 입력받는 프로그램이다. 사용자의 편의를 위해

"Center point"라는 <프롬프트 출력>을 사용하 다. 입력된 점은 한편으로는

변수 pt1에 할당된다. 입력 점의 위치는 예제에서와 같이 좌표계를 자판 입력

하는 방법 외에도, 마우스로 선택하는 것이 가능하다. !pt1은 변수 pt1에 어떠

한 내용이 들어 있는가를 확인하는 방법으로 AutoLISP에서는 ! 부호를 변수

앞에 붙여 사용함으로써 현재 그 변수에 할당되어 있는 내용을 확인할 수 있다.

132개까지의 문자로 이루어진 스트링을 입력할 수 있다. <표시 깃발>의 내용

이 nil이면 스트링내의 Space는 인정되지 않는다. getpoint에서와 마찬가지로

<프롬프트 출력>을 사용하여 입력하는 스트링이 무엇에 관한 정보인지를 화면

에 출력하여 참고할 수 있다.

<주의점>

Get 함수를 Command 함수와 더불어 사용할 수 없으나, 디젤 함수와 같이 사용하는 것

은 가능하다.

181

AutoLISP 프로그래밍

(getstring <표시 깃발> <프롬프트 출력>)

Page 14: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

Command:(setq txt (getstring "Text: "))

Text: ABC

"ABC"

Command:!txt

"ABC"

예제는 스트링을 입력받아서 변수 txt에 할당하는 프로그램이다. <프롬프트

출력>은 Text:인데 이는 스트링을 읽어들일 때 화면에 출력되는 내용을 가리

킨다. !txt를 사용해서 내용을 확인하면 스트링 "ABC"가 할당되어 있음을 확

인할 수 있다.

두 개의 점 사이의 거리를 출력한다. getdist와 마찬가지로 고무줄 입력의 모

양을 취하고 싶을 때 <기준점>의 값을 입력한다. <프롬프트 스트링>의 사용은

다른 종류의 get 함수와 같다.

라디안 단위로 각도의 값을 출력한다. 이는 x축을 기준으로 하여 반시계 방향

으로 측정하며, 이에 대한 입력은 사용자가 입력할 수도 있고 두 개의 주어진

점으로부터 계산할 수도 있다. 정당한 입력이 입력되지 않으면, "Requires

valid numeric angle or two point. Try again"이라는 에러 메시지가 출력

된다. 좌표계는 현재 오토캐드의 UCS(User Coordinate System)에 의하여

정의된 좌표계를 기준으로 한다. 입력 지침을 주기 위하여 <프롬프트 스트링>

을 추가할 수 있다. getorient는 상대각을 getangle은 절대각의 크기를 나타

낸다.

182

제2 장 AutoLISP

(getdist <기준점> <프롬프트 스트링>)

(getangle <기준점> <프롬프트 스트링>)

Page 15: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

라디안 단위로 각도의 값을 출력한다. 이는 x축을 기준으로 하여 반시계 방향

으로 측정하며, 이에 대한 입력은 사용자가 입력할 수도 있고 두 개의 주어진

점으로부터 계산할 수도 있다. 정당한 입력이 입력되지 않으면, "Requires

valid numeric angle or two point. Try again"이라는 에러 메시지가 출력

된다. 좌표계는 현재 오토캐드의 UCS(User Coordinate System)에 의하여

정의된 좌표계를 기준으로 한다. 입력 지침을 주기 위하여 <프롬프트 스트링>

을 추가할 수 있다. getangle은 절대각의 크기를 getorient는 상대각의 크기

를 나타낸다.

실수값을 사용자로부터 입력받아 이를 출력한다. 정수값이 입력되면 이를 실

수형으로 자동 변환하고, 원하는 수치 데이터의 값이 아닌 경우에는

"Requires numeric value. Try again:"이라는 에러 메시지가 출력된다. 입

력 지침을 주기 위하여 <프롬프트 스트링>을 추가할 수 있다.

정수값을 사용자로부터 입력받아 이를 출력한다. 입력은 -32768로부터

+32768 사이의 값이어야 하며 이를 넘을 때는 에러 메시지가 발생한다. 입력

지침을 주기 위하여 <프롬프트 스트링>을 추가할 수 있다.

Command:(getangle "Enter angle: ")

Enter angle: 30

0.523599

Command:(setq pt1 (getpoint "Enter point: "))

Enter point: 마우스로점을선택한다

183

AutoLISP 프로그래밍

(getorient <기준점> <프롬프트 스트링>)

(getreal <프롬프트 스트링>)

(getint <프롬프트 스트링>)

Page 16: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(2.0 2.0 0.0)

Command:(getangle pt1 "Enter angle: ")

Enter angle: 마우스로각을선택한다

0.9007

getangle은 각의 입력을 요구하며, 30으로 입력된 디그리는 라디안의 단위

로 변환되어 출력된다. getpoint를 사용하여 선택된 점의 데이터는 변수에 동

시 할당하는 것이 가능하다. 입력된 데이터는 pt1에 할당된다. 이후 마우스로

선택된 점의 데이터는 pt1에 할당된다. getangle에서 <기준점>을 주었을 경우

그 점을 기준으로 측정하고자 하는 각도를 입력받기 위하여 다른 하나의 점을

요구한다. 임의의 점을 선택하면 getangle은 두 개의 점으로부터 원하는 각도

를 계산하여 그 결과를 라디안의 단위로 출력한다.

2) 연산 관련 함수들

+, -, *, /, 1+, 1-, rem, min, max, abs, gcd, sin, cos, atan, expt,

exp, log, <, <=, >, >= 등의 함수는 LISP과 동일한 역할을 한다.

truncate, round, float, rational, mod, signum, lcm, random, tan,

asin, acos, sinh, cosh, tanh, asinh, acosh, atanh, numerator,

denominator, complex, realpart, imagpart, conjugate, phase 등의

LISP 함수는 활용되지 않는다.

기하학적인 계산식을 사용하여 <표현식>을 평가한다.

<기준점>으로부터 <각>의 각도를 이루며, <거리> 만큼 떨어져 있는 점의 좌표

184

제2 장 AutoLISP

(cal <표현식>)

(polar <기준점> <각> <거리>)

Page 17: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

를 계산하여 출력한다.

<점1> 과 <점2> 사이의 거리를 구한다.

3) 스트링 관련 함수들

strcat은 LISP과 동일한 역할을 한다.

string, string-uprcase, string-downcase, string-lessp, string-not-

greaterp, string-equal, string-not-equal, string-not-lessp, string-

greaterp 등의 LISP 함수는 활용되지 않는다.

주어진 스트링을 <표식>이 참값일 때는 소문자로 변형하고, 그렇지 않을 경우

에는 대문자로 변형한다.

<스트링>의 문자의 개수를 출력한다.

<시작>의 위치로부터 길이 만큼의 문자열만을 <스트링>으로부터 출력한다.

Command: (setq il (getstring "Enter text: " T))

Enter text: This is for test

"This is for test"

Command:(strcase il)

"this is for test"

185

AutoLISP 프로그래밍

(distance <점1> <점2>)

(strcase <스트링> <표식>)

(strlen <스트링>)

(substr <스트링> <시작> <길이>)

Page 18: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

Command:(substr "This is a test" 6 2)

"is"

Command:(strlen il)

16

스트링 "This is for test"를 변수 il에 할당하고 이를 strcase를 사용하여

소문자로 바꾸어 준다. substr은 스트링 il의 6번째로부터 2개의 문자인 "is"

를 출력하게 하고 strlen은 스트링 il의 길이인 16을 출력한다.

4) 문자 관련 함수들

char, alphanumericp, upper-case-p, lower-case-p, alpha-char-p,

digit-char-p, char-code, code-char, char-upcase, char-downcase,

digit-char, int-char, char<, char<=, char=, char/=, char>=, char>,

char-lessp, char-not-greaterp, char-equal, char-not-equal, char-not-

lessp, char-greaterp 등의 LISP 함수는 활용하지 아니한다.

<정수>의 코드에 해당하는 문자를 출력한다. 이는 ASCII 규약에 따른다.

<스트링>의 첫번째 문자를 ASCII 코드로 출력한다.

Command:(ascii "A")

65

Command:(ascii "a")

97

186

제2 장 AutoLISP

(chr <정수>)

(ascii <스트링>)

Page 19: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

Command:(chr 65)

"A"

Command:(chr 97)

"a"

chr과 ascii는 각각 A와 a에 해당하는 ASCII 코드와 문자를 변환하여 보여

줌을 확인할 수 있다.

5) 평가 함수들

eval, apply, quote, lambda 등의 함수는 LISP과 동일한 역할을 한다.

funcall은 활용되지 않는다.

6) 심볼, 프로퍼티, 배열, 시퀀스 리스트, 스트럭처, 객체 관련 함수들

set, setq, defun 등의 함수는 LISP과 동일한 역할을 한다. setf,

defmacro, defconst 등의 LISP 함수는 활용되지 않는다.

putprop, get 등의 프로퍼티 관련 LISP 함수는 활용되지 않는다.

aref, make-array, vector 등의 배열 관련 LISP 함수는 활용되지 않는다.

length, reverse 등의 함수는 LISP과 동일한 역할을 한다.

concatenate, elt, nreverse 등의 LISP 함수는 활용되지 않는다.

car, cdr, cxxr, cons, list, append, last, nth, member, assoc,

mapcar, subst, 등의 함수는 LISP과 동일한 역할을 한다.

first, second, third, fourth 등의 LISP 함수는 활용되지 않는다.

스트럭처 관련 함수와 객체 관련 LISP 함수는 AutoLISP에서 지원되지 않

는다.

187

AutoLISP 프로그래밍

Page 20: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

7) Predicate 및 제어 관련 함수들

symbolp, consp, integerp, floatp, rationalp, complexp, stringp,

characterp, array, objectp, classp, plusp, evenp, oddp, subsetp, eql,

equalp, typep 등의 LISP 함수는 활용되지 않는다.

atom numberp, not, null, listp, boundp, minusp, zerop, eq, equal

등의 함수는 LISP과 동일한 역할을 한다.

eq, equal, =의 세 가지는 조금씩 다른 용도로 사용된다. =는 수와 스트링의

비교에 사용되며 eq는 두개의 비교 대상이 동일한 객체에 할당되어 있는 지를

비교하고, equal은 두 개의 대상이 동일한 결과를 출력하는지의 여부를 조사

한다.

cond, and, or, if 등의 함수는 LISP과 동일한 역할을 한다.

when, unless, case, let, let*, loop, do, dotimes 등의 LISP 함수는 활용

되지 않는다.

<표현식>들을 주어진 <횟수> 만큼 반복하여 실행한다.

<조건>을 확인하여 만족하는 동안 <표현식>들을 반복하여 실행한다.

<리스트>의 내용을 하나 하나씩 <표현식>의 <심볼>의 내용을 바꾸어 가며 실

행한다. 즉 <리스트>의 하나의 요소에 대하여 <표현식>들의 내용을 한 번씩

반복 실행한다. 여기에서 <심볼>은 foreach에 대해서만 해당하는 지역 변수

가 된다.

188

제2 장 AutoLISP

(repeat <횟수> <표현식>....)

(while <조건> <표현식>.....)

(foreach <심볼> <리스트> <표현식>...)

Page 21: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

189

AutoLISP 프로그래밍

Command:(setq count 4 data '(A B C D E F G H I J))

(A B C D E F G H I J )

Command: (while (< count 10) (print (nth count data))

1> (setq count (1+ count)))

E

F

G

H

I

J 10

Command:(defun getpts ( / pt ptlist)

1>(while (setq pt (getpoint "\nEnter point or ENTER when done:'))

2>(setq ptlist (append ptlist (list pt)))))

GETPTS

Command:(setq ptlist (getpts))

Enter point, or ENTER when done:

임의의점을마우스로선택한다

(4.3 5.6 0.0)(4.3 6.2 0.0)(5.0 6.2 0.0)(5.3 5.6 0.0)(6.1 6.0 0.)(6.5 5.6 0.0)

(6.5 5.0 0.0)(7.2 5.0 0.0))

Command:LINE

From point: (foreach pt ptlist (command pt))

To point:

To point: nil

To point: 리턴을친다

Page 22: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

변수 count에는 10을 dat에는 '(A B C D E F G H I J)를 할당한다.

while는 count 10 보다 작은 동안 계속하여 리스트'(A B C D E F G H I

J) 중에서 count번째에 해당하는 요소를 프린트하고 count를 하나씩 증가한

다. count는 초기에 4로 설정되어 있으므로 5번째 요소인 E를 프린트하고

(nth 명령어에 의한 리스트의 첫 번째 순서는 0부터 시작함에 유의할 것) 계

속하여 11번째인 요소 J까지 프린트를 계속한다.

함수 getpts는 while의 조건 문을 이용하여 여러 개의 점의 위치를 연속적

으로 입력받는 함수이다. ptlist라는 변수를 여러 개의 점의 집합으로 표시하

고 오토캐드 명령어 LINE을 수행하는 과정에서 ptlist로부터 점을 하나씩 취

하여 사용하는 방법을 foreach를 사용하여 실행하 다. 마치 LISP에서의

dolist와 비슷한 역할을 수행함을 알 수 있다. <그림 2-3>은 각 제어 명령어의

플로우 차트를 나타낸다.

8) 프로그램, 입출력, 파일, 시스템 관련 함수들

progn의 함수는 LISP 과 동일한 역할을 하나, progn*, block, return 등의

함수는 활용되지 않는다.

read, print, prin1, print, princ, terpri 등의 대부분의 출력 관련 함수들

190

제2 장 AutoLISP

<그림 2-3> 각 제어 명령어의

플로우 차트While Repeat Foreach

조건만족

프로그램 내용 프로그램 내용

불만족

프로그램 내용

n회 실행 각각의 리스트요소에 대해 실행

Page 23: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

은 LISP과 동일한 역할을 한다.

<스트링>의 내용을 스크린의 프롬프트에 출력한다.

open, close, read-char, write-char, read-line 등의 함수는 LISP 과 동일

한 역할을 한다.

delete-file, with-open-file, read-byte, write-byte, file-length, file-

position 등의 LISP 함수는 활용되지 않는다.

load, gc, 등의 함수는 LISP 과 동일한 역할을 하나, save, savefun,

dribble, room, time, peek, poke, goto-xy, color, move, moverel,

mode 등의 LISP 함수는 활용되지 않는다.

하나의 화면을 갖는 시스템에서 텍스트 화면으로부터 그래픽 화면으로 전환하

라. nil을 출력한다.

하나의 화면을 갖는 시스템에서 텍스트 화면으로부터 그래픽 화면으로 전환하

라. nil을 출력한다.

하나의 화면을 갖는 시스템에서 그래픽 화면으로부터 텍스트 화면으로 전환

하고 화면을 깨끗이 한뒤 커서를 맨 윗쪽 첫째 칸에 위치시킨다. nil을 출력

한다.

191

AutoLISP 프로그래밍

(prompt <스트링>)

(graphscr)

(textscr)

(textpage)

Page 24: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

심볼(atoms)의 모든 리스트를 출력한다. <비교 리스트>를 가지고 그것이 존재

하는지의 여부를 판단할 수 있다. <포맷 방식>을 0으로 하면 출력은 atom의

형태로 되며, 1인 경우는 스트링의 형태로 출력한다., <비교 리스트>는 스트링

의 형태로 준다.

<파일이름>은 스트링으로 선언되며 이 스트링의 파일을 읽어 들인다. 뒤의 <표

현식>은 파일이 제대로 읽어들 는지 아닌지를 확인하고 그렇지 못한 경우에

이 <표현식>을 평가하여 그 값을 출력한다.

9) 단위 변환 함수들

<정수>를 스트링의 형태로 변환한다.

<스트링>을 실수형으로 변환한다.

<스트링>을 정수형으로 변환한다.

Command:(itoa 24)

"24"

Command:(itoa 3.5.)

error: bad argument type

(itoa 3.5)

192

제2 장 AutoLISP

(atoms-family <포맷 방식> <비교 리스트>)

(load <파일이름> <표현식>)

(itoa <정수>)

(atof <스트링>)

(atoi <스트링>)

Page 25: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

Command:(atof "24.5")

24.5

Command:(atof "24")

24.0

Command:(atoi "24.9")

24

주어진 <숫자>를 다음의 <모드>에 따라서 변환한다.

1. 과학적 수식 표현(예: 1.55E+01) 2. 10진수 표현(예: 15.50)

3. 공학적 수식 표현(예: 1'-3.50'') 4. 건축학적 수식 표현(예: 1'-3 1/2'')

5. 분수적 수식 표현(예: 15 1/2)

<스트링>으로부터 <모드>에 지정된 방식에 따라 실수를 출력한다. <모드> 종류

는 rtos에서 정의된 것과 동일하다.

Command:(rtos 8.5)

"8.5000"

Command:(rtos 12.625 4)

"1' - 0 5/8""

Command:(setq str (rtos 12.625 4 2))

"1'-0 3/4""

Command:(distof str 4)

12.75

Command:(distof "12.625" 4 2)

193

AutoLISP 프로그래밍

(rtos <숫자> <모드> <정도>)

(distof <스트링> <모드>)

Page 26: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

error: too many arguments

(DISTOF "12.625" 4 2)

*Cancel*

Command:(disof "12.625" 4)

12.625

<숫자>의 정수값을 출력하고 나머지는 무시된다.

<숫자>를 실수형으로 변환한다.

주어진 <숫자>를 <종래 단위>로부터 <변환 단위>로 변환한 결과를 출력한다.

1

Command:(setq feet (getdist "Feet:"))

Feet: 12

12.0

Command:(setq feet (cvunit feet "feet" "inches"))

144.0

12 feet를 inch로 환산하는 방법을 나타내었다.

두 개의 점을 잇는 직선이 X축과 이루는 각도를 반시계 방향으로 측정하여 라

디안 단위로 출력한다.

194

제2 장 AutoLISP

(fix <숫자>)

(float <숫자>)

(cvunit <숫자> <종래 단위> <변환 단위>)

(angle <점> <점>)

Page 27: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(angle '(0 0) '(-1 0))

3.14159

<각도>를 스트링으로 출력한다. 이때 원하는 <모드>와 <정확도>를 줄 수 있다.

이 값들을 주지 않으면 현재 상태에 정의된 <모드>와 <정확도>에 따라서 실행

된다.

주어진 <스트링>의 값을 <모드>의 형태로 각으로 환산한다. <모드> 값은 0= 10

진수 각도; 1= 각도, 분, 초; 2= grads; 3= 라디안; 4= Surveyor의 단위;

10) 도면 데이터 관리 함수들

AutoLISP의 함수중 도면 데이터 관리 함수는 일반적인 LISP 언어와는 많

은 차이점을 갖는다. 이는 도면에 관련된 오토캐드 고유한 도형의 표현 방식을

이용하기 위하여 피할 수 없는 현상이다. 전체적인 데이터의 구조를 이해하고

충분한 활용이 가능하여야만 AutoLISP의 기능을 완전히 활용할 수 있다. 이

러한 데이터를 다루는 AutoLISP 특유의 함수들에 대하여 다루도록 하자.

프로그램중 혹은 CAD 작업중 <Entity name: xxxxxxxx> 등의 내용이 화

면에 나타나는 경우가 있는데, 이는 도면의 요소가 데이터베이스에 어떤 방식

으로 추가되었는지를 나타내는 것이다. 이러한 도형 요소(Entity)를 다루는

함수들에 대하여 알아본다.

도형 데이터베이스에 가장 마지막으로 입력된 도형 요소를 출력한다.

195

AutoLISP 프로그래밍

(angtos <각도> <모드> <정확도>)

(angtof <스트링> <모드>)

(entlast)

Page 28: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

현재 선택되어 있는 도형 요소의 다음으로 오는 도형 요소를 출력한다. 만약 <도

형 요소 이름>이 주어지면 이 <도형 요소 이름> 다음의 도형 요소를 출력한다.

도형 요소들을 선택해서 새로운 도형 요소의 집합을 만들어낸다. <프롬프트 스

트링>은 일반적인 get 함수와 같이 사용자에게 현재 작업에 대한 설명의 문자

열을 넣어준다. (entsel)의 표현식은 사용자가 화면상에서 여러 가지 방법 중

의 하나로 선택할 수 있다. 즉 원하는 도형 요소를 직접 마우스로 선택할 수

있고, 상자를 정의하여 이에 포함되는 모든 도형 요소들을 선택할 수도 있다.

(redraw)는 현재의 viewport에서 보이는 모든 도형 요소를 다시 그리도록 한

다. <도형 요소 이름>이 주어지면 이 것만을 다시 그리며, 그리는 방법은 <모

드>에 준한다. 즉 <모드>가 1인 경우가 표준이며, 2인 경우는 반전된 방법으

로, 3인 경우는 하일라이트(highlight) 방법을, 4인 경우는 하일라이트를 없

애는 방법을 의미한다.

현재 지정되고 있는 도형 요소를 지우거나 주어진 <도형 요소 이름>의 도형 요

소를 데이터베이스로부터 삭제한다. 작동 후 <도형 요소 이름>을 출력한다.

도형 요소들의 선태 집합을 구한다. ssget이 실패하면 nil을 출력한다. 인수없

이 (ssget)이 사용되는 경우는 오토캐드에서의 선택 방법에 준하여 도형들을

선택 방법을 입력한다. <모드>가 사용되는 경우는 사용자 입력 방식에 의해 도

196

제2 장 AutoLISP

(entnext <도형 요소 이름>)

(entsel <프롬프트 스트링>)

(redraw <도형 요소 이름> <모드>)

(entdel <도형 요소 이름>)

(ssget <모드> <점 1> <점 2> <점 리스트> <필터 리스트>)

Page 29: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

형 요소가 선택되지 않고 자동으로 도형 요소가 선택된다. <모드>는 다음의 여

러 가지 종류가 있다.

L: 마지막 도형 요소를 선택한다.

I: Implied pick first pending selection set 의 경우에 사용된다.

W: 창을 지정하여 내부에 포함되는 모든 도형 요소들을 선택한다.

C: 창에 걸치는 도형 요소도 선택한다.

WP: WPoly 의 경우에 사용된다.

CP: CPoly 의 경우에 사용된다.

X: 모든 도형 요소를 선택한다.

F: 울타리 기능으로 도형 요소를 선택한다.

W, C 를 <모드> 로 사용한 경우에는 창의 모서리를 <점 1> <점 2>의 위치에

인수로 지정하며, WP, CP, F가 사용되었을 경우에는 <점 리스트>의 값을

설정하여야 한다. <필터 리스트>가 지정된 경우에는 필터의 조건을 만족하는

조건만이 선택되도록 한다.

<선택 집합>이 몇 개의 도형 요소를 갖고 있는지를 출력한다.

<도형 요소 이름>이 <선택 집합>에 포함되어 있는지를 조사하고, 있으면 T, 없

으면 nil을 출력한다.

<선택 집합>의 <수>번째 도형 요소의 이름을 출력한다.

197

AutoLISP 프로그래밍

(sslength <선택 집합>)

(ssmemb <도형 요소 이름> <선택 집합>)

(ssname <선택 집합> <수>)

Page 30: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(ssadd) 단독으로 사용될 때 새로운 선택 집합을 생성한다. 그렇지 않을 경우

에는 기존의 <선택 집합>에 <도형 요소 이름>의 도형 요소를 추가한다. <선택

집합>을 출력한다.

<선택 집합>으로부터 <도형 요소 이름>의 도형 요소를 삭제한다.

ssget의 선택 방법에 필터링 방법을 추가하여 도형 요소를 2차로 선별하는

것이 가능하다. 그 이용법은 다음과 같다.

(ssget "X" '((0 . "CIRCLE")(8 . "OBJ01")))의 표현식은 현 도면에서

OBJ01의 레이어 이름을 가진 모든 원을 선택 집합으로 만든다. <그림 2-4>는

ssget을 이용하여 도면 중의 원을 선택하는 방법을 보여준다.

198

제2 장 AutoLISP

코드 내 용 데이터 형 예 제

0 도형 요소의 종류 스트링 (0."LINE")

2 블록 이름 삽입 스트링 (2."ARROW")

3 디멘전의 종류 스트링 (3."TOLERANCE")

6 선의 종류 이름 스트링 (6."CENTER")

7 텍스트의 종류 이름 스트링 (7."STANDARD")

8 레이어 이름 스트링 (8."OBJ01")

39 두께 실수 (39 . 6.0)

62 색 종류 정수 (62 . 1)

66 블록 삽입을 위한 인수 정수 (66 . 1)

210 3차원 확장 방향 점집합 리스트 (210 1.0 0.0 -0.5)

(ssadd <도형 요소 이름> <선택 집합>)

(ssdel <도형 요소 이름> <선택 집합>)

Page 31: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

<도형 요소 이름>의 도형 요소의 모든 데이터 리스트를 출력한다.

바뀌어진 도형 요소들의 결과에 따른 변화된 모양으로 화면의 모양을 변경한

다. <도형 요소 이름>을 출력한다.

<리스트>의 <구 요소> 부분을 <새 요소> 부분으로 대치한다.

<도형 요소 데이터> 값을 가지고 새로운 도형 요소를 만든다. <도형 요소 데이

터>는 entget의 형태로 주어진다.

199

AutoLISP 프로그래밍

<그림 2-4> ssget을 이용한 원의 선택

(entget <도형 요소 이름>)

(entupd <도형 요소 이름>)

(subst <새 요소> <구 요소> <리스트>)

(entmake <도형 요소 데이터>)

Page 32: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

3. 프로그래밍 예제

이 절에서는 AutoLISP을 이용하여 버스를 설계하는 방식에 대하여 기술하

다. 프로그래밍 방법이 아닌 CAD로서 오토캐드를 이용한 설계 방법은 가남

사의 "알기 쉽게 배우는 오토캐드"를 참고하기 바란다. 그 내용은 주어진 규격

의 버스를 설계하기 위하여 오토캐드를 어떻게 이용하는가에 관한 것이다. 이

와 같이 설계된 대상은 다시 읽어들여 위치를 변경하거나 크기를 스케일하는

것이 가능하다. 생산 모델에서는 이러한 기능을 넘어서 버스를 제작하기 위하

여 설계자가 고려하여야 할 여러 가지 내용들을 입력받아 설계를 행하여 나가

는 프로세스까지도 함축하여야 한다. 이러한 기능을 오토캐드만으로는 실현하

기 곤란하다.

CAD에 대한 프로그래밍 적용 방법으로 먼저 단순히 AutoLISP을 이용하

여 버스의 생산 모델을 개발하여 보겠다. 이와 같이 설계된 대상이 프로세스의

변경이나 부품 모양의 변경으로 인하여 수정을 가하여야 하는 경우 근본적으

로 많은 부분의 프로그램을 수정하여야 한다. OOP의 개념을 이용하면 이러한

200

제2 장 AutoLISP

<그림 2-5> 표준 규격의 버스 설계도

Page 33: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

여러 가지 문제점에서 혜택을 받을 수 있는데, AutoLISP으로 개발된 OOP

설계툴의 내용과 적용은 본장의 마지막 절에서 다루도록 한다.

(1) 버스설계프로그램의개요

2차원 도면의 버스를 설계하여 보자. 버스는 차체, 창문, 의자, 바퀴의 요소

로서 구성되고, 추가적으로 치수를 기입할 수 있도록 한다. <그림 2-5>은 표준

규격으로 만들어진 버스의 모양이다. 오토캐드 상에서 이와 같은 버스를 설계

하 다면, 설계의 수정이 요구될 때는 이를 변경할 수 있는 방법이 없다. 설계

프로세스의 과정까지 포함한 AutoLISP 프로그램은 이러한 기능을 갖추도록

할 수 있다.

<그림 2-6>, <그림 2-7>, <그림 2-8>은 설계시 입력으로 버스의 길이와 높이

혹은 타이어의 종류를 바꿀 수 있는 것을 보여준다. 원하는 길이 혹은 높이를

설계자가 판단하여 입력 파라미터를 바꾸어 주면 그에 따라 변화된 모양의 버

스가 설계된다.

버스 프로그램의 실행 방법은 다음과 같다. 먼저 오토캐드의 커맨드에서

201

프로그래밍예제

<그림2-6> 버스 길이의 변경

Page 34: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

bus.lsp를 로딩한다. initbus를 입력하고 임의의 포인트(point)를 선택하면,

표준 형태의 버스가 선택한 점으로부터 설계되어 나타난다. 버스의 형태의 변

경은 몇 가지 global variable을 바꾸어 주면 된다. *length*는 버스의 길이,

*height*는 버스의 높이, *tradius*는 타이어의 반지름이다. 가령 버스의 길

이를 조절하여 15 피트(feet)에 해당하는 길이로 하고 싶으면, 커맨트에서

(setq *length* '15)의 명령을 시행하고, (bus)의 function을 시행하고, 마찬

가지로 설계의 기준 점을 마우스로 선택하도록 한다. 프로그램은 부록에 설치

방법과 사용법이 설명되어 있다.

버스 설계 프로그램이 포함하고 있는 프로세스의 기능은 다음과 같다.

- 길이를 수정한다.

- 높이를 수정한다.

- 타이어의 지름을 수정한다.

- 설계의 시작점을 선택한다.

- 앞 타이어와 뒷 타이어의 위치를 차체의 크기와 타이어의 크기에 따라서 결정한다.

- 차체의 길이와 의자간의 간격을 감안하여 의자의 개수를 산출하고 등간격으로 배치한다.

- 차체의 길이와 창문간의 간격을 감안하여 창문의 개수를 산출하고 등간격으로 배치한다.

- 변화된 차체의 길이와 높이에 따라 치수를 기입한다.

<그림 2-9>는 전체적인 버스 생산 모델의 운용을 위한 소스 프로그램이다.

이를 설명하면 다음과 같다. 함수 initbus는 표준 규격의 버스를 만들기 위한

프로그램이다. 이는 general.lsp, body.lsp, tier.lsp, chair.lsp,

window.lsp의 다섯 개의 서브 프로그램을 읽어들이고 표준규격 버스를 설계

하기 위한 차체의 높이, 길이, 바퀴의 크기들을 정의한다. general.lsp에는

버스 설계 프로그램에서 필요한 일반적인 프로그램이, body.lsp에는 차체의

202

제2 장 AutoLISP

Page 35: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

설계에 대한 프로그램이, tier.lsp에는 바퀴의 설계에 대한 프로그램이,

chair.lsp에는 의자의 설계에 대한 프로그램이, window.lsp에는 창문의 설계

에 대한 프로그램이 들어 있다.

표준 규격의 버스 크기는 앞에서 설명한 바와 같이 *length*는 차체의 길이

를, *height*는 차체의 높이를, *tradius*는 바퀴의 반지름을 나타낸다. 이들

의 크기를 각각 10피트, 3피트, 0.6피트로 정의한다.

함수 버스는 버스 부품 각각의 위치를 잡아 주고 서브 프로그램을 불러서 설

계를 완성시키는 주프로그램이다. 이의 기능을 설명하면 먼저 화면상에서 버

스를 설계한 기준점을 읽어들인다. 이는 (getpoint)기능을 이용하여 버스를

설계하고자 하는 위치의 기준점을 마우스로 읽어들이고, 읽어들인 점은 bpos,

혹은 *initpoint*라고 하는 변수에 저장이 된다. 이후에 바퀴를 설치하기 위하

여 앞뒤 바퀴의 중심을 계산하는 과정을 수행한다.

두 개 바퀴의 크기의 합이 차체의 길이보다 클 경우와 그렇지 않을 경우에

대하여 각각 달리 계산을 한다. 두 개의 바퀴 크기의 합이 차체의 길이보다 클

경우에는 앞바퀴의 중심은 기준점으로부터 0.5피트 우측으로 그리고 차체의

높이 만큼 아래로 위치시키고, 뒷바퀴의 중심은 차체의 뒤끝 부분으로부터

0.5피트 좌측으로 그리고 차체의 높이 만큼 아래로 위치시킨다. 두 개 바퀴의

크기의 합이 차체의 길이보다 작을 경우에는 앞에서 차체 길이의 1/4 뒤로부

터 차체 길이의 1/4 되는 위치에 바퀴의 중심을 위치시킨다. 앞바퀴와 뒷바퀴

의 각각의 위치는 *tposition1*과 *tposition2*라는 global variable에 저장되

어 있다. 차체의 좌측 상단 모서리는 기준점에 맞추어 그려지고, 앞바퀴와 뒷

바퀴는 중심의 위치를 입력받아 그려진다.

의자의 설치 개수는 차체의 길이를 의자 하나가 점유하는 공간으로 나눔으

로써 구할 수 있다. 여기서 의자 하나를 설치하기 위하여 점유하여야 할 면적

은 0.8피트로 하 다. 변수 cn은 설치될 의자의 개수이다. 의자의 높이는 바

퀴의 최고 높이보다 0.5피트 높도록 설치되어야 하며, 이는 변수 ch에 할당된

203

프로그래밍예제

Page 36: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

다. 의자의 좌측 하단의 모서리를 기준으로 하여 계산된 개수의 의자를 반복

수행문 while을 사용하여 그리도록 되어 있다.

창문의 경우도 마찬가지이다. 창문의 설치 개수는 차체의 길이를 창문 하나

가 점유하는 공간으로 나눔으로써 구할 수 있다. 여기서 창문 하나를 설치하기

위하여 점유하여야 할 면적은 1.7피트로 하 다. 변수 wn은 설치될 창문의

개수이다. 창문의 높이는 차체의 높이의 1/3되는 곳에 설치되어야 하며, 이는

변수 wh에 할당된다. 창문의 좌측 하단의 모서리를 기준으로 하여 계산된 개

수의 의자를 반복 수행문 while을 사용하여 그리도록 되어 있다.

함수 bus-dim은 그려진 버스의 바퀴 사이의 거리와 높이의 치수를 기입하

도록 하 다. 첫번째 치수는 앞바퀴와 뒷바퀴간에 수평 치수 기입을 두번째 치

수 기입은 기준점으로부터 높이 만큼의 수직 치수 기입을 하도록 하 다.

지금까지는 버스를 설계하기 위한 전체적인 구조를 어떻게 설계하는가의 프

로그램에 대하여 살펴보았다. 각각의 부품들 즉 차체와 의자, 바퀴, 창문, 타

이어 등을 설계하는 부프로그램들에 대하여 살펴보도록 하겠다.

204

제2 장 AutoLISP

<그림 2-7> 버스 높이의 변경

Page 37: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(defun c:initbus ()

(load "c:/acad12/sample/bus/general")

(load "c:/acad12/sample/bus/body")

(load "c:/acad12/sample/bus/tier")

(load "c:/acad12/sample/bus/chair")

(load "c:/acad12/sample/bus/window")

(setq *length* '10)

(setq *height* '3)

(setq *tradius* '0.6)

(bus)

(command "redraw")

)

(defun bus ()

(setq bpos (getpoint))(terpri)

205

프로그래밍예제

<그림 2-8> 타이어 크기의 변경

Page 38: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq *initpoint* bpos)

(setq t1 (/ *length* 4))

(if (> *tradius* t1)

(setq *tposition1* (list (+ (+ (car bpos) *tradius*) 0.5)

(- (nth 1 bpos) *height*)

(nth 2 bpos))

*tposition2* (list (- (- (+ (car bpos) *length*) *tradius*) 0.5)

(- (nth 1 bpos) *height*)

(nth 2 bpos)))

(setq *tposition1* (list (+ (car bpos) t1)

(- (nth 1 bpos) *height*)

(nth 2 bpos))

*tposition2* (list (- (+ (car bpos) *length*) t1)

(- (nth 1 bpos) *height*)

(nth 2 bpos))))

(body bpos)

(tier *tposition1*)

(tier *tposition2*)

(setq cn (/ *length* 0.8))

(setq ch (- (- *height* *tradius*) 0.5))

(setq cp (list (+ (car bpos) 0.2) (- (nth 1 bpos) ch) (nth 2 bpos)))

(setq c '1)

(while (< c cn)

(chair cp)

(setq cp (cons (+ (car cp) 0.8) (cdr cp)))

(setq c (+ c 1)))

206

제2 장 AutoLISP

Page 39: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq wn (/ *length* 1.7))

(setq wh (/ *height* 3))

(setq wp (list (+ (car bpos) 0.5) (- (nth 1 bpos) wh) (nth 2 bpos)))

(setq w '1)

(while (< w wn)

(window wp)

(setq wp (cons (+ (car wp) 1.7) (cdr wp)))

(setq w (+ w 1)))

(bus-dim)

(command "redraw")

;; (window bpos)

)

(defun bus-dim ()

(command "dim" "hor" *tposition1* *tposition2*

(mp *tposition1* 0 -1 0) "")

(command "dim" "ver" *initpoint* (mp *initpoint* 0 (- 0 *height*) 0)

(mp *rmp* -1 0 0) "" "exit")

)

<그림 2-9> AutoLISP을 이용한 생산 모델의 작성 프로그램

주프로그램은 차체의 높이, 길이, 타이어 반지름 등을 입력받아 우선 차체를

그린다. 차체의 길이에 따라서 적당한 개수의 창문과 의자를 선정하여 반복해

그리고, 차체의 하중을 견딜 수 있도록 길이를 배분하여 적당한 위치에 두 개

의 타이어를 설치한다. 이 과정에서 general.lsp, body.lsp, window.lsp,

207

프로그래밍예제

Page 40: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

tier.lsp, chair.lsp의 5개의 부 프로그램이 사용되는데, 각각의 역할과 기능은

다음과 같다.

(2) 기능적부프로그램

general.lsp는 기하학적인 모양과 관계없이 일반적인 필요에 의한 세 가지

기능을 포함하고 있다. 기능 ea는 erase all을 뜻하는데, 새로운 변수로서 버

스를 다시 설계할 때 모든 설계 요소를 지우는 기능을 갖추고 있다. (entlast)

는 최종의 입력된 설계 요소를 지정하는 기능으로, 이를 이용하여 마지막 요소

를 순차적으로 지워감으로써, 현재의 설계 데이터베이스에 남아 있는 모든 요

소들을 제거하도록 한다.

두번째의 기능인 sel-entities는 어떤 특정 시간에 생성된 엔티티로부터 이

후의 시간에 생성된 엔티티에 이르기까지 그사이의 모든 엔티티들을 선택하기

위한 기능이다. 이는 두 개의 입력을 취한다. 첫번째는 선택하고자 하는 시작

엔티티이고 두번째는 끝으로 선택되어야 할 엔티티이다. 첫번째 엔티티 이후

에 새로운 selection set sn1을 만들고, 마지막 엔티티를 만날 때까지 엔티티

를 sn1에 추가시켜 가면서 엔티티 포인터를 증가시켜 나간다. 이러한 과정으

로 누실된 최종 엔티티는 따로 selection set에 추가시킨다. mp는 상대적인

거리로서 기준점을 움직이기 위한 기능이다. 주어진 임의의 점으로부터 x 방

향, y 방향, z 방향으로 움직이기 위한 상대적 거리를 입력하여 출력된 결과를

*rmp*에 보관한다.

(3) 버스차체만들기

이외의 4가지 부프로그램은 기하학적인 모양을 그리는 프로그램으로서,

body.lsp는 차체의 모양을 만든다. 먼저 프로그램은 차체의 좌측 상단의 모서

리의 점을 입력받는다. 이때 입력받는 점은 pt1에 local variable로 저장되고,

pt2는 우측 상단 모서리의 점으로 계산된다. pt3는 우측 하단 모서리의 위치

208

제2 장 AutoLISP

Page 41: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

로 계산되고, pt4는 좌측 하단 모서리 점으로 계산된다. 이어서 4개의 점을

모서리로 갖는 폴리라인(polyline)을 만들고, 이것을 반지름 0.25로 필레팅

(filletting)한다.

(4) 창문만들기

window.lsp는 버스의 창문을 그리는 부프로그램이다. 역시 기준점을 입력

받는데, 이는 왼쪽 상단의 내부 유리 모서리가 된다. 창문의 모양이 대칭이라

는 사실을 주목하여 반쪽 창문을 만든 후에 미러링(mirroring)을 하는 방법을

선택한다. 미러링(mirroring)을 하기 위한 entity group selection을 목적으

로 시작하기에 앞서 하나의 엔티티를 se라는 이름으로 선택을 하여 둔다. 반쪽

창문을 그리고 난 후 바로 마지막 엔티티를 ee라고 선택하고, se로부터 ee까

지 생성된 모든 엔티티들을 앞서의 general.lsp에서 소개된 sel-entires의 기

능을 이용하여 선택한다.

반쪽 창문을 그리는 방법은 다음과 같다. 먼저 내부 유리를 그리기 위하여

0도 방향으로 0.7 만큼 (왼쪽으로 0.7 만큼), 하단으로 0.9 만큼, 좌측으로

209

프로그래밍예제

<그림 2-10> 버스 차체의 설계 순서

Page 42: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

0.7 만큼 그리고 이를 닫음으로써 내부 유리를 완성한다. ref1은 손잡이의

위치가 시작되는 점이다. 손잡이가 완성된 후에는 내부 유리로부터 창틀을

그린다. 창틀은 내부 유리를 표현하는 사각형으로부터 offset을 이용하여 완

성할 수 있다. 내부 유리의 윤곽을 그릴 때 생성되었던 선을 찾아서 그로부터

순차적으로 line1, line2, line3, line4 의 각 변을 구성하는 선 요소들을 지

시하도록 한다. 윗변을 나타내는 line1은 상측으로 offset 0.05 만큼을 움직

이고, 하변을 나타내는 line2는 아래쪽으로 offset 0.05 만큼을 움직이며, 좌

변을 나타내는 line4는 좌측으로 0.05 만큼을 움직이도록 한다. 이후 새로

생성된 선분중 상측과 좌측, 하측과 좌측 선분에 각각 반지름 0.05를 갖는

필렛(fillet)을 생성하도록 한다. 지금까지 생성된 반쪽의 창문을 완성하기 위

하여 line2를 중심으로 하여 미러링을 하는 기능을 활용한다. mirror는 대칭

시키고자 하는 선택된 대상체와 대칭선을 입력으로 요구한다. 구체적으로 대

칭선은 두 점을 잇는 직선으로 주어진다. 이러한 정보는 line2의 10번째 요

소인 시작점의 정보와, 11번째 요소인 종점에 대한 정보를 회수하여 이용할

수 있다.

210

제2 장 AutoLISP

<그림 2-11> 버스 창문의 설계 순서

Page 43: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(5) 바퀴만들기

바퀴는 4개의 동심원과 6개의 볼트의 위치를 표시하는 소형의 원으로 표현

된다. 먼저 부프로그램 tier.lsp는 바퀴의 중심을 위치로 입력받는다.

*tradius*는 바퀴의 외곽 반경이고 이에 따라서 0.67의 비율로, 0.58, 0.08

의 반지름의 배율을 갖는 원들을 그린다. 이 세 개의 원은 바퀴의 살에 해당

하는 부분이다. 바퀴 살을 완성하기 위하여 볼트 머리를 만든다. 먼저 육각

형의 볼트 머리를 pt1을 중심으로 반지름 0.025의 원을 외접하도록 그린다.

그리고 이것을 배열하는데 극좌표 형식으로 pt를 중심으로 하여 6개를 360

도의 각도를 돌아가면서, 각각의 요소들도 위치에 따라서 회전시키면서 그리

게 된다.

(6) 의자만들기

마지막으로 의자는 등받이와 밑받침의 연결 부분과 의자 받침의 두 가지의

조합으로 그려진다. 그림에서 나타난 바와 같이 의자의 모양이 polyline의 형

태로 그려져 있다.

211

프로그래밍예제

<그림 2-12> 버스 바퀴의 설계 순서

Page 44: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

이상에서 버스 자동 설계 생산 프로그램의 부프로그램들을 살펴보았다. 현

장에서의 필요로 많은 설계 변경, 혹은 생산상의 개념 수정을 요하는 경우가

발생한다. 그에 따라서 설계 생산 프로그램을 변경할 때 고려하여야 할 사항은

최소한의 노력으로 주어진 코드를 재사용함으로써 신속하게 변경 요구에 대응

할 수 있는가에 대한 것이다. 이러한 경우 주어진 설계 생산 개념을 바꾸었을

때 이상의 프로그램에서 변경하여야 하는 내용과 과정을 다음 절에서 살펴보

도록 하자.

(defun c:ea ()

(while (entlast)

(command "erase" (entlast) ""))

)

(defun sel-entries (e1 e2)

(setq ce e1)

212

제2 장 AutoLISP

<그림 2-13> 버스 의자의 설계 순서

Page 45: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq sn1 (ssadd))

(while (not (equal ce e2))

(setq ce (entnext ce))

(setq sn1 (ssadd ce sn1))

(prin1 ce))

(setq sn1 (ssadd e2 sn1))

)

(defun mp (pt x y z)

(setq *rmp*

(list (+ x (car pt)) (+ y (nth 1 pt)) (+ z (nth 2 pt)))

)

)

(defun body (base_point)

(setq pt1 base_point)

(setq pt2 (cons (+ (car base_point) *length*) (cdr base_point)))

(setq pt3 (list (car pt2) (- (nth 1 pt2) *height*)

(nth 2 pt2)))

(setq pt4 (list (car base_point) ( - (nth 1 base_point) *height*)

(nth 2 base_point)))

(setq ref1 (cons (+ (car pt1) 0.05)

(cons (- (cadr pt1) 0.5) (cddr pt1))))

(if (null (entlast)) (command "point" '(0 0 0)))

213

프로그래밍예제

부 프로그램 general.lsp

Page 46: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(command "pline" pt1 pt2 pt3 pt4 "c")

(setq tem (entlast))

(command "fillet" "R" "0.25")

(command "fillet" "P" tem)

(setq t1 (list (+ (car pt1) 2) (- (nth 1 pt1) 3)))

)

(defun window (pt1)

(setq ref1 (cons (+ (car pt1) 0.05)

(cons (- (cadr pt1) 0.5) (cddr pt1))))

(if (null (entlast)) (command "point" '(0 0 0)))

(setq se (entlast))

(command "line" pt1 "@.7<0" "@.9<270" "@.7<180" "c")

(command "line" ref1 "@.1<90" "@.05<0" "@.1<270" "c")

(setq line1 (entnext se))

(setq line2 (entnext line1))

(setq line3 (entnext line2))

(setq line4 (entnext line3))

(command "copy" line1 "" '(0 0 0) '(0 0.05 0))

(setq oline1 (entlast))

(command "copy" line3 "" '(0 0 0) '(0 -0.05 0))

(setq oline3 (entlast))

(command "copy" line4 "" '(0 0 0) '(-0.05 0 0))

(setq oline4 (entlast))

(command "fillet" "R" "0.05")

214

제2 장 AutoLISP

부 프로그램 body.lsp

Page 47: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(command "fillet" oline1 oline4)

(command "fillet" oline3 oline4)

(setq ml1 (cdr (assoc 10 (entget line2))))

(setq ml2 (cdr (assoc 11 (entget line2))))

(setq ee (entlast))

(sel-entries se ee)

(command "mirror" sn1 "" ml1 ml2 "N")

(prin1 ce)

)

(defun tier (pt)

(command "circle" pt *tradius*)

(command "circle" pt (* *tradius* 0.67))

(command "circle" pt (* *tradius* 0.58))

(command "circle" pt (* *tradius* 0.08))

(setq pt1 (list (car pt) (+ (nth 1 pt) 0.15) (nth 2 pt)))

(command "polygon" "6" pt1 "c" "0.025")

(setq t1 (entlast))

(command "array" t1 "" "P" pt "6" "" "Y")

)

(defun chair (pt)

(command "line" pt "@0.55<355" "@0.8<80"

"@0.11<0" "@0.95<260" "@0.63<180" "c")

215

프로그래밍예제

부 프로그램 window.lsp

부프로그램 tier.lsp

Page 48: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq pt1 (list (+ (car pt) 0.1) (- (nth 1 pt) 0.2) (nth 2 pt)))

(command "line" pt1 "@0.25<270" "@0.5<0" "@0.25<90" "c")

)

<그림 2-14> 버스 자동 설계 부 프로그램

216

제2 장 AutoLISP

부프로그램 chair.lsp

Page 49: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

4. 객체 지향 방식의 구현

이번 절에서는 지금까지 살펴본 버스의 모양을 수정하는 경우 프로그램을

어떠한 방식으로 변경하는지에 대하여 알아보자. 주어진 프로그램을 수정하기

위해 각각의 프로그램 레벨에서 수정시 교정하여야 할 부분을 살펴보자.

원래 프로그램의 구조에서 bus.lsp은 전체의 버스 구조를 다루고 있으며 이것

을 이용하여 하부 단계에서 바퀴, 의자, 창문, 차체를 선정된 지점에 위치시켰

다. 새로운 프로그램은 두 단계의 구조를 가지고 있으며 여기에서 차의 상단에

환기통 덮개를 추가하고, 창문의 모양을 바꾸고, 의자의 위치에 대하여 상대적

으로 승객을 위치시키는 세 단계의 구조를 갖는 프로그램으로 변경하도록 한다.

각각의 변경은 프로그램을 수정하기 위하여 거쳐야 하는 과정을 설명하기

위하여 설정하 다. 즉 차의 상단에 환기통 덮개를 추가하는 것은 가장 상위의

레벨에서 부품을 추가하게 되는 경우에 대한 프로그램의 수정 작업을 살펴보

려는 것이고, 창문의 모양을 바꾸는 것은 하나의 독립된 모듈을 수정하는 경우

에 대하여, 승객을 위치시키는 것은 구조적인 레벨의 단계를 증가시키는 경우

217

객체지향방식의구현

<그림 2-15> 환기통 덮개의 추가

Page 50: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

에 대하여 살펴보고자 하는 이유에서이다. 궁극적으로 일반적인 LISP 프로그

램을 사용하는 경우에는 그 모듈화의 한계 때문에 각 레벨에서 혹은 상위 레벨

에서의 자체 프로그램을 수정하는 작업을 거치지 않을 수 없고 이러한 것이 일

반적인 프로그램에서의 문제점으로 지적되어 있는 바이다. 객체지향의 프로그

램을 적용함으로써 이러한 문제점들을 해결할 수 있는 데, 이것에 대한 구체적

인 방법론은 다음 절에서 다루고자 하고 각각의 변경에 대한 수정 내용에 따라

항목별로 그 내용을 살펴보도록 하자.

(1) 기존버스설계프로그램의수정

1) 환기통 덮개의 추가

함수 커버는 상단의 차체의 환기통 덮개 모양을 만들어 이를 추가하고자 하

는 목적에서 만들어졌다. 다른 부품의 추가와 마찬 가지로, 모프로그램인

bus.lsp에서 cover가 놓여질 위치를 산출하고 그곳에 cover를 설치하 다. 차

체의 길이의 1/3.5 되는 곳과 2/3.5 되는 곳에 위치하도록 하 다. 프로그램

중의 *cv1*, *cv2*는 두 개의 환기통이 놓여질 위치를 표시하며, 결국 하나의

항목을 추가하기 위하여 그 항목이 추가될 모프로그램을 변경하여야 한다.

(defun cover (pt / t1 t2 t3)

(setq t1 (entlast))

(command "line" pt "@1<0" "@0.3<90" "@1<180" "c")

(setq t2 (entlast))

(sel-entries t1 t2)

(command "rotate" sn1 "" pt 30)

)

(defun bus ()

218

제2 장 AutoLISP

Page 51: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq bpos (getpoint))(terpri)

(setq *initpoint* bpos)

(setq t1 (/ *length* 4))

(if (> *tradius* t1)

(setq *tposition1* (list (+ (+ (car bpos) *tradius*) 0.5)

(- (nth 1 bpos) *height*)

(nth 2 bpos))

*tposition2* (list (- (- (+ (car bpos) *length*) *tradius*) 0.5)

(- (nth 1 bpos) *height*)

(nth 2 bpos)))

(setq *tposition1* (list (+ (car bpos) t1)

(- (nth 1 bpos) *height*)

(nth 2 bpos))

*tposition2* (list (- (+ (car bpos) *length*) t1)

(- (nth 1 bpos) *height*)

(nth 2 bpos))))

(body bpos)

(tier *tposition1*)

(tier *tposition2*)

(setq cn (/ *length* 0.8))

(setq ch (- (- *height* *tradius*) 0.5))

(setq cp (list (+ (car bpos) 0.2) (- (nth 1 bpos) ch) (nth 2 bpos)))

(setq c '1)

(while (< c cn)

(chair cp)

(setq cp (cons (+ (car cp) 0.8) (cdr cp)))

219

객체지향방식의구현

Page 52: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq c (+ c 1)))

(setq wn (/ *length* 1.7))

(setq wh (/ *height* 3.5))

(setq wp (list (+ (car bpos) 0.5) (- (nth 1 bpos) wh) (nth 2 bpos)))

(setq w '1)

(while (< w wn)

(window wp)

(setq wp (cons (+ (car wp) 1.7) (cdr wp)))

(setq w (+ w 1)))

(bus-dim)

(setq t2 (/ *length* 3.5))

(setq *cv1* (cons (+ (car bpos) t2) (cdr bpos)))

(setq *cv2* (cons (+ (car bpos) (* t2 2)) (cdr bpos)))

(cover *cv1*)

(cover *cv2*)

(command "redraw")

)

<그림 2-16> 환기통 설치를 위한 변경후 프로그램

2) 창문 모양 변경

현재 직사각형의 모양을 타원 형태로 바꾸어준다. 단순한 타원의 모양을 만

들기 위하여 타원이 필요로 하는 세 개의 입력점 pt1, pt2, pt3를 주어진 함

수 입력을 가지고 산출하 다. 수정을 요하는 프로그램은 단순히 함수 윈도

(window)이지만 그 이름을 바꾸어주고 모프로그램이 혼돈하지 않도록 원래의

함수는 그 이름을 바꾸어주거나 삭제하여야 한다.

220

제2 장 AutoLISP

Page 53: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(defun window (point / pt1 pt2 pt3)

(setq pt1 (cons (car point)

(cons (- (nth 1 point) 0.5)

(cddr point))))

(print pt1)

(setq pt2 (cons (+ (nth 0 pt1) 1.6)

(cdr pt1)))

(setq pt3 (cons (+ (car point) 0.8)

(cdr point)))

(command "ellipse" pt1 pt2 pt3))

<그림 2-18> 창문 모양 변경후 프로그램

3) 승객의 추가

승객을 의자에 앉히기 위하여 의자의 위치를 참고하여 승객을 위치하도록

하 다. 승객의 모양을 실제로 그려서 그것을 block의 형태로 저장하고 블럭

221

객체지향방식의구현

<그림 2-17> 창문의 모양 변경

Page 54: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

의 이름을 ok로 하 다. 승객의 위치는 의자의 좌측 끝 모서리인 점으로부터

0.5 만큼 우측으로 이동한 위치를 승객이 착석시 위치하게 되는 insert point

로 하 다. 의자의 하부 단계에 의자의 좌표를 표준으로 하는 person이라는

부프로그램을 작성하 다. ok라는 이름의 블럭은 프로그램의 작동 전에 블럭

으로 생성되어 있어야 한다.

(defun chair (pt)

(command "line" pt "@0.55<355" "@0.8<80"

"@0.11<0" "@0.95<260" "@0.63<180" "c")

(setq pt1 (list (+ (car pt) 0.1) (- (nth 1 pt) 0.2) (nth 2 pt)))

(command "line" pt1 "@0.25<270" "@0.5<0" "@0.25<90" "c")

(person (cons (+ (car pt) 0.5) (cdr pt)))

)

(defun person (pt)

(command "insert" "ok" pt "" "" "")

)

<그림 2-19> 승객 추가 변경후 프로그램

이상의 내용으로부터 일반적인 순차적 프로그램에서 수정시 거쳐야 하는 과

정을 살펴보았다. 프로그램의 수정을 최소화할 수 있는 경우는 어떤 모듈이 확

보되어 있으며 그 모듈만을 변경하는 경우이다. 예를 들면 창문은 이미 기존

프로그램에서 하나의 모듈로 확보되었고 이의 속성이나 모양을 변경할 필요가

있을 때에는 그 모듈만을 고치면 되었다. 프로그램 작성시에 그의 구조를 완전

히 모듈화하며, 그 모듈들 사이에 변화가 없이 모듈 내에서만 프로그램을 변경

하게 된다면 그에 대한 수정 사항의 발생 시에는 그 모듈만을 수정하면 되고,

222

제2 장 AutoLISP

Page 55: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

전체 프로그램의 관리와 기존의 프로그램 코드는 효율적으로 재사용될 수 있

다. 버스의 프로그램을 예로 들면, 버스를 설계시 다른 부품의 추가없이 있는

부품을 변경함으로써 항상 새로운 설계 요구를 만족할 수 있다면 즉, 차체의

모양, 창문의 모양, 타이어의 모양, 의자의 모양만을 변경한다면 자체만으로도

재사용의 효율이 높은 프로그램이 될 것이다.

대부분의 프로그램에 있어서 발생하는 문제는 이와 다르다. 즉 주어진 모듈

내에서 변경을 하는 것을 전제로 한다면 재사용의 효율이 높은 프로그램을 초

기 단계에서부터 작성을 할 수 있고 프로그램 재사용의 효율 향상은 전체 프로

그램 작업의 작업 효율 향상과 직결되어 작업 능률의 향상을 꾀할 수 있다. 그

러나 이미 주어진 예로부터 알 수 있듯이, 작성하여야 할 프로그램의 변화는

예측하기 힘들고, 이의 경우를 모두 고려하여 프로그램을 작성한다는 것은 불

가능하다. 즉 버스의 경우에서 환기통을 추가한다든지 승객을 추가한다든지

하는 경우는 필요에 의해서 존재하지 않았던 요소를 추가하여야 하는 경우에

해당하고 대부분의 작업시 이러한 경우가 발생하게 된다.

이러한 경우에 작업의 효율을 높이기 위해서는 여러 가지의 개념을 생각할

223

객체지향방식의구현

<그림 2-20> 승객의 추가

Page 56: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

수 있다. 우리가 이용할 수 있는 방법 중의 하나로 Inheritance(상속성)의 개

념을 이용할 수 있다. 이는 형질을 상속받는다는 것을 의미하는데, 기존 프로

그램의 모듈로부터 프로그램의 속성을 그대로 받아서 쓸 수 있는 방법을 의미

하는 것이다. 프로그램의 모듈화를 높이기 위하여, Data abstraction,

encapsulation의 방법들을 이용하는데 이는 모두 프로그램의 모듈화를 높이

기 위하여 취하는 방법이다. 객체지향 언어를 거론할 때마다 항상 언급되는

Data hiding의 기법도 간과할 수는 없다.

결론부터 말하자면, AutoLISP은 객체지향형의 언어가 아니다. 이것을 이

용하여 객체지향 프로그램의 기능을 이용하려면 그러한 환경을 만들어주어야

한다. 그러한 개발 환경을 객체지향형으로 근사하게 개발하는 것이 가능한데

이러한 것은 AutoLISP 프로그래밍으로서 가능하다. 객체지향형의 프로그래

밍 기법이 지원하여 주는 장점을 보여주기 위하여 엔진의 설계에 대한 예를 들

어보겠다.

(blk

(blk_name "none")

(i_point '(0 0 0))

(draw (command "insert" (the 'blk_name) (the 'i_point) "" "" ""))

)

(test_piece

(children (part1 part2 part3 part4))

)

(part1

(a-kind-of (blk))

224

제2 장 AutoLISP

Page 57: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(blk_name "part1")

(parents (test_piece))

)

(part2

(a-kind-of (blk))

(blk_name "part2")

(parents (test_piece))

)

(part3

(a-kind-of (blk))

(blk_name "part3")

(parents (test_piece))

)

(part4

(a-kind-of (blk))

(blk_name "part4")

(parents (test_piece))

)

<그림 2-21> 객체지향 환경을 이용한 엔진 설계 프로그램

이상은 객체지향의 환경을 지원하기 위해 개발한 환경을 엔진의 설계를 이

용하여 보여주었다. 설계된 도면으로부터 블럭을 설정한 상태에서 이것을 이

용하여 각각의 위치를 설정하여 객체별로 대상을 다루는 방식이 가능하다. 엔

225

객체지향방식의구현

Page 58: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

진은 오토캐드에서 주어진 샘플중의 하나로서 그것을 구성하는 여러 개의 부

품을 갖고 있다. <그림 2-22>는 주어진 샘플에서의 엔진의 모양을 나타낸다.

실제로 엔진이 어떠한 속성을 가지며 각각의 부품이 어떠한 위치 관계를 갖는

지는 거론하지 않고 단지 개발 환경의 적용 가능성만을 시사하고자 한다.

우선은 각각의 부품을 오토캐드에서의 블럭으로 인식시킨다. 좌측에 상하로

분포하는 부품들을 상단으로부터 part1, part2, part3, part4라는 이름으로

블럭으로 인식시킨다. 이는 커맨드 상태에서 block를 치면 블럭의 이름을 요

구하는데 이때 part1(최상단의 부품의 경우)을 입력하고 기준이 되는 insert

point를 요구할 때 그 부품을 다루고자 하는 점을 선택한다. 이후에 블럭화 하

고자 하는 대상을 선택하면 된다. 이러한 방식으로 4개의 부품을 각각 블럭화

한다. 엔진의 도면은 오토캐드의 샘플 디렉토리(sample directory)에서 찾을

수 있다.

입력된 블럭을 표시하는 방법은 커맨드 상태에서 insert를 치면 삽입하고자

하는 블럭의 이름을 묻는다. 이때 블럭의 이름을 입력하면 현 도면의 어느 위

치에 입력할 것인가를 요구한다. 이후의 세 단계에서는 스케일 여부와 회전 여

226

제2 장 AutoLISP

<그림 2-22> 엔진의 sample 도면

Page 59: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

부를 묻는다. 이상의 프로그램의 blk는 이러한 기능을 지원하는 block 생성

객체를 보여준다. 추가적으로 원하는 변수값을 변경할 수 있도록 블럭의 이름

과 삽입 위치를 인수로 갖고 있다.

엔진의 도면에서 임의로 선택한 4개의 블럭으로 구성된 새로운 부품을 만들

기 위해서 test_piece 라는 이름의 새로운 부품을 정의하고 이것이 4개의 부품

을 갖는다는 선언을 한다. 즉 (children (part1 part2 part3 part4))는 이러

한 작업을 수행한다. 4개의 부품은 이미 만들어진 block의 개념을 이용하여

생성할 수 있다. 즉 part1의 경우, 이것은 blk로부터 모든 속성을 물려받으

며, 단지 그 블럭의 이름만을 part1이라는 블럭으로 한다는 것을 표시한다.

이하의 3개의 부품에 대해서도 동일한 방식으로 선언을 하게 된다.

간단한 설명을 위하여 i_point의 위치는 고려하지 않았다. 각 부품의 속성을

고려한 위치 결정은 원하는 만큼의 인수를 추가하고 이를 이용함으로써 고도

의 활용이 가능하게 된다. 다음 절에서는 이러한 개발 환경을 어떻게

AutoLISP을 이용하여 만들 수 있는지를 설명하도록 하겠다.

227

객체지향방식의구현

<그림 2-23> 개발 환경을 이용한 위치

이동

Page 60: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(2) AutoLISP에서의객체지향형프로그래밍구현

앞 절에서는 객체지향형 프로그래밍의 방식을 간단히 소개하 다.

AutoLISP은 객체 지향형의 언어는 아니다. ADS(AutoCAD Development

System)는 현재 주목받고 있는 C++의 객체지향적 프로그램을 이용하여 오토

캐드를 이용하고자 하는 의도에서 개발되었다. 이는 컴파일러 형식의 개발 도

구인데 경우에 따라서는 인터프리터(Interpreter) 형식의 개발 도구가 더욱

유용한 경우가 있다. 예를 들어 수시로 부품을 개발하고 추가, 삭제, 수정 등

의 작업을 요하는 설계 과정이 한 번에 프로그램을 작성하고 이를 컴파일하여

작업을 하는 방법보다는 수시로 현재의 작업 상태에 대한 응답식의 환경을 제

공하는 interpreter형이 더욱 유리하다. AutoLISP으로 객체지향 방식의 개

발 도구를 제작한 내용을 살펴보자.

개발된 시스템은 완전한 OOP의 개발 도구보다는 실제적으로 활용하여 유익

한 기능들을 갖추도록 하 으며 이러한 기능으로는 Data encapsulation,

Inheritance, 그리고 객체 상호간의 관련 위치를 제어할 수 있는 기능들을 들

수 있다. 이 세 가지의 기능들을 차례로 살펴보도록 하자.

1) Data Encapsulation

하나의 객체를 설계할 때는 원하는 모든 정보를 인수화하여 포함시켜야 한

다. 예로써 다음의 구조를 살펴보자.

(rect

(center (0 0 0))

(low_corner (list (- (car (the 'center)) (/ (the 'width) (float 2)))

(- (nth 1 (the 'center)) (/ (the 'height) (float 2)))

(nth 2 (the 'center))))

(width 1)

228

제2 장 AutoLISP

Page 61: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(height 1)

(draw (command "line" (the 'low_corner)

(list (+ (car (the 'low_corner)) (the 'width))

(nth 1 (the 'low_corner))

(nth 2 (the 'low_corner)))

(list (+ (car (the 'low_corner)) (the 'width))

(+ (nth 1 (the 'low_corner)) (the 'height))

(nth 2 (the 'low_corner)))

(list (car (the 'low_corner))

(+ (nth 1 (the 'low_corner)) (the 'height))

(nth 2 (the 'low_corner)))

"c")))

<그림 2-24> 직사각형 객체의 표현 방식

이상은 하나의 직사각형을 객체의 형태로 표시하는 방식을 보여준다. 일반

적으로 하나의 직사각형을 나타내기 위하여 그 길이와 높이가 주어져야 한다.

그리고 이것이 원하는 좌표 상에 위치하기 위하여 그것의 위치를 표시하는 부

분이 필요하다. 객체 rect는 width, length, center, low_corner 등을 인수

로 갖는다. 즉 하나의 직사각형이 갖는 넓이는 width, 길이는 length로 표시

한다. 또한 좌표상에서의 직사각형의 중심은 center로 표시된다. low_corner

는 좌측 하단의 꼭지점을 표시하는 임의의 인수로 추가를 하 다. 인수 draw

는 이러한 객체의 파라미터적인 인수로부터 실제의 기하학적인 요소들을 생성

하는 부분이다.

전체적인 구조를 볼 때 하나의 객체를 나타내는 모든 인수들은 동일하게 표

현이 된다. 즉 하나의 객체에 관한 모든 정보들은 그것을 나타내는 인수들의

229

객체지향방식의구현

Page 62: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

조합으로서 표현이 되며, 각각의 인수는 encapsulate되어 있다고 볼 수 있다.

앞서의 표현 방식을 살펴보면 각각의 인수들은 객체 내부에서의 인수간의 내

용들을 참고하고 있음을 알 수 있는데, draw 인수 내부의 function "the"는

이러한 기능을 수행하도록 작성되어 있다. 즉 직사각형을 그리기 위하여 실제

적인 도형 요소는 좌측 하단의 꼭지점에서 우측 하단의 선분을, 우측 하단에서

우측 상단, 우측 상단에서 좌측 상단의 선분을 차례로 그리도록 하는데, 이는

각각의 인수에서 정의된 값들을 이용한다.

한 번 생성된 객체는 수정 또는 보완이 가능하며 그에 대한 정보의 회수도

가능하다. 하나의 객체는 다른 객체에서 혹은 interpreter에 의한 명령으로 각

각 그 내용을 확인하고 이용할 수 있다. 예를 들면 생성된 한 직사각형 객체의

중심을 알고 싶다면 (the 'center)와 같은 형태의 interpreter 명령어를 수행

함으로써 가능하다.

또 하나의 특징은 입력을 다변화할 수 있다는 것이다. 주어진 직사각형의 객

체가 기하학적으로 의미있게 생성되려면, 넓이와 높이 그리고 중심의 위치가

필요하다. 그러나 좌측 하단의 꼭지점 위치를 지정하여 도형을 생성하는 것도

가능한데 이는 low_corner 인수가 길이, 높이, 중심의 세 가지 입력을 이용하

여 얻어지도록 되어 있으나, 실제적인 도형 생성시 직접 입력을 받음으로써 도

형을 생성하는 것이 가능하다. 즉 길이, 높이, 좌하단 꼭지점을 입력함으로써

도형을 생성할 수도 있다. 이외에도 필요한 인수를 설정하여 추가함으로써 원

하는 입력을 다양화할 수 있다.

2) Inheritance

하나의 객체를 생성하고 이것을 이용하여 또 다른 객체를 생성할 경우 원래

의 객체가 가지고 있던 형질을 대부분 다시 이용하고 싶을 경우가 있다. 물론

이 형질이란 인수로 표시된 객체의 정보와 그 상호간의 연결 관계를 의미한다.

다음의 구조를 예로서 설명하도록 하자.

230

제2 장 AutoLISP

Page 63: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(basedraw

(local_point (0 0 0))

(model_point (0 0 0))

(rotate 0))

(robot

(a-kind-of (basedraw rect))

(children (body head arm1))

(width 5)

(height 8)

(rotate 0))

(arm1

(a-kind-of (rect))

(children (arm2))

(parents (robot))

(width 5)

(height 1)

(local_point (-2 0 0))

(model_point (0 0 0))

(rotate 45))

(arm2

(a-kind-of (arm1))

(children (arm3))

(parents (arm1))

231

객체지향방식의구현

Page 64: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(model_point (2 0 0))

(rotate 90))

(arm3

(a-kind-of (arm1))

(parents (arm2))

(children (arm4))

(model_point (2 0 0))

(rotate -45))

(arm4

(a-kind-of (arm1))

(parents (arm3))

(children ())

(model_point (2 0 0))

(rotate -90))

(body

(a-kind-of (basedraw rect))

(parents (robot))

(width 4)

(height 5))

(head

(a-kind-of (basedraw rect))

(model_point (0 2.5 0))

232

제2 장 AutoLISP

Page 65: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(parents (robot))

(width 1)

(height 1.5)

(rotate 10)

(center (0 0.7 0)))

<그림 2-25> 로봇 객체의 표현 방식

위의 예제는 inheritance의 유용함에 대한 적절한 예제를 제시하여 준다.

robot이라는 객체는 여러 개의 관절(arm)로 구성되어 있다. 각각의 관절은

직사각형 형태의 모양을 갖고 있다. 직사각형의 객체를 만드는 rect의 객체에

대하여는 이미 언급하 다. 이러한 rect 객체의 형질을 이어받은 객체를 제작

함으로써 시간을 절약할 수 있다.

객체 robot은 body head arm1의 세계의 자 객체로 구성되어 있고, arm1

은 arm2의 부품을, arm2는 arm3를, arm3는 arm4를 갖고 있다. 모든 부

품은 직사각형 형태의 모양을 갖추고 있다. 이미 만들어진 객체 rect를

inherit하고 있다. a-kind-of 인수는 현재의 객체가 어떠한 객체들로부터 형

질을 유전받을 것인지를 결정한다. robot 객체에 속한 모든 부품들은 rect의

형질을 이어받고 있다.

유전은 여러 가지의 객체로부터도 가능하다. 예를 들어 robot은 a-kind-of

인수로서 rect와 basedraw의 두 가지로부터 받고 있는데 여러 가지의 기능을

원하는 만큼 유전받을 수 있다. 한편 주어진 형질에 교정을 원하거나 추가할

부분에 대해서는 인수를 추가하게 된다. 객체 robot은 넓이 5와 높이 8을 갖

는 직사각형을 나타낸다. arm1은 넓이 5, 높이 1인 직사각형을 만든다. 이하

의 팔들은 arm1의 형질을 그대로 유전받도록 한다. 단지 그것이 전체 좌표

상에서 놓이는 위치에 대한 정보를 저장할 필요가 있는데 이는 현 객체의 어느

점이(local_point) 모 객체의 어느 점 (model point)에 위치하는 가에 대한

233

객체지향방식의구현

Page 66: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

정보를 주도록 되어 있다.

3) 객체 상호간의 위치 제어

하나의 객체가 다른 객체에 기준되어 나타날 때, 주로 현 객체의 어느 점이

모 객체의 좌표의 어느 점에 위치하는가를 나타냄으로써 전체적인 표현이 가

능하다. arm1의 경우를 놓고 보자면 넓이 5 높이 1인 직사각형은 그 중심이

(0, 0, 0) 점에 위치하도록 만들어진다. 이러한 지방 좌표계에서 arm1 1은

점(1,0.5,0)을 중심으로 하여 회전을 한다. 즉 이 점의 위치가 모 객체인

robot의 중심에 놓이도록 하여야 한다. 이하의 모든 arm들은 그 지방 좌표계

의 회전 중심이 각각의 모 객체 좌표에서의 회전축에 놓여 있다.

기하학적인 도형을 표시함에 있어서 하나의 객체가 다른 객체에 대하여 평

행 이동하는 경우만을 고려하는 것은 상당히 제한된 적용이다. 대부분의 경우

한 객체의 위치가 다른 객체의 위치에 대하여 회전을 한 상대적 좌표계를 갖게

되는 경우가 많다. 각 객체에서의 rotate인 수는 이러한 경우를 포함한다.

arm1의 경우에 객체는 자신을 회전하지 않은 경우를 나타내고, arm2의 경우

234

제2 장 AutoLISP

<그림 2-26> OOP 기법에 의한 robot

객체의 설계 도면

Page 67: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

는 자신을 45도 local point를 중심으로 회전한 후 모 객체의 위치인 model

point에 위치시키게 된다. 이에 대한 결과는 <그림 2-27>과 같다. 이상의 조

건에서 arm2를 90 회전하게 되는 경우에는 arm2의 rotate 인수를 0에서 90

으로 바꾸면 된다.

이상에서 OOP 기능을 갖는 환경에서의 객체지향적 프로그램의 예제를 들어

보았다. 이와 같은 환경을 지원하기 위하여 필요한 기능들을 열거하고 이를 실

행하는 프로그램을 작성하여 보도록 하자. 먼저 개발 환경이 가져야할 기능들

을 열거하여 보자.

- 작성된 객체 지향 프로그램을 읽어들이는 기능

- 각각의 객체의 이름에 대하여 인수들을 할당하는 기능

- 객체의 인수를 inherit받는 기능

- 필요한 객체에서 특정 인수의 값을 회수하는 기능

- 하나의 객체를 도면에 출력하는 기능

- 모든 관련 객체를 함께 도면에 출력하는 기능.

235

객체지향방식의구현

<그림 2-27> 객체의 인수 수정에 의한

도면의 변경

Page 68: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

이상의 기능들이 OOP의 성능을 활용하기 위한 환경 구성의 최소한의 구성

모듈이다. 각각에 대한 내용을 구체적으로 살펴보도록 하자.

4)객체 지향 프로그램 입력 기능

(defun read_unit (fname / i j c d lst check)

(setq i "")

(setq d '0)

(setq lst '())

(setq j (open fname "r"))

(while (setq c (read-char j))

(if (= c 40) (progn (setq d (inc d))

(setq check 'y)))

(if (= c 41) (setq d (dec d)))

(if (< c 123) (setq i (strcat i (chr c))))

(if (and (zerop d) (= check 'y))

(progn (setq lst (append lst (list (read i))))

(setq i "")

(setq check 'n))))

lst)

<그림 2-28> 객체지향 프로그램을 읽어들이는 프로그램

함수 read_unit은 주어진 객체지향 프로그램을 읽어들인다. 프로그램의 구

조는 robot 객체의 예를 들면서 설명한 바와 같다. 즉 괄호 내부에 객체의 이

름을 먼저 지정하고 이어서 이 함수에 쓰인 인수들의 이름과 그에 해당하는 기

능 혹은 값을 할당하는 기능을 갖고 있다. 먼저 입력으로 fname을 요구하는

236

제2 장 AutoLISP

Page 69: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

데 이는 file의 이름을 뜻한다. 즉 객체지향 프로그램이 들어있는 파일의 이름

을 요구한다. 이후의 i, j, c, d, lst, check는 지역 변수로서 함수 자체 내에

서 정의되고 소멸된다.

여기서 "i"는 하나의 객체를 누적하여 받아들이는 스트링 버퍼의 역할을 한

다. "d"는 왼편 괄호와 오른편 괄호의 사용 빈도를 측정하여 어느 순간에 객체

의 단위로 인식할 것인가를 결정짓는 counter로서 사용되고, "c"는 파일로부

터 하나씩 읽어들인 캐릭터이다. lst는 읽어들인 모든 객체의 인수의 값을 list

화한 것이다. j는 단순히 파일을 열기 위한 매개 변수로 쓰 다.

먼저 입력된 이름의 파일을 "j"의 이름으로 연다. 읽어들인 하나의 문자는

변수 c에 저장되고, 만약 그것이 왼쪽 괄호(아스키 코드 번호 40)에 해당하면

counter d를 하나 증가하고, check를 y로 세팅한다. 이와 반대로 오른쪽 괄

호(아스키 코드 41)에 해당하면 counter d를 하나 감소한다. 주어진 문자가

특수 문자가 아닌 일반적인 문자이면(편의상 아스키 코드 123보다 작은 문자)

i에 문자를 누적하여 스트링으로 처리한다.

오른쪽 괄호로 끝난 상태에서 d의 counter가 0라면 이것은 하나의 객체 인

수가 i에 스트링의 형태로 읽혀져 있다는 것이다. 이것을 lst라고 하는 list에

추가하고, check 변수를 n로 세팅한 뒤 읽기를 계속 진행한다. 이것은 입력

파일이 끝날 때까지 진행한다. 읽기가 끝나면 모든 파일 내용은 lst라는 list에

저장되어 있는데 프로그램의 마지막 줄은 이것을 출력하도록 한다.

5) 객체별 인수 할당 기능

(defun FRAME ()

(init)

(mapcar 'associate_list (read_unit "chair.lsp"))

)

237

객체지향방식의구현

Page 70: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(defun init ( )

(setq frames '( ))

)

(defun associate_list (item)

(cond

((null item) nil)

(T

(add_items_to_frame (car item))

(set (car item) (cdr item)))))

(defun add_items_to_frame (name)

(setq frames (cons name frames)))

<그림 2-29> 객체의 이름에 대하여 인수들을 할당하는 프로그램

파일로부터 읽혀진 객체지향 프로그램은 다음 단계로서 데이터 구조를 갖는

기능적인 데이터베이스로 편집된다. 먼저 함수 FRAME은 모든 객체를 포함

하는 list의 이름으로서 frames라는 list를 선언하고 이를 클리어하는데 이것

이 함수 init의 역할이다. 읽혀지는 파일의 list는 각각의 객체 이름에 객체 인

수들의 값을 assign한다. associate_list는 객체 하나 하나를 순서대로 읽고

그것을 인수들의 집합에 assign하는 함수의 역할을 한다. add_items_

to_frame 함수는 하나의 객체가 assign될 때마다 그의 내용을 frames라는

list에 저장한다.

238

제2 장 AutoLISP

Page 71: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

6) 객체 인수의 inherit 기능

(defun getnextlevel (list)

(cond

((null list) '())

(T (append (retrieve_frame (eval (car list)) 'a-kind-of)

(getnextlevel (cdr list))))))

(defun getnextall (list)

(cond

((null (getnextlevel list)) list)

(T (append list (getnextall (getnextlevel list))))))

(defun getmixinlist (frame / tem)

(setq tem (retrieve_frame frame 'a-kind-of))

(getnextall tem))

(defun r_add_frame (frame list)

(cond

((null list) frame)

(T (r_add_frame (add_frame frame (eval (car list)))

(cdr list)))))

(defun add_frame (childf momf / temp)

(setq temp '())

(setq temp childf)

239

객체지향방식의구현

Page 72: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(append temp (inherit momf childf)))

(defun inherit (parents child)

(cond

((null parents) '())

((assoc (caar parents) child)

(inherit (cdr parents) child))

(T (cons (car parents) (inherit (cdr parents) child)))))

(defun retrieve_frame (frame slot)

(cadr (assoc slot frame)))

<그림 2-30> 객체의 인수를 inherit 받는 프로그램

하나의 객체를 하나의 프레임으로 보고, 그 안에 있는 인수는 slot이라고 부

르자. 즉 frame robot은 5개의 슬롯을 가지고 있다. frame의 a-kind-of 슬

롯이 갖고 있는 모 객체들을 조사하여 그것들의 슬롯을 물려받도록 한다. 먼저

주어진 프레임이 a-kind-of 슬롯을 갖고 있는지 조사한다. 모 객체가 포함한

모든 슬롯을 물려받기 위하여 모 혹은 모 객체의 모 객체가 갖고 있는 모든 a-

kind-of의 내용들을 조사하여야 한다. 모 객체는 한개일 수도 있고 그 이상일

수도 있다. 혹은 그 모 객체는 또한 여러 개 혹은 한 개의 모 객체를 가질 수

있다. 모 객체가 존재하지 않는 노드까지의 모든 모 객체의 이름을 조사하는

기능의 함수가 getmixinlist이다.

먼저 retrieve_frame은 주어진 프레임에서의 슬롯을 읽는 함수이다. 프레임

과 슬롯을 입력받아 슬롯의 값을 회수하고 그 슬롯의 값을 cadr을 이용하여

취한다. getmixinlist는 다루는 프레임의 a-kind-of의 슬롯에 어떠한 값이 있

는가를 검사하고, getnextall 함수를 이용하여 이 프레임에 관련된 모든 모 객

240

제2 장 AutoLISP

Page 73: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

체들을 조사해 나가기 시작한다. getnextlevel은 현재의 프레임의 객체의 바

로 상위 단계의 모 객체들의 이름을 조사하는 함수이다. 현재 단계에서의 모든

객체에 대하여 각각의 객체가 갖는 모 객체의 값을 append하여 조사한다. 함

수 getnextall은 이러한 상위 단계의 모 객체가 더이상 존재하지 않을 때까지

계속하여 모 객체들의 이름을 취합하여 진행한다. 결과적으로 getmixinlist는

현재의 객체와 관련된 모든 모 객체의 이름을 반환하여 준다.

이와 같이 얻어진 모 객체의 list는 r_add_frame에서 이용되는데, 이 함수는

한 객체의 프레임과 그것의 모든 모 객체의 슬롯을 유전받을 수 있도록 모 객

체의 list를 입력받아 모든 슬롯을 포함한 객체의 프레임을 생성한다.

r_add_frame은 주어진 모 객체의 list를 받아 각각의 모 객체에 대하여 함수

add_frame을 부른다. add_frame은 inherit을 부르는데 이는 모 객체의 슬롯

을 하나씩 조사해 가면서 그것이 현재 객체 프레임에 존재하는 슬롯인지의 여

부를 판단하여 있으면 추가하고 존재하면 무시하는 방식으로 진행한다. 현재의

객체 프레임에서 형질을 유전받기 위해서는 다음의 명령을 수행하면 된다.

(setq 'current-object (r_add_frame 'current-object (getmixinlist 'current-object)))

7) 객체의 특정 인수 회수 기능

(defun the (slot / value check)

(setq value *instan*)

(setq check (cadr (assoc slot value)))

(cond

((atom check) check)

((member (car check) frames) check)

((boundp (car check)) (eval check))

241

객체지향방식의구현

Page 74: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(T check)))

(defun the1 (slot value / check ch)

(setq ch (eval value))

(setq check (cadr (assoc slot ch)))

(cond

((atom check) check)

((member (car check) frames) check)

((boundp (car check)) (eval check))

(T check)))

<그림 2-31> 필요한 객체에서 특정 인수의 값을 회수하는 프로그램

함수 the는 현재 지정된 객체 프레임에서의 원하는 슬롯값을 회수한다.

*instan*은 global variable로서 현재 다루고 있는 객체 프레임을 의미한다.

주어진 슬롯을 가지고 그 값을 check에 할당하게 되는데 그 값이 수치나 단순

한 데이터를 나타내는 경우에는 그 값을 출력하고, AutoLISP의 명령어일 때

는 (boundp의 경우) 그 내용을 evaluate하여 회수하게 된다. 함수 the1은

현재 지정된 객체 프레임이 아닌 임의의 객체 프레임에 대하여 원하는 슬롯의

값을 회수할 때 사용하는 함수이다.

8) 객체 부품의 도면 출력 기능

(defun make_c_part (pname)

(setq *c_part* pname)

(setq *instan* (eval *c_part*))

(setq *instan* (r_add_frame *instan* (getmixinlist *instan*)))

242

제2 장 AutoLISP

Page 75: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(make_part))

(defun make_part ( / se ce ee lv)

(command "point" "0,0")

(setq se (entlast))

(the 'draw)

(command "point" "0,0")

(setq ee (entlast))

(setq sn1 (ssadd))

(setq ce se)

(while (not (equal ce ee))

(setq ce (entnext ce))

(setq sn1 (ssadd ce sn1))

(prin1 ce))

(entdel se)

(entdel ee)

(command "rotate" sn1 "" (the 'local_point) (the 'rotate))

(command "move" sn1 "" (the 'local_point) (the 'model_point))

(object_move sn1 *c_part*))

<그림 2-32> 하나의 객체를 도면에 출력하는 프로그램

함수 make_c_part는 현재의 객체 부품을 도면으로 출력하는 기능을 가진

함수이다. 여기에 쓰인 global variable인 *c_part*는 현재 지정한 객체의 이

름을, *instan*은 지정된 객체의 프레임을 각각 지시하도록 정의한다. 도면

출력을 원하는 경우에 원하는 객체의 이름을 지정하여 함수에 입력하면 그 객

체 이름을 *c_part*에 프레임을 *instan*에 설정한 상태에서 작업을 시작한

243

객체지향방식의구현

Page 76: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

다. 앞서 설명된 바와 같이 모 객체를 가진 객체의 경우에는 이들의 모든 슬롯

을 전해 받기 위하여 슬롯을 확장하는 단계를 거친다. 모든 슬롯을 포함한 프

레임으로 *instan*이 수정되고 나면 함수 make_part가 수행된다.

함수 make_part는 현재 상태에서 *c_part*의 부품 이름을 가지고 *instan*

의 프레임을 갖는 객체를 도면으로 출력한다. 먼저 (the 'draw)는 *c_part*

객체의 도면 부분에 해당하는 정보를 갖고 있는 슬롯이다. 이상의 슬롯에서 그

려진 도형 요소들을 sn1이라는 이름의 selection set으로 모은 다음 이를

local_point로 주어진 점을 중심으로 하여 현재 객체의 슬롯 'rotate에 해당하

는 양 만큼 회전을 한다. 그리고 현재의 local_point 위치를 모 객체의 위치인

model_point에 위치하도록 옮긴다. 모 객체가 없을 때까지 계속하여 회전과

위치 이동을 계속하는데 이는 다음 단계에서 설명하도록 한다.

9) 주 객체의 도면 출력 기능

(defun object_move (ss cpart / tem)

(cond

((or (null (setq tem (trace cpart 'parents)))

(equal cpart *c_node*)) ())

(T (command "rotate" ss "" (trace (car tem) 'local_point)

(trace (car tem) 'rotate))

(command "move" ss "" (trace (car tem) 'local_point)

(trace (car tem) 'model_point))

(object_move ss (car tem)))))

(defun trace (pname slot / t1 t2)

(setq t1 (eval pname))

244

제2 장 AutoLISP

Page 77: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq t2 (r_add_frame t1 (getmixinlist t1)))

(setq check (cadr (assoc slot t2))))

(defun expand_n (nlist)

(cond

((null nlist) nil)

(T (make_c_part (car nlist))

(if (null (the 'children))

(expand_n (cdr nlist))

(expand_n (append (the 'children) (cdr nlist)))))))

(defun expand_node (nname)

(setq *c_node* nname)

(expand_n (list nname)))

<그림 2-33> 모든 관련 객체를 함께 도면에 출력하는 프로그램

대부분의 경우 하나의 객체를 독립적으로 출력하는 것은 의미가 없다. 대부

분의 객체는 그의 모 객체와 자 객체를 갖는데 각각의 객체의 표현에서

parents와 children에 해당하는 슬롯은 이러한 관계를 규명짓는다. 또 하나의

실제 부품을 표시할 때도 대부분 그것을 구성하는 소부품으로써 표시된다는

사실은 이러한 객체 방식의 구현이 필요함을 보여준다. 단독의 부품을 도면으

로 출력하는 이외에 하나의 부품의 모든 자 객체와 더불어 표현하는 방식이 함

수 expand_node를 이용함으로써 가능해진다.

먼저 expand_node는 확장하고자 하는 객체의 이름을 입력으로 취한다. 이

입력은 global variable 인 *c_node*를 이 객체의 이름으로 확보하고, 객체의

이름에 list를 취하여 함수 expand_n을 부른다. 이 함수는 주어진 입력의 모

245

객체지향방식의구현

Page 78: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

든 객체를 하나 하나 도면으로 출력한다. null list인 경우에 함수가 끝나며,

그렇지 않은 경우에는 그 첫번째의 객체를 도면 출력하고, 그의 자 객체가 있

는 경우에는 이를 도면 출력하여야 할 객체 list에 추가한다. 모든 객체가 도면

으로 출력된 후에 함수가 정지한다.

각각의 객체가 출력되는 과정은 앞서의 make_part 함수의 동작이며 이에

추가적으로 각각의 객체가 현재의 기준 객체에 대하여 표현되도록 그 좌표를

추적하여 나가는 함수로서 trace와 object_move가 있다.

246

제2 장 AutoLISP

Page 79: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

5. 객체 지향 프로그램 예제

(1) 버스설계프로그램의재조명

앞 절에서 객체지향 방식을 실현하기 위한 AutoLISP의 프로그램을 살펴보

았다. 이번에는 버스의 설계를 객체 지향 방식의 설계 도구를 이용하여 설계하

는 방법을 실현하겠다. 먼저 버스 설계의 기능을 위하여 추가적으로 고려하여

야 할 사항이 있는데 이는 의자, 창문, 바퀴 등의 설계가 멀티플(multiple)로

그려진다는 것이다. 지금까지 살펴본 내용은 이러한 다중 작업에 대한 부분까

지 확장되어 있지는 않다. 먼저 전반부에서는 이 작업을 위하여 전체 프로그램

수정을 하여야 할 부분에 대하여 설명하고, 후반부에서는 기존의 버스 설계를

객체지향의 방식으로 프로그래밍하는 과정을 보겠다.

1) 멀티플 작업을 위한 수정 프로그램

동일한 형태의 대상을 일렬로 배치하여야 하는 상황은 CAD 작업시에 자주

발생한다. 이러한 상황에 대하여, 다중의 객체 배열을 위한 루틴을 따로 처리

할 수 있도록 한다면 이상적일 것이다. 실제의 부품을 만드는 과정인 함수

make_part 부분을 변경하여야 한다.

먼저 객체를 배열하는 방식에 대한 규약을 정의하도록 하자. 제일 먼저 어

느 정도의 수량을 배열할 것인지를 알아야 한다. 이를 인수 quantity로 한

다. 배열이 시작되는 점을 quantity start point의 약자인 q_s_point로 끝

나는 점을 quantity ending point인 q_e_point로 정의하자. 즉 (quantity

6) (q_s_point (0 0 0)) (q_e_point (3 3 3))은 점 (0 0 0)로부터 점 (3 3

3)의 사이에 6개의 동일한 그림을 그린다. 여기에선 우리는 단위 대상의 어

떠한 점이 6개의 점 상에 놓여야 하는가를 정의해야 하는데 이를

hinge_point라 하자. 이렇게 하여 여러 개의 동일 형태를 그리기 위한 기본

인수들을 정의하 다.

247

객체지향프로그램예제

Page 80: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

make_part의 함수가 불리면 이는 먼저, 그리고자 하는 대상이 여러 개인지

를 알아본다. 즉 대상을 여럿 그릴 경우에는 quantity에 해당하는 인수가 2

이상이어야 한다. 이것을 확인하고 여러 개의 객체를 만들 경우에는

multiprocess라는 루틴으로 분기하도록 한다.

multiprocess 함수는 각각 multilist, msv, m_list 등의 함수를 부른다.

multiprocess는 먼저 단위 도형 요소들을 selection set으로 만든다. 이와 같

이 만들어진 도형을 command 수준에서 copy 명령어를 불러서 쓰게 된다.

여기에서 쓰인 mapcar는 각각의 삽입점에 대하여 copy 명령어를 수행하기

위하여 사용되었다. 즉 이 명령은 (multilist)로 산출된 각각의 점에 대하여

생성된 도면의 hinge_point를 삽입하도록 진행된다.

multilist는 주어진 여러 개의 삽입 요소에 대하여 계산된 삽입 점들의 결과

를 제공한다. local variable인 t1은 3차원에서의 시작점과 종점의 거리간의

증분치를 나타낸다. 시작과 끝에 각각 도형 요소가 위치해야 하므로 n개의

quantity에 대하여는 (n-1)의 값으로 나누어주게 된다. 함수 dec는 단순히

정수를 하나씩 감소하는 함수이고, 결과를 실수화하기 위하여 함수 float을 사

용하 다. 그 결과를 x,y,z 좌표의 각각의 값에 대하여 연산을 행한다.

함수 m_list는 단순히 주어진 값에 대한 수까지의 수열을 만든다. 즉

(m_list 5)는 (4 3 2 1)의 수열을 만든다. 이는 multilist를 만들기 위한 방법

으로 각각의 요소에 대하여 원하는 증분치 만큼을 곱하고 시작점을 더하여 결

과적으로 multilist를 만들어낼 수 있는 것이다. 이와 같이 앞절에서의 부분에

수정을 가하여야 할 부분은 아래의 프로그램에 주어진다.

(defun make_part ( / se ce ee lv)

(command "point" "0,0")

(setq se (entlast))

(if (> (the 'quantity) 0)

248

제2 장 AutoLISP

Page 81: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(multiprocess)

(the 'draw))

(command "point" "0,0")

(setq ee (entlast))

(setq sn1 (ssadd))

(setq ce se)

(while (not (equal ce ee))

(setq ce (entnext ce))

(setq sn1 (ssadd ce sn1))

(prin1 ce))

(entdel se)

(entdel ee)

(command "rotate" sn1 "" (the 'local_point) (the 'rotate))

(command "move" sn1 "" (the 'local_point) (the 'model_point))

(object_move sn1 *c_part*))

(defun multiprocess ( / se ce ee tss)

(command "point" "0,0")

(setq se (entlast))

(the 'draw)

(command "point" "0,0")

(setq ee (entlast))

(setq tss (ssadd))

(setq ce se)

(while (not (equal ce ee))

(setq ce (entnext ce))

249

객체지향프로그램예제

Page 82: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq tss (ssadd ce tss))

(prin1 ce))

(entdel se)

(entdel ee)

(mapcar '(lambda (t1)

(command "copy" tss "" (the 'hinge_point) t1))

(multilist))

(command "erase" tss "")

)

(defun multilist ( / t1 t2)

(setq t1 (mapcar '/ (mapcar '- (the 'q_e_point) (the 'q_s_point))

(mapcar 'float

(list (dec (the 'quantity))

(dec (the 'quantity))

(dec (the 'quantity))))))

(princ t1)

(setq t2 (the 'quantity))

(setq t2 (m_list t2))

(princ t2)

(mapcar '(lambda (v1)

(mapcar '+ (the 'q_s_point) (msv v1 t1)))

t2))

(defun msv (s vec)

(list (* s (car vec)) (* s (nth 1 vec)) (* s (nth 2 vec))))

250

제2 장 AutoLISP

Page 83: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(defun m_list (num)

(cond

((zerop num) nil)

(T (cons (- num 1) (m_list (dec num)))))

)

<그림 2-34> 복수 배열 사용을 위한 변경 프로그램

(multiple

(quantity 10)

(q_s_point (1 2 40))

(q_e_point (10 20 70))

(hinge_point (0 0 0))

(draw (command "circle" "0,0,0" "1")))

<그림 2-35> 설계 프로그램 예제

<그림 2-36>은 샘플 프로그램을 실행한 결과로서 점 (1 2 40)과 (10 20 70)

사이에 등간격으로 위치한 반지름 1인 10개의 원을 확인할 수 있다.

2) 객체지향 방식 버스의 설계

이제는 지금까지 설명된 도구를 이용하여 객체지향 방식의 버스를 설계하는

과정을 살펴보도록 하자. 대부분의 경우 도형을 만들었던 종래 방식의 코드를

이용할 수 있다. 중요한 점은 각각의 객체가 자신의 인수들에 의하여 만들어지

며 상호간의 위치 관계도 이와 같이 용이하게 관리된다는 점이다. 하나하나의

객체에 대하여 프로그램 과정을 설명하여 나가도록 하자.

먼저 기본적으로 도면이 갖기를 바라는 속성들이 있다. 이를 basedraw라는

251

객체지향프로그램예제

Page 84: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

객체로 만들어 사용하도록 한다. 이러한 변수에 해당하는 것이 local_point,

model_point, rotate 등이 있다. 특별히 그 인수를 지정하지 않는다면 그 값

들은 basedraw에서 지정된 값을 이용할 것이다.

제일 먼저 모 객체가 되는 bus를 정의하도록 하자. 이는 자 객체로서 body,

window, chair, tier 등을 가지며, bus의 높이를 b_hight로 bus의 길이를

b_length로 지정하여 3과 10을 초기 값으로 한다.

bus의 자 객체의 하나인 body는 역시 basedraw의 인수를 유전받으며, 도

형의 시작점을 (0 0 0)으로 잡는다. 이는 base_point라는 인수로 표시되어 있

다. body 자체의 높이와 길이는 각각 상위 객체인 bus로부터 b_length와

b_width로 유전받으며 각각의 모서리 점을 계산하여 인수 pt1, pt2, pt3,

pt4의 네 개의 점으로 잡고, 이상의 결과를 가지고 버스의 몸체를 그린다.

draw 인수 내부의 변화를 살펴보면 종래의 프로그램에 비해 변수들이 the의

함수로 주어져 있음을 알 수 있는데 이것이 모듈의 독립성을 높여주는 역할을

한다.

tier는 다중 도형이다. 두 개의 동일한 도형을 설치하므로 이것은 multiple

252

제2 장 AutoLISP

<그림 2-36> 예제 프로그램의 실행 결과

Page 85: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

의 형질을 유전받도록 하기 위하여 (a-kind-of multiple)을 사용하 다. 타

이어는 기본적으로 타이어 중심의 위치와 반지름을 입력받도록 되어 있는데,

각각 t_center와 t_radius의 이름으로 정의하 다. 그 수량은 2개를 설치하도

록 하고, 설치점은 몸체 길이의 1/4되는 곳에 앞바퀴를, 몸체 길이의 3/4에

해당하는 곳에 뒷바퀴를 설치하도록 한다. 각각을 위치시키는 점은 타이어의

중심점을 위치시킨다. 역시 이후의 설계는 종래의 프로그램과 유사하다. 모든

변수는 the의 함수로 표시되었다.

window 역시 multiple로부터 속성을 유전받는다. 다만 그 수량은 윈도우

의 폭인 1.7을 가지고 몸체의 길이로 나누어 설치할 수 있는 만큼만 설치하도

록 한다. 시작점은 차의 앞면의 차체 높이의 2/3되는 곳에, 끝점은 몸체 뒷면

으로부터 1.7만큼 떨어진 2/3되는 높이에 설치하도록 한다. 구조적으로

hinge_point는 창문의 우측 상단의 모서리로 된다.

chair 역시 multiple로부터 속성을 유전받는다. 역시 그 수량은 의자의 폭

인 0.8로서 몸체의 길이로 나누도록 되어 있으며, 시작점은 x축으로는 0.4 만

큼, y축으로는 버스 몸체의 높이와 타이어의 크기를 고려한 위치에서 0.4 만

큼 높은 점에 위치시킨다. 끝점은 타이어의 몸체 길이에서 0.8을 감한 x 위치

와 동일한 y 좌표의 점을 지정한다. 설계 프로그램은 다음과 같다.

(basedraw

(local_point (0 0 0))

(model_point (0 0 0))

(rotate 0))

(bus

(a-kind-of (basedraw))

(children (body window chair tier))

253

객체지향프로그램예제

Page 86: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(b_height 3)

(b_length 10))

(body

(a-kind-of (basedraw))

(base_point (0 0 0))

(length (the2 'b_length 'body))

(height (the2 'b_height 'body))

(parents (bus))

(pt1 (the 'base_point))

(pt2 (cons (+ (car (the 'base_point)) (the 'length))

(cdr (the 'base_point))))

(pt3 (list (car (the 'pt2)) (- (nth 1 (the 'pt2)) (the 'height))

(nth 2 (the 'pt2))))

(pt4 (list (car (the 'base_point))

( - (nth 1 (the 'base_point)) (the 'height))

(nth 2 (the 'base_point))))

(ref1 (cons (+ (car (the 'pt1)) 0.05)

(cons (- (cadr (the 'pt1)) 0.5) (cddr (the 'pt1)))))

(draw (progn

(if (null (entlast)) (command "point" '(0 0 0)))

(command "pline" (the 'pt1) (the 'pt2) (the 'pt3)

(the 'pt4) "c")

(setq tem (entlast))

(command "fillet" "R" "0.25")

(command "fillet" "P" tem)

254

제2 장 AutoLISP

Page 87: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq t1 (list (+ (car (the 'pt1)) 2)

(- (nth 1 (the 'pt1)) 3)))))

)

(tier

(a-kind-of (multiple))

(parents (bus))

(t_center (0 0 0))

(t_radius 0.5)

(quantity 2)

(q_s_point (list (/ (the2 'b_length 'tier) 4)

(- 0 (the2 'b_height 'tier))

0))

(q_e_point (list (- (the2 'b_length 'tier)

(/ (the2 'b_length 'tier) 4))

(- 0 (the2 'b_height 'tier))

0))

(hinge_point (the 't_center))

(pt1 (mapcar '+ (the 't_center) '(0 0.15 0)))

(draw (progn

(command "circle" (the 't_center) (the 't_radius))

(command "circle" (the 't_center) (* (the 't_radius) 0.67))

(command "circle" (the 't_center) (* (the 't_radius) 0.58))

(command "circle" (the 't_center) (* (the 't_radius) 0.08))

(command "polygon" "6" (the 'pt1) "c" "0.025")

(setq t1 (entlast))

255

객체지향프로그램예제

Page 88: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(command "array" t1 "" "P" (the 't_center) "6" "" "Y")))

)

(window

(a-kind-of (multiple))

(parents (bus))

(quantity (fix (/ (the2 'b_length 'window) 1.7)))

(q_s_point (list 0

(- 0 (/ (the2 'b_height 'bus) 3))

0))

(q_e_point (list (- (the2 'b_length 'window) 1.7)

(- 0 (/ (the2 'b_height 'bus) 3))

0))

(model_point (0 0 0))

(local_point (0 0 0))

(w_point (0 0 0))

(draw

(progn

(setq ref1 (cons (+ (car (the 'w_point)) 0.05)

(cons (- (cadr (the 'w_point)) 0.5)

(cddr (the 'w_point)))))

(if (null (entlast)) (command "point" '(0 0 0)))

(setq se (entlast))

(command "line" (the 'w_point) "@.7<0" "@.9<270" "@.7<180" "c")

(command "line" ref1 "@.1<90" "@.05<0" "@.1<270" "c")

(setq line1 (entnext se))

256

제2 장 AutoLISP

Page 89: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq line2 (entnext line1))

(setq line3 (entnext line2))

(setq line4 (entnext line3))

(command "copy" line1 "" '(0 0 0) '(0 0.05 0))

(setq oline1 (entlast))

(command "copy" line3 "" '(0 0 0) '(0 -0.05 0))

(setq oline3 (entlast))

(command "copy" line4 "" '(0 0 0) '(-0.05 0 0))

(setq oline4 (entlast))

(command "fillet" "R" "0.05")

(command "fillet" oline1 oline4)

(command "fillet" oline3 oline4)

(setq ml1 (cdr (assoc 10 (entget line2))))

(setq ml2 (cdr (assoc 11 (entget line2))))

(setq ee (entlast))

(sel-entries se ee)

(command "mirror" sn1 "" ml1 ml2 "N")

(prin1 ce)))

)

(chair

(a-kind-of (multiple))

(parents (bus))

(quantity (fix (/ (the2 'b_length 'chair) 0.8)))

(q_s_point (list 0.4

(+ (+ (- 0 (the2 'b_height 'bus)) (the2 't_radius 'tier))

257

객체지향프로그램예제

Page 90: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

0.4)

0))

(q_e_point (list (- (the2 'b_length 'chair) 0.8)

(+ (+ (- 0 (the2 'b_height 'bus)) (the2 't_radius 'tier))

0.4)

0))

(model_point (0 0 0))

(local_point (0 0 0))

(c_point (0 0 0))

(draw

(progn

(command "line" (the 'c_point) "@0.55<355" "@0.8<80"

"@0.11<0" "@0.95<260" "@0.63<180" "c")

(setq pt1 (mapcar '+ (the 'c_point) '(0.1 -0.2 0)))

(command "line" pt1 "@0.25<270" "@0.5<0" "@0.25<90" "c")))

)

<그림 2-37> 객체지향 방식으로 구성된 버스의 설계 프로그램

이상에서 종래의 bus 설계 프로그램을 객체지향 설계 방식으로 재구성

된 프로그램에 대하여 살펴보았다. 각각의 결과로 그려진 도면은 다음과

같다.

객체지향 방식의 장점은 변화를 위하여 다시 작성해야 하는 코드의 양을

최소로 할 수 있다는 것이다. 각각의 인수에 대한 수정으로 작성하고자 하

는 객체를 쉽게 수정할 수 있다. 버스의 높이와 길이를 각각 바꾸기 위하여

변수 b_length,와 b_height를 변경하여 <그림 2-37>을 얻을 수 있다. 물

론 이 경우에 각각의 그림에 대하여 base_point의 값을 바꾸어 주어야 한

258

제2 장 AutoLISP

Page 91: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

다. <그림 2-40>에서는 의자와 창문의 설치 수량을 각각 바꾸어 주었다. 이

는 chair에서의 quantity와 window에서의 quantity를 바꾸어 줌으로써

가능하다. <그림 2-41>은 타이어 수량과 의자 높이를 변경한 결과를 보여준

다. 종래의 프로그램에서의 수정은 각각의 코드를 분석하고 그에 따른 수정

259

객체지향프로그램예제

<그림 2-38> ]객체지향 방식으로 작성된

도면

<그림 2-39> 버스 높이와 길이의 변경

Page 92: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

작업이 필수적이지만 수정된 객체지향 방식에서는 몇 개의 인수를 바꾸어 줌

으로써 작업이 완성된다.

260

제2 장 AutoLISP

<그림 2-40> 버스 의자와 창문 수량의

변경

<그림 2-41> 버스 타이어 수량과 의자

높이의 변경

Page 93: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(2) 로봇시뮬레이터

앞 절에서는 객체 지향 환경의 적용 예를 설명하기 위하여 간단한 모양의 로

봇 구조물을 생성하는 프로그램을 작성하 다. OOP 개발 환경은 여러 분야에

유용하게 적용될 수 있는데 특히 로봇 시뮬레이터와 같은 용도로서는 많은 장

점을 얻을 수 있다.

로봇 시뮬레이터라 함은 제작된 로봇을 대상으로 작업 상황에서의 이동 경

로를 산출, 확인하려는 목적, 로봇을 개발할 때 개발 로봇의 운동학적, 동역

학적인 특성을 연구 하기 위한 목적, 또는 교육적인 용도로써 3차원 공간에

서의 로봇의 동작 특성 이해를 위한 목적 등으로 이용된다. 대부분의 경우

특정 로봇 매니퓰레이터에 대해서는 제작 회사가 관련 로봇 시뮬레이터를 제

공하는 경우가 많고 또한 특정 로봇 언어를 사용함으로써 자체 로봇의 기능

을 지원하는 경우가 많다. 이러한 경우 전체의 사용 모듈이 턴키 방식으로

되어 특정 로봇에 대한 의존성이 높게 되고, 필요한 부분만을 이용할 수 없

게 된다.

이러한 문제로 범용성, 확장성, 경제성이 있는 시뮬레이터의 개발이 요구

된다. 이러한 목적으로 3차원에서의 로봇의 운동학적인 면을 고찰할 수 있는

로봇 시뮬레이터를 개발하는 방법으로 앞서 설명한 객체 지향 방식을 이용하

여 공간상에서 관절을 각각의 좌표계에 대하여 위치시키는 방법을 보이도록

하겠다.

새로운 버전에서는 몇 가지 수정을 가하 는데 주어진 하나의 객체를 위치

시키는 방법이 종래에는 생성된 객체를 선택하여 이를 회전하고 위치를 움직

인데 반하여, 오토캐드의 UCS(User Coordinate System)의 기능을 이용하

여 새로운 객체를 그리는 경우에 이에 해당하는 좌표계로 먼저 변환한 후에 원

하는 대상을 생성하도록 한다. 똑같은 대상을 생성하더라도 현재의 UCS에 따

라서 그것이 공간상에서 회전하고 이동한 결과로 생성할 수 있다.

함수 expand_n은 이러한 기능을 갖추고 있으며 그 내용은 아래와 같다.

261

객체지향프로그램예제

Page 94: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(defun expand_n (nlist done saved / tx ty tz mo lo)

(setq *c_part* (car nlist))

(setq *instan* (eval *c_part*))

(setq *instan* (r_add_frame *instan* (getmixinlist *instan*)))

(setq tx (the 'rotatex) ty (the 'rotatey)

tz (the 'rotatez) mo (the 'model_point)

lo (the 'local_point))

(command "ucs" "or" mo)

(if tz (command "ucs" "z" tz))

(if ty (command "ucs" "y" ty))

(if tx (command "ucs" "x" tx))

(command "ucs" "or" (mapcar '- '(0 0 0) lo))

(if (> (the 'quantity) 0)

(multiprocess)

(unitprocess))

(cond

((null nlist) nil)

((null (the 'children))

(command "ucs" "r" (car saved))

(expand_n (cdr nlist)

(append done (list (car nlist)))

(cdr saved)))

((= (length (the 'children)) 1)

(expand_n (append (the 'children) (cdr nlist))

(append done (list (car nlist)))

saved))

262

제2 장 AutoLISP

Page 95: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(T

(command "ucs" "s" (etos *c_part*))

(expand_n (append (the 'children) (cdr nlist))

(append done (list (car nlist)))

(append (mcons (length (the 'children))

(etos *c_part*)) saved))))

)

(defun mcons (num ad)

(cond

((= num 1) nil)

(T (cons ad (mcons (- num 1) ad)))))

<그림 2-42> 3차원 좌표 변환을 위한 프로그램

expand_n은 생성해야 할 객체의 리스트와 이미 확장된 객체의 리스트, 차

후에 사용될 경우를 대비하여 보관하여 두는 객체의 세 가지 인수를 취한다.

먼저 생성해야 할 객체의 리스트로부터 첫번째 객체를 선택하여 이를 현재 생

성해야 할 이름의 전역 함수인 *c_part*에 저장하고, 이를 평가한 값을 전역

함수인 *instan*에 저장하고, 이것의 a-kind-of 슬롯에 할당되어 있는 모든

frame을 추가한다.

현재의 객체에 대한 rotatex, rotatey, rotatez, model_point, local_point

등의 정보가 있으면 이를 지역 변수로 복사하고 이를 이용하여 model_point

의 점으로 새로운 좌표계의 원점을 잡고 이에 대하여 좌계를 x축에 대하여

rotatex의 값 만큼, y축에 대하여 rotatey의 값 만큼, z축에 대하여 rotatez

의 값 만큼, 회전한 새로운 좌표 계를 만들고 이 상태에서 원점을 local_point

의 값으로 잡는다.

이러한 상태에서 그리는 객체는 월드 좌표계에 대하여 객체의 local_point

263

객체지향프로그램예제

Page 96: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

값을 중심으로 회전시켜 model_point에 위치시킨 것과 같은 효과를 나타낸

다. 생성해야 할 도형의 개수가 한 개 혹은 두 개 이상인 경우에 대하여 각각

unitprocess와 multiprocess를 실행하는데 이는 단순히 주어진 도형을 현재

의 좌표 계에서 그리는 역할을 한다.

마지막 부분의 조건문은 현재의 nlist 상태에 대하여 취하여야 할 내용을 갖

고 있다. 모든 nlist의 객체들이 평가되고 난 후에 expand_n은 종료하게 된

다. 그렇지 않고 현재 객체가 존재하고 이의 자 객체가 존재하지 않을 경우는

saved로부터 이전의 좌표계를 복원하면서 saved를 update한다. 하위 객체가

있을 경우에는 하나 혹은 그 이상인가에 따라서 처리 방식이 달라진다. 자세한

내용은 프로그램의 내용으로부터 확인할 수 있다. 이의 내용을 설명하기 위한

그림은 다음과 같다.

로봇을 그리는 프로그램은 다음과 같다. 그리고자 하는 형태는 직육면체의

베이스를 갖고(robot) 이는 첫번째 원통형 관절(arm1)에 연결되어 있다. 이

는 두번째의 원통형 관절(arm2)에 연결되어 있고 세번째, 네번째는 직육면체

264

제2 장 AutoLISP

Aexpand_n ((A) nil nil) expand_n (nil (A B C F G I D E) nil

expand_n ((B) (A) nil)

expand_n ((C D E)(A B) (B B))

expand_n ((F D E)(A B C) (B B))

expand_n ((D E) (A B C F G I) (B))

expand_n ((E) (A B C F G I D) nil)

expand_n ((G I D E)(A B C F) (F B B))

expand_n ((I D E)(A B C F G) (F B B))

B

C D E

F

G I

<그림 2-43>expand_n의 하위 객체 생성

방법

Page 97: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

의 관절 arm3, arm4로 연결되어 있다. 베이스인 robot은 box0로서 기존의

box를 그대로 이용하 으며, 베이스에 대한 가로, 세로, 높이의 값을 새로 설

정하 다.

arm1은 실린더 형태로서 (0 0 4)의 model_point를 (0 0 1)의 local_point

에 위치하 다. arm2 역시 실린더 형태이나, 이는 x축을 중심으로 90도 회전

하여 이를 arm2 좌표 계에 위치하 다. arm3, arm4도 이러한 방식으로

box0 형태로서 생성되었다. 프로그램은 다음과 같다.

(robot

(a-kind-of (basedraw box0))

(children (arm1))

(width 2)

(height 0.5)

(length 3)

(rotatez 0))

(arm1

(a-kind-of (cyl))

(children (arm2))

(parents (robot))

(depth 5)

(radius 0.3)

(local_point (0 0 0))

(model_point (0 0 1)))

(arm2

265

객체지향프로그램예제

Page 98: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(a-kind-of (cyl))

(children (arm3))

(parents (arm1))

(depth 2)

(radius 0.3)

(model_point (0 0 4))

(local_point (0 0 1))

(rotatex 90))

(arm3

(a-kind-of (box0))

(parents (arm2))

(children (arm4))

(width 1)

(height 0.5)

266

제2 장 AutoLISP

<그림 2-45> 로봇 시뮬레이터에 대한

실행 결과(1) 기준 위치

Page 99: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(length 5)

(model_point (0 0 -0.5))

(local_point (0 0 0))

(rotatez 120))

(arm4

(a-kind-of (arm3))

(parents (arm3))

(children ())

(model_point (0 4 -0.5))

(rotatez 90))

(cyl

(a-kind-of (basedraw))

(center (0 0 0))

267

객체지향프로그램예제

(2) 주축의 회전

Page 100: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(radius 1)

(depth 1)

(draw (progn

(command "thickness" (the 'depth))

(command "circle" (the 'center) (the 'radius))

(command "thickness" "0"))))

<그림 2-44> 로봇 시뮬레이터 프로그램

회전 각도를 조정하기 위하여 각각의 객체에서, rotatex, rotatey, rotatez

부분을 수정하도록 한다.

(3) 블럭기능의활용

지금까지 설명된 개발 환경의 장점은 실용 오토캐드와 접한 관계에 있다

는 것이다. 즉 임의의 형태로 작업된 도면은 하나의 객체로 인식하는 것이

가능한데 이는 객체로 인식하고자 하는 부분을 선택하여 이를 블럭으로 설정

268

제2 장 AutoLISP

(3) 최종 관절의 회전

Page 101: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

하고 난 후는 다른 객체와 마찬가지로 사용하는 것이 가능하다. 예는 아래와

같다.

(blk

(blk_name "none")

(i_point '(0 0 0))

(draw (command "insert" (the 'blk_name) (the 'i_point) "" "" ""))

)

(test_piece

(children (part1 part2 part3 part4))

)

(part1

(a-kind-of (blk))

(blk_name "part1")

(parents (test_piece))

)

(part2

(a-kind-of (blk))

(blk_name "part2")

(parents (test_piece))

)

(part3

269

객체지향프로그램예제

Page 102: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(a-kind-of (blk))

(blk_name "part3")

(parents (test_piece))

)

(part4

(a-kind-of (blk))

(blk_name "part4")

(parents (test_piece))

)

<그림 2-46> block을 이용한 프로그래밍 기법

이상에서 원, 삼각형, 직사각형, 다각형의 모양을 각각 part1, part2, part

3, part4의 이름으로 설정하고 이를 실행하 다.

270

제2 장 AutoLISP

<그림 2-47>block을 이용한 실행 결과상단: AutoCAD에 의하여

생성된 도형하단: 각각의 도형을

블럭화하여 test-piece로합성한 객체

Page 103: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

6. OOPACAD

지금까지 설명된 프로그램은 객체지향 프로그램 환경을 지원하여 준다. 이

를 OOPACAD(Object Oriented Programming of AutoCAD)라고 이름한

다. OOPACAD를 이용하여 실질적인 프로그래밍을 하는데 필요한 기본적인

요소들을 정리하여 설명하도록 한다.

(1) OOPACAD 프로그래밍

하나의 객체는 하나의 괄호로써 표현된다. 괄호의 첫 번째 요소는 객체의 이

름이 되고, 나머지 요소는 슬롯의 집합으로 정의된다. 즉 (객체이름 (슬롯1이

름 슬롯1내용) (슬롯2이름 슬롯2내용) ........ ) 으로 정의된다. 슬롯의 이름

은 사용자가 원하는 대로 정의할 수 있으나 다음의 슬롯 이름은 특수한 목적으

로 정의되어 있으므로 중복 사용을 피하도록 한다. 프로그램의 운용은

command:에서 (load "c:system)을 실행한 후 (runall)을 실행한다. 이때

읽어들일 OOPACAD 프로그램의 파일명을 입력한다. (expand_node '객체

이름)을 실행하면 그리고자 하는 객체를 볼 수 있다.

1) a-kind-of

a-kind-of 슬롯은 유전적 기능을 사용할 수 있도록 한다. 현재의 객체가 다

를 객체의 모든 슬롯들을 갖도록 하는 기능을 갖고 있다. 즉 하나의 기본적인

객체를 만들고 이를 불러서 사용할 수 있는 기능을 갖고 있다. 예를 들어 box

를 하나 만들고 다른 종류의 box의 객체를 만들고 싶다면, (새객체이름 (a-

kind-of box) .......) 의 형태로 새로운 객체를 생성할 수 있다. 만약 이 객

체의 슬롯의 내용을 변경하고 싶으면 이에 해당하는 슬롯을 다시 적어 주면 된

다. 새로운 슬롯은 동일한 이름의 예전 슬롯의 내용에 덮어 쓰여진다. 유전형

질의 슬롯에 새로운 슬롯을 만들고 싶으면 새로운 슬롯의 이름을 현재의 객체

271

OOPACAD

Page 104: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

에 추가하면 된다.

2) draw

draw 슬롯은 AutoLISP에 의한 도형 설계 루틴이 들어간다. 즉 구체적으로

라인을 생성하거나 원을 만들거나 혹은 그림을 그리는데 관계된 모든 루틴을 집

어넣는다. 두 개 이상의 명령어로 구성될 때는 progn 명령어를 사용하여 하나

의 입력으로 처리되도록 한다. 여기에서 사용되는 파라미터 값들은 이외의 슬롯

값들을 참고하여 얻는 것이 가능한데 이 경우는 "the" 명령어를 사용함으로써

가능하다. 즉 선을 그리는데 주어진 슬롯 이름 pt1과 pt2의 값을 참고한다면

(draw (command "line" (the 'pt1) (the 'pt2) "")))의 형태로 쓸 수 있다.

3) children

children 슬롯은 하위 객체의 이름의 리스트로 주어진다. (children (a b c

d))의 슬롯 표현은 현 객체는 a, b, c, d의 4개의 객체를 하위 객체로 가지고

있음을 뜻한다. 상위 객체와 하위 객체의 개념은 앞에서 설명하 듯이 형질의

유전적인 이전, 즉 현재의 슬롯에서 참고할 내용이 없는 경우에는 상위 객체들

을 찾아올라 가면서 그 값을 찾는다. 현재의 객체를 확장하는 과정에서 어떤

슬롯의 값을 찾을 때 이것이 존재하지 않는 경우가 있다. 그러한 경우 이것의

상위 객체 중에 이러한 이름의 슬롯이 있는가를 확인하고 그렇지 않을 경우에

는 그 상위 객체의 상위 객체를 추적해 올라가면서 이 값을 찾는다.

parents 슬롯을 지정하여 줄 필요는 없는데 이는 OOPACAD 실행시

children에 해당하는 모든 객체에 partents 슬롯을 자동으로 추가하여 준다.

즉 현재 test라는 객체의 슬롯에 (children (a b c d))이 있는 경우 객체 a,

b, c, d에 대하여 각각 (parents test)라는 슬롯을 자동적으로 생성하여 준

다. 그러므로 사용자는 OOPACAD 프로그램시 children 슬롯만을 지정하면

된다.

272

제2 장 AutoLISP

Page 105: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

children을 이용하는 이유 중의 하나는 각각의 상위 하위 관계로 연결돼 객

체들이 나름대로의 좌표계를 갖는다는 것이다. 즉 동일 좌표계에서 존재하는

관련 객체들의 위치를 이러한 개념을 이용하여 일괄적으로 관리하는 것이 가

능하게 된다.

4) 위치 관련 슬롯

주어진 객체는 모든 축으로 회전 가능하다. (rotatex 90)에서 rotatex의 슬

롯 이름은 x축을 중심으로 하여 회전한다는 표현이며, 이에 대한 값은 몇 도

에 해당하는가를 나타내는 도의 값으로 주어진다. 즉 이 슬롯은 현재의 객체를

x축을 중심으로 90도 회전한다는 것이다. y, z축에 대하여는 rotatey,

rotatez의 슬롯 이름을 사용할 수 있다. 이들 회전 슬롯은 동시에 사용이 가능

하다. 즉 x축으로 얼마, y축, z축의 값들을 동시에 주면 그 객체를 3개의 축을

중심으로 각각 회전한 결과를 출력한다.

회전의 중심점을 주기 위하여 local_point라는 슬롯 이름을 사용한다. 현재

월드 좌표계에서 생성된 객체를 이 월드 좌표계로 local_point에 해당하는 점

273

OOPACAD

<그림 2-48>회전 슬롯을 이용한

도형의 회전

Page 106: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

을 중심으로 rotatex, rotatey, rotatez의 내용 만큼씩 회전하고 난 후 이 회

전 중심점을 월드 좌표계의 model_point에 위치시킨다. 예를 들어 (test

(rotatex 10) (rotatey 20) (rotatez 30) (local_point (1 1 1))

(model_point (3 0 0))은 현 객체의 좌표계 (1 1 1)의 점을 중심으로 하여 객

체 test를 x축으로 10도 만큼, y축으로 20도 만큼, z축으로 30도 만큼 회전시

킨 후에 이를 상위 객체 좌표계의 (3 0 0)의 점에 위치시킨다. <그림 2-48>과

<그림 2-49>는 이러한 위치 관련 슬롯을 이용한 도형의 생성 방법을 보여준다.

5) 함수 the, the2의 활용

한 객체에서 다른 슬롯의 내용을 참고하고 싶은 경우에는 (the '슬롯이름)

의 형태로 슬롯의 내용을 읽을 수 있다. 예를 들어 (test (var1 1) (var 2)

(var3 (+ (the 'var1) (the 'var2))))의 내용에서 var3의 값은 var1의 내용

과 var2 의 내용을 더한 값 3이 된다.

참고하고자 하는 슬롯의 이름이 현재의 객체 내에 존재하지 않고 이를 상위

객체로부터 참고할 경우에는 the2 함수를 사용한다. 이는 (the2 '슬롯이름 '

274

제2 장 AutoLISP

<그림 2-49>local_point와

model_point를 이용한도형의 정치 방식

Page 107: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

참고객체이름) 의 형식으로 사용되며, 참고할 객체의 이름으로부터 슬롯이름

의 내용을 읽고 이것을 찾을 수 없는 경우에는 그 상위 객체들을 추적해 감으

로서 원하는 슬롯의 값을 얻도록 한다.

다음 프로그램은 the2 의 활용 예를 보여준다.

(root

(children (leaf))

(one 1)

(two 2))

(leaf

my_two (the2 'one 'leaf))

(my_one (the2 'two 'leaf)))

<그림 2-50> the2의 활용 프로그램

슬롯 my_two는 1의 값이 슬롯 my_one은 2의 값이 할당되게 된다.

(2) Multiprocess의재조명

앞의 expand_n의 프로그램에서 슬롯 이름 quantity의 내용에 따라서 실행

은 unitprocess와 multiprocess로 분기하게 된다. 슬롯 quantity가 2개 이상

인 경우에는 multiprocess를 실행하게 된다. 이 경우 여러 가지 다른 기능들

을 추가하기 위하여 내용을 변경하도록 한다.

(defun multiprocess ( / se ce ee tss ct tlist llist tx ty tz dx dy dz qt ix iy iz)

(setq qt (the 'quantity))

(command "point" "0,0")

275

OOPACAD

Page 108: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(setq se (entlast))

(setq tlist (mmlist (car (the 'model_point))

(nth 1 (the 'model_point))

qt))

(setq llist (rmlist qt (the 'mradius)))

(setq tx (the 'mrotatex) ty (the 'mrotatey) tz (the 'mrotatez))

(if tx (setq dx (/ (- (nth 1 tx) (car tx)) (- qt 1))

ix (car tx)))

(if ty (setq dy (/ (- (nth 1 ty) (car ty)) (- qt 1))

iy (car ty)))

(if tz (setq dz (/ (- (nth 1 tz) (car tz)) (- qt 1))

iz (car tz)))

(setq ct '0)

(repeat qt

(progn

(command "ucs" "s" "temp")

(command "ucs" "or" (nth ct tlist))

(princ ix)

(if tz (progn

(command "ucs" "z" iz)

(setq iz (+ iz dz))))

(if ty (progn

(command "ucs" "y" iy)

(setq iy (+ iy dy))))

(if tx (progn

276

제2 장 AutoLISP

Page 109: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(command "ucs" "x" ix)

(setq ix (+ ix dx))))

(command "ucs" "or" (mapcar '- '(0 0 0)

(the 'local_point)))

(the 'draw)

(setq ct (+ ct 1))

(command "ucs" "r" "temp")

(command "ucs" "d" "temp")))

(command "point" "0,0")

(setq ee (entlast))

(setq tss (ssadd))

(setq ce se)

(while (not (equal ce ee))

(setq ce (entnext ce))

(setq tss (ssadd ce tss))

(prin1 ce))

(entdel se)

(entdel ee)

)

<그림 2-51> 수정된 multiprocess 프로그램

multiprocess는 객체의 quantity 슬롯의 값이 2 이상인 경우에 호출된다.

이는 동일한 도형의 형태를 공간상에 여러 개 배치할 목적으로 사용된다.

mulitprocess가 호출되는 경우 슬롯의 해석이 달라지는 경우가 발생한다. 일

반적인 경우에 model_point의 값은 한 점의 좌표로서 정의되나 multiprocess

277

OOPACAD

Page 110: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

인 경우에는 두 점의 좌표의 리스트로 정의된다. 그리하여 리스트의 첫번째 점

으로부터 두번째 점까지 quantity 슬롯의 개수 만큼의 도형을 등간격으로 배

열하게 된다.

local_point는 quanitity 슬롯의 값이 1인 경우와 마찬가지로 한 점의 좌표

로 주어진다. multiprocess의 경우에 추가적으로 사용되는 슬롯은 mradius,

mrotatex, mrotatey, mrotatez 등이 있는데 각각의 역할은 다음과 같다.

먼저 mradius는 현재의 원점을 중심으로 하여 생성하는 현 객체의

local_point를 위치시키는 반지름을 정의한다. 즉 (mraidus 4)는 현재의 원점

으로부터 반지름 4의 거리에 현재 quantity 개수 만큼의 동일한 객체를 위치

시키는 것을 의미한다. mrotatex, mrotatey, mrotatez는 시작하는 각도로

부터 끝나는 각도의 리스트로 구성되며 각각의 각도에 대하여 객체 자체의 좌

표를 회전시키면서 객체를 생성한다. 이상의 슬롯의 성질들을 이용하여 여러

가지의 형태를 만들어내는 것이 가능하다.

프로그램의 작동은 다음과 같다. quantity 슬롯의 값은 지역 변수인 qt에

할당된다. 함수 mmlist는 model_point의 첫번째 점과 두번째 점 사이를

quantity의 수 만큼으로 나누어 tlist라는 등간격의 점들의 리스트를 만든다.

한편 llist는 주어진 객체를 원형으로 배열할 경우에 이를 등간격으로 나누어

그 점들의 집합을 출력한다. tx, ty, tz의 값들은 역시 각각의 mrotatex,

mrotatey, mrotatez의 값들로 시작되는 각과 종료되는 각도로 표시되며 이들

값들이 각각 존재할 경우에 대하여 dx, dy, dz 값들을 증분하여야 할 각도의

양으로 계산한다.

이상과 같이 모든 값들이 할당되면 quantity의 수 만큼 반복하는데

local_point를 tlist로부터 하나씩 취하며, 각각의 축에 대하여 dx, dy, dz 만

큼 좌표축을 회전하여 도형을 생성하고 그 원점을 llist로부터 하나씩 취한 값

으로 model_point로 삼는다. 이후의 단계는 주어진 객체 전체를 선택하는 과

정을 나타낸다.(지금 상태에서 특별히 수행하는 역할은 없으나 나중에 다중 객

278

제2 장 AutoLISP

Page 111: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

체의 이름을 정의하기 위하여 사용할 수 있다.)

1) 기어 제작

(gear

(a-kind-of (box))

(width 1)

(height 0.5)

(length 0.5)

(quantity 20)

(local_point (-3 0 0))

(mrotatez (0 360))

(model_point ((0 0 0) (0 0 0)))

)

<그림 2-52> 기어 프로그램

279

OOPACAD

<그림 2-53> 기어 프로그램의 실행 결과

Page 112: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

기어 프로그램은 box 형태의 일종이다. 넓이 1, 높이 0.5, 길이 0.5의 상자

형태로서 20개의 동일한 도형으로 생성된다. 실행중 model_point의 위치는

변함이 없으며(왜냐하면 (0 0 0)로부터 (0 0 0)까지의 변화량은 없으므로 일

정한 점이 된다.), 각각의 좌표계는 z축에 대하여 18도 만큼씩 회전하고 각각

의 회전된 좌표축에 대하여 일정한 local_point 점을 원점에 맞추기 때문에 결

과적으로 전체 모양은 기어 형태가 된다.

2) 계단 제작

(stairs

(a-kind-of (box))

(width 1)

(height 0.5)

(length 0.5)

(mradius 0)

280

제2 장 AutoLISP

<그림 2-55>계단 제작 프로그램의

실행 결과

Page 113: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(quantity 8)

(local_point (0 0 0))

(model_point ((0 0 0) (4 4 4)))

)

<그림 2-54> 계단 제작 프로그램

계단 제작 프로그램은 넓이 1, 높이 0.5, 길이 0.5의 상자 모양을 좌표 (0

0 0)으로부터 좌표 (4 4 4)까지 8개를 등간격으로 배치하는 역할을 한다.

3) 스파이럴 제작

(spiral

(a-kind-of (box))

(width 1)

(height 0.2)

281

OOPACAD

<그림 2-57>스파이럴 제작

프로그램의 실행 결과

Page 114: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(length 0.5)

(mradius 0)

(quantity 60)

(local_point (-3 0 0))

(mrotatez (0 1000))

(model_point ((0 0 0) (4 4 4)))

)

<그림 2-56> 스파이럴 제작 프로그램

스파이럴 제작 프로그램은 넓이 1, 높이 0.2, 길이 0.5의 상자 60개를 원점

(0 0 0)로부터 (4 4 4)로 이동하면서 각각의 local_point(-3 0 0)의 값을 원점

에 일치시킨 것으로 스파이럴 형태의 모양을 얻을 수 있다.

(3) OOPACAD에자주사용되는원형들

자주 사용되는 기본 도형들을 기본 원형(primitive part)으로 정의하면 이

를 활용하여 쉽게 작업을 할 수 있다. 다음의 설계 과정에서 자주 사용되는 기

본 원형들을 정의하고 그 사용법을 설명하도록 한다.

1) Arc

: 와이어 프레임 호를 나타낸다.

center 호의 중심을 나타내는 3 차원 점의 데이터

radius 호의 반지름을 나타낸다.

end-angle 호가 끝나는 각도를 나타낸다. x 축의 + 방향을 기준으로 하여 반

시계 방향으로 정의한다. 단위는 radian을 취한다.

282

제2 장 AutoLISP

정의:

슬롯 이름:

Page 115: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

start-angle 호가 시작하는 각도를 나타낸다. 각도의 기준은 end-angle에서

와 동일하다.

end 호가 끝나는 3차원의 점을 출력한다.

start 호가 시작하는 3차원의 점을 출력한다.

height 반지름의 2배의 값을 출력한다.

length 반지름의 2배의 값을 출력한다.

width 반지름의 2배의 값을 출력한다.

(arc

(center (0 0 0))

(radius 1)

(start-angle 0)

(end-angle (* 2 (- pi 0.1)))

(end

(list (+ (car (the 'center))

(* (the 'radius) (cos (the 'end-angle))))

(+ (cadr (the 'center))

(* (the 'radius) (sin (the 'end-angle))))))

(start

(list (+ (car (the 'center))

(* (the 'radius) (cos (the 'start-angle))))

(+ (cadr (the 'center))

(* (the 'radius) (sin (the 'start-angle))))))

(height (* 2 (the 'radius)))

283

OOPACAD

메시지:

Page 116: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(length (* 2 (the 'radius)))

(width (* 2 (the 'radius)))

(angle-at-point a (+ a 1))

(draw (command "arc" "c"

(list (car (the 'center))(cadr (the 'center)))

(the 'start)

"a" (fix (* (- (the 'end-angle) (the 'start-angle))

(/ 180 pi)))))

)

인수 end는 end-angle, radius, center로부터 호가 끝나는 점의 3차원 좌

표를 출력하고, 인수 start는 start-anlge, radius, center로부터 호가 시작

하는 점의 3차원 좌표를 출력하도록 프로그램되어 있다. 이러한 기본 원형을

이용하여 각각의 중심을 바꾸면서, start-angle과 end-angle을 변화시키면서

호를 만드는 프로그램은 다음과 같다. command:에서 (expand_node

'arc1), (expand_node 'arc2), (expand_node 'arc3), (expand_node

'arc4) 등을 각각 실행하여 보자.

(arc1

(a-kind-of (arc))

(center (2 2 0))

(end-angle (/ pi 2))

(radius 1))

(arc2

(a-kind-of (arc))

284

제2 장 AutoLISP

Page 117: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(center (4 2 0))

(end-angle (* pi 1))

(radius 1))

(arc3

(a-kind-of (arc))

(center (6 2 0))

(end-angle (* pi 1.5))

(radius 2))

(arc4

(a-kind-of (arc3))

(center (8 2 0))

(start-angle (/ pi 2)))

<그림 2-58> Arc를 이용한 프로그램

285

OOPACAD

<그림 2-59>Arc의 실행 결과

Page 118: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

2) Box

길이, 넓이, 높이를 갖는 와이어 프레임 형태의 상자를 만든다.

length 상자의 길이를 정의한다.

height 상자의 높이를 정의한다.

width 상자의 넓이를 정의한다.

low_corner 상자의 모서리 점의 하나를 출력한다.

f_corner 상자의 모서리 점의 하나를 출력한다.

(box

(center (0 0 0))

(low_corner (list (- (car (the 'center)) (/ (the 'width) (float 2)))

(- (nth 1 (the 'center)) (/ (the 'length) (float 2)))

(nth 2 (the 'center))))

(f_corner (list (- (car (the 'center)) (/ (the 'width) (float 2)))

(- (nth 1 (the 'center)) (/ (the 'length) (float 2)))

(+ (nth 2 (the 'center)) (/ (the 'height) (float 2)))))

(p4 (mp f_corner (the 'width) (the 'length) (the 'height)))

(width 1)

(height 1)

(length 1)

(draw (progn

(command "line" (the 'f_corner)

286

제2 장 AutoLISP

정의:

슬롯 이름:

메시지:

Page 119: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(mp (the 'f_corner) (the 'width) 0 0)

(mp *rmp* 0 (the 'length) 0)

(mp *rmp* (- 0 (the 'width)) 0 0)

(mp *rmp* 0 (- 0 (the 'length)) 0)

(mp *rmp* 0 0 (- 0 (the 'height)))

(mp *rmp* (the 'width) 0 0)

(mp *rmp* 0 (the 'length) 0)

(mp *rmp* (- 0 (the 'width)) 0 0)

(mp *rmp* 0 (- 0 (the 'length)) 0)

(mp *rmp* (the 'width) 0 0)

(mp *rmp* 0 0 (the 'height))

(mp *rmp* 0 (the 'length) 0)

(mp *rmp* 0 0 (- 0 (the 'height)))

(mp *rmp* (- 0 (the 'width)) 0 0)

(mp *rmp* 0 0 (the 'height))

"c"))))

기본 도형 box는 직육면체 상자의 12개의 선을 연속하여 그리도록 한다. 이

를 이용하여 의자의 모양을 만들도록 한다. 의자는 4개의 발과 받침 부분, 등

받이 부분 등으로 구성되며 각각의 발은 받침 부분의 모서리에 위치하도록 한

다. 등받이는 받침과 같은 모양을 x축을 중심으로 90도 회전하여 이를 받침의

끝에 위치하도록 한다. command:에서 (expand_node 'chair)을 입력한다.

(chair

(children (seat back leg1 leg2 leg3 leg4)))

287

OOPACAD

Page 120: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(leg1

(a-kind-of (box))

(local_point (0 0 2))

(model_point (1.25 1.25 0))

(length 0.5)

(height 4)

(width 0.5))

(leg2

(a-kind-of (leg1))

(model_point (1.25 -1.25 0)))

(leg3

(a-kind-of (leg1))

(model_point (-1.25 1.25 0)))

(leg4

(a-kind-of (leg1))

(model_point (-1.25 -1.25 0)))

(seat

(a-kind-of (box))

(length 3)

(height 0.5)

(width 3))

288

제2 장 AutoLISP

Page 121: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(back

(a-kind-of (box))

(length 3)

(height 0.5)

(width 3)

(local_point (0 -1.5 0))

(model_point (0 1.5 0))

(rotatex 90))

<그림 2-60> 의자의 설계 프로그램

3) Circle

원의 기본 도형을 생성한다.

radius 원의 반지름을 입력한다.

289

OOPACAD

<그림 2-61> 의자 프로그램의 실행

결과

정의:

슬롯 이름:

Page 122: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(circle

(center (0 0 0))

(radius 1)

(draw (command "circle" (the 'center) (the 'radius))))

(circle1

(a-kind-of (circle))

(model_point (0 2 0))

(local_point (the 'center))

(rotatex 45))

(circle2

(a-kind-of (circle))

(model_point (0 4 0))

(local_point (the 'center))

(rotatex 90))

(circle3

(a-kind-of (circle))

(model_point (0 6 0))

(local_point (the 'center))

(rotatex 270))

(circle4

(a-kind-of (circle))

(model_point (0 8 0))

(local_point (the 'center))

290

제2 장 AutoLISP

Page 123: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(rotatex 350))

(display

(children (circle circle1 circle2 circle3 circle4)))

<그림 2-62> 원을 이용한 프로그램

Circle 기본 원형은 오토캐드의 circle 명령어를 이용하여 작성되었다. 프로

그램은 원의 중심을 바꾸어 가면서 위치를 회전시킨 결과를 출력하도록 한다.

command:에서 (expand_node 'display)를 입력하도록 한다.

4) Cylinder

실린더 모양을 출력한다.

radius 실린더의 반지름을 나타낸다.

291

OOPACAD

<그림 2-63>원을 이용한

프로그램의 실행 결과

정의:

슬롯 이름:

Page 124: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

length 실린더의 높이를 나타낸다.

(cylinder

(center (0 0 0))

(radius 1)

(depth 1)

(draw (progn

(command "thickness" (the 'depth))

(command "circle" (the 'center) (the 'radius))

(command "thickness" "0"))))

(round-table

(children (base leg table-top vase)))

(base

(a-kind-of (cylinder))

(radius 1)

(depth 0.1))

(leg

(a-kind-of (cylinder))

(radius 0.5)

(depth 7)

)

(table-top

292

제2 장 AutoLISP

Page 125: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(a-kind-of (cylinder))

(radius 4)

(depth 0.1)

(model_point (0 0 7))

(local_point (0 0 0))

)

(vase

(a-kind-of (cylinder))

(radius 0.3)

(depth 1)

(model_point (0 0 7.1))

(local_point (0 0 0))

)

<그림 2-64> Cylinder를 이용한 round-table 설계 프로그램의 실행 결과

293

OOPACAD

<그림 2-65> cylinder를 이용한

round-table의 제작

Page 126: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

round-table은 기본 원형인 실린더로 구성된 테이블 탁자를 나타낸다. 이는

받침대, 축, 탁자 판과 그 위에 위치하는 꽃병으로 구성되어 있고, 각각의 모

양은 각 객체간의 상대적인 위치로 정의된다. command:에서 (expand_node

'round-table) 을 실행하도록 한다.

5) ellipse

와이어 프레임 형태로 타원의 모양을 만들어낸다.

center 타원의 중심을 나타낸다.

pt1 타원 위의 한 점을 나타낸다.

pt2 타원 위의 다른 한 점을 나타낸다.

(ellipse

(center (0 0 0))

(pt1 (1 0 0))

(pt2 (-1 0 0))

(draw (command "ellipse" (the 'center) (the 'pt1)

(the 'pt2) "" "")))

(display

(a-kind-of (multiple ellipse))

(quantity 5)

(q_s_point (0 0 0))

(q_e_point (15 15 15))

(hinge_point (the 'center)))

<그림 2-66> ellipse를 이용한 프로그램

294

제2 장 AutoLISP

정의:

슬롯 이름:

Page 127: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

객체 display는 5개의 타원을 점 (0 0 0)로부터(15 15 15)의 사이를 등간격

배치한다. command:에서 (expand_node 'display)를 실행한다.

6) polygon-projection

주어진 꼭지점으로 이루어진 다각형을 일정 두께로 투사하여 나타

낸다.

p_list 다각형의 꼭지점의 2차원 점의 집합을 나타낸다.

depth 투사할 깊이를 나타낸다.

(polygon-projection

(center (0 0 0))

(p_list '((0 1)(1 1)(1 0)))

(depth 1)

295

OOPACAD

<그림 2-67> ellipse를 이용한

프로그램 실행 결과

정의:

슬롯 이름:

Page 128: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(draw (progn

(command "thickness" (the 'depth))

(command "pline")

(foreach pt (the 'p_list) (command pt))

(command "c")

(command "thickness" "0"))))

(poly-table

(children (base leg table-top vase)))

(base

(a-kind-of (polygon-projection))

(p_list '((1 1) (1 -1)(-1 -1)(-1 1)))

(depth 0.1))

(leg

(a-kind-of (polygon-projection))

(depth 7)

)

(table-top

(a-kind-of (base))

(p_list '((4 4)(4 -4)(-4 -4)(-4 4)))

(depth 0.1)

(model_point (0 0 7))

(local_point (0 0 0))

296

제2 장 AutoLISP

Page 129: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

)

(vase

(a-kind-of (base))

(depth 1)

(model_point (0 0 7.1))

(local_point (0 0 0))

)

<그림 2-68> polygon-projection을 이용한 poly-table의 설계 프로그램

poly-table은 round-table이 cylinder 도형 원형을 이용한데 반해,

polygon-projection을 이용하여 leg은 삼각형 투사 형태로 나머지는 사각형의

투사 형태로 table을 설계한 것이다. command:에서 (expand_node 'poly-

table)을 실행한다.

297

OOPACAD

<그림 2-69>polygon-projection을

이용한 poly-table프로그램의 실행 결과

Page 130: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

7) line

직선을 정의한다.

length 직선의 전체 길이를 나타낸다.

start 직선의 시작 점의 3차원 위치를 나타낸다.

end 직선의 끝점의 3차원 위치를 나타낸다.

direction-vector 직선의 시작점으로부터 끝점을 지시하는 벡터를 나타낸다.

(line

(center (0 0 0))

(length (distnace (the 'start) (the 'end)))

(start (0 0 0))

(end (1 1 1))

(direction-vector (mapcar '- (the 'end) (the 'start)))

(height 0)

(width 0)

(draw (command "line" (the 'start) (the 'end) "")))

(line-example

(children (line1 line2 line3 line4)))

(line1

(a-kind-of (line))

(start (0 -1 0))

(end (0 1 0))

298

제2 장 AutoLISP

정의:

슬롯 이름:

Page 131: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

)

(line2

(a-kind-of (line1))

(model_point (1 0 0))

(local_point (0 0 0)))

(line3

(a-kind-of (line1))

(rotatez 90))

(line4

(a-kind-of (line2))

(rotatez 90))

<그림 2-70> line-example 프로그램

299

OOPACAD

<그림 2-71>line-example의 실행

결과

Page 132: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

객체 line-example은 4개의 선을 공간상에 위치시키는 방법을 보여준다.

(4) OOPACAD 적용예제(Parthenon)

OOPACAD를 이용하여 고대 신전인 parthenon을 제작하여 보자. 간략화

한 parthenon의 모양은 지붕과 기둥, 그리고 지지대로서 구성된다. 세부적인

하위 객체들의 모양을 프로그램하기에 앞서서 먼저 parthenon 자체의 슬롯을

정의하여 보자. 전체적으로 하나의 parthenon을 만들기 위하여 변수로서 설

정하고자 하는 슬롯은 4개로 한다. 신전의 높이, 기둥의 지름, 신전의 개략적

인 넓이와 길이 등을 상위 객체에서 지정하고자 한다. 프로그램 내용은 다음과

같다.

(parthenon

(children (roof culumn1 culumn2 bolster1 bolster2))

(p-height 15)

(c-raidus 0.5)

300

제2 장 AutoLISP

<그림 2-73>객체 parthenon의

실행 결과

Page 133: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(p-width 5)

(p-length 5))

<그림 2-72> 객체 parthenon의 프로그램

parthenon의 하위 객체는 roof, culumn1, culumn2, bolster1, bolster2

로 구성되어 있다. roof은 지붕으로써 polygon projection의 기능을 이용하여

삼각형을 늘려서 만들 수 있다. culumn1은 원하는 수량의 cylinder를 만들고

이와 대칭되는 위치에 culumn2을 만든다. bolster1과 bolster2는 box를 이

용하여 만든다.

(roof

(a-kind-of (polygon-projection))

(p_list (list (list (* (the2 'p-width 'roof) -1) 0)

(list (the2 'p-width 'roof) 0) (list 0 2)))

(depth (the2 'p-length 'roof))

301

OOPACAD

<그림 2-75>객체 roof의 실행 결과

Page 134: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(rotatex 90)

(local_point (list 0 0 (half (the2 'p-length 'roof))))

(model_point (list 0 0 (the2 'p-height 'roof)))

)

<그림 2-74> 객체 roof의 프로그램

객체 roof은 polygon-projection의 기능을 물려받는다. polygon-

projection은 p_list와 depth 슬롯을 필요로 한다. p_list는 확장할 다각형의

꼭지점의 리스트이고, depth는 확장하는 깊이를 나타낸다. 꼭지점의 좌표로

는 x축으로 상위 객체의 슬롯 이름인 p-width의 값에서 1을 감한 값으로 위

치하고, 그와 대칭되는 위치에 하나의 점이 위치하며, (0 2)의 위치에 마지막

점이 위치하여 삼각형의 형태를 갖추게 된다. 이를 z축으로 상위 객체의 슬롯

인 p-length의 내용만큼 늘린 도형을 생성하게 된다. 지금까지 생성된 도형

은 z축의 방향으로 위치한 삼각 기둥의 모양이므로 이를 x축에 대하여 90 회

전시킨 후, 중심점을 parthenon 의 좌표 계의 z축 방향 p-height에 위치하

도록 한다.

(culumn1

(a-kind-of (cylinder))

(quantity 3)

(radius 0.5)

(depth (the2 'p-height 'culumn1))

(mradius 0)

(model_point (list (list (- 1 (the2 'p-width 'culumn1))

(- (half (the2 'p-length 'culumn1)) 0.5)

0)

302

제2 장 AutoLISP

Page 135: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

(list (- 1 (the2 'p-width 'culumn1))

(- 0.5 (half (the2 'p-length 'culumn1)))

0))))

(culumn2

(a-kind-of (culumn1))

(model_point (list (list (- (the2 'p-width 'culumn2) 1)

(- (half (the2 'p-length 'culumn2)) 0.5)

0)

(list (- (the2 'p-width 'culumn2) 1)

(- 0.5 (half (the2 'p-length 'culumn2)))

0))))

<그림 2-76> 기둥의 프로그램

303

OOPACAD

<그림 2-77>기둥 프로그램의

실행 결과

Page 136: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

기둥은 실린더의 값을 유전받도록 한다. 실린더는 radius와 depth의 슬롯

을 필요로 한다. radius 는 현 프로그램에서는 일괄적으로 0.5로 처리하 으

나 이는 상위 객체의 슬롯 p-radius로부터 받게 하는 것도 바람직하다.

depth은 상위 객체로부터 p-height 슬롯의 내용을 참고하도록 되어 있다. 원

형 배열이 아니기 때문에 mradius 의 값은 0으로 한다.

model_point는 parthenon의 넓이로부터 1 만큼 안쪽으로 x축의 위치에,

길이의 반으로부터 y 값으로 0.5 감한 안쪽으로부터 이에 대칭되는 장소에 위

치하게 된다. culumn2는 culumn1과 동일하고 이와 대칭되는 위치로

model_point의 x 좌표의 값만이 변경되었음을 확인할 수 있다.

(bolster1

(a-kind-of (box))

(width (+ (the2 'p-width 'bolster1) 2))

(length (+ (the2 'p-length 'bolster1) 2))

(height 1)

(local_point (list 0 0 (half (the 'height))))

)

(bolster2

(a-kind-of (bolster1))

(width (+ (the2 'p-width 'bolster2) 3))

(length (+ (the2 'p-length 'bolster2) 3))

(height 0.1)

(local_point (list 0 0 (+ (the2 'height 'bolster1)

(half (the 'height))))))

<그림 2-78> bolster 프로그램

304

제2 장 AutoLISP

Page 137: AutoLISP - plm.or.kr · Ø Þ È Q ñ Þ × j I > Þ Þ î I × Q ñ W > Â W x 8 x é Ñ Ë Ø Þ È É \ L û S × m á I I î _ B 8 Q ñ Þ × À ( ´ ' À ²

두 개의 지지대는 box의 형태로 구성된다. bolster1는 parthenon 크기의

넓이와 길이를 각각 2 만큼 늘이고, 높이는 1로 한다. 윗면을 기둥의 바로 아

래인 원점에 위치시키기 위하여 local_point의 z 좌표의 값을 상자 높이의 중

간으로 잡았다.(상자의 원점은 그 중심에 존재하기 때문이다.) bolster2 형태

도 마찬가지이나 넓이와 길이를 3 만큼씩 늘 고 높이를 0.1로 하 다.

local_point 값은 윗면에 위치한 bolster1의 높이를 감안하여 그 높이 만큼과

bolster2 높이의 반의 값을 더한 값으로 잡았다. command:에서

(expand_node 'bolster1), (expand_node 'bolster2)를 각각 입력하여 그

모양을 확인할 수 있다.

305

OOPACAD

<그림 2-79>bolster 프로그램의

실행 결과