티스토리 뷰

반응형

오토리습으로 도면 그리는 사람들도 이젠 칼퇴근 좀 해 봅시다!. 가정으로 돌아가 가정을 돌보자구요!

autolisp은 단축키? '단축키를 만들어보자'

캐드의 Acad.pgp 는 사용자로 하여금 단축키를 정의할 수 있는 화일인데, 이를 통해서 우리가 쉽게 한글자 또는 한 단어로 쉽게 명령을 실행하는 것이다.

1. 'Line' 명령의 단축키

지금의 autocad상에서는 'vlide'란 명령어를 입력하면 화면이 하나 뜹니다. 아래와 같이 말이죠.

오토캐드에서 제공하는 lisp 편집기라고 보면 됩니다.

자, 이제 여러분의 생애 첫 리습을 만들어 봅시다.

(defun c:Li() (command "LINE"))

위의 명령어는 "line"을 "Li" 라는 단축키로 정의해 둔 것입니다.
즉, c: 다음의 "Li" 가 단축키로 사용될 단어? 또는 키라고 말 할 수 있습니다.
여러분이 만약 단축키를 "abc" 로 바꿔 사용하고 싶다면, 이렇게 하면 되겠죠?

(defun c:abc() (command "LINE")) 이렇게 하시면 됩니다.

-> 참고로 리습을 하면서 가장 어려운 부분일 수 있겠지만, 괄호 '(' ')' 이것이 중복되면 가장 헷갈리는 요소입니다. 리습과 친해지려면 괄호와 가까워 져야 합니다. ^^

2. 리습의 첫 시작 '(defun' 이란 뭘까요?
명령을 정의한다는 뜻입니다. 아마도 definition function 이 약자 같습니다. 연상되시죠? 리습의 시작은 '(defun' 으로 하죠.  우선 캐드에서는 "("를 열어야 리습인줄 압니다. 이건 그냥 문법이라고 이해해야 합니다. 프로그램을 구성하는 문법말이죠.

3. c: 이란?
command 이란 의미로서 캐드 명령어로 사용한다는 의미를 내포하고 있습니다.
"c:" 이 없으면 캐드에서 아무리 쳐도 찾을 수 없다는 명령어라고 나오니, 반드시 문법을 지켜주세요. 이것도 그냥 암기
"Li" 뒤의 ()도 마찬가지니, 리습 프로그램을 구성하는 구조라고 이해하면 좋을 것 같아요.

4. (command "line") 어떤 의미일까요?
command는 캐드 입력화면에서 하나하나 키보드를 쳐야 하는데, 이를 바로 구현해 주는 고마운 기능입니다. 노가다 금지... 같은 것이죠. 원래는 캐드화면에서 사람이 "line" 이라고 당연히 키보드를 쳐야 하는데, 그것을 대신하여 위에 처럼 쓰죠. 그럼, 실전에서 한번 사용해 봅시다.

예시) 도면의 0,0 좌표(x,y)에서 x200, y200으로 선을 하나 그려보자구요. 리습으로 구현한 생애 첫 실습이네요.  성공을 기원합니다. 

(defun c:Li()
(command "line" "0,0" "200,200")
)

괄호 숫자에 꼭 주의하세요. 실제 실행하면 아래와 같은 결과물이 나옵니다.

생애 첫 리습실습


결과물은 (X 0,Y 0)에서 (X 200, Y200) 으로 대각선을 그려준 것을 볼 수 있습니다. 와우~ 축하드려요. 이렇게 하나씩 배워가다보면 분명 멋진 결과물 그리고 복잡한 결과물도 만들 수 있습니다.

원을 그리는 것도 마찬가지겠죠?

(defun c:Cir()
(command "circle" "0,0" "100")
)

명령어 창에 'Cir' 입력하면 실행되겠죠? 한번 해 봅시다.


결과 화면을 보면,  (X 0, Y 0)에 반지름 100인 원을 그렸습니다. circle이란 명령어를 몇번의 입력을 거치지 않고 바로 구현, 이것이 리습의 힘입니다.

여기서 꼭 주의해야할 팁이 있는데,  괄호 "("의 갯수와 ")"의 갯수가 꼭 같아야 합니다. 아니면 에러가 발생하는 것은 당연하겠죠?


리습(Lisp)의 연산 방법



리습 프로그램에서 연산은 어떻게 할까? 사실 변수란 것을 알고 연산을 알아야 우리가 말하는 자칭 프로그램이란 것을 할 수 있습니다. 여기서 리습이 약간 어렵게 느껴지는 요소중 하나는 '괄호', 그리고 또 하나는 '연산의 표현'이라고 개인적으로 생각합니다.

우리가 만나는 일반적인 프로그램은 a라는 변수에 1을 더한다. 이런식은 보통 언어에서 a = a+1 또는 간략형으로 a++  이런식이 대부분이죠. 하지만, 리습은 처음 개발한 분이 모양을 이상하게 만든 것 같습니다. 어떤 심오한 의미가 있는지는 잘 모르겠지만요.

예를 들어,  "1 + 2" 이라고 하는 간단한 연산을 표현하는 방식이 (+ 1 2) 이렇게 표현합니다. 

(연산자 대상1 대상2) 뭐 이런식이죠.

그 연산 규칙을 살펴보면, 
1. 연산의 앞뒤로 꼭 괄호()를 열었다 닫아야 합니다.
   모든 리습에서의 연산과 명령어는 괄호를 꼭 열고 닫아야 하죠. 이래서 괄호가 정말 많은 리습입니다.



2. 괄호 다음에 연산기호는 꼭 앞에 먼저 씁니다.

3.  연산의 대상을 차례로 쓰는 방식이지요.
     123 + 456    ->    (+ 123 456)
     123 x 987    ->    (* 123 987)
     546 - 123    ->    (- 546 123)
     345 / 123    ->    (/ 345 123)
   이 예시를 보면 이해가 빠를거예요.


4. 그렇다면 3개 이상의 대상이 있다면? 여러숫자의 연산도 원리는 같습니다.
   똑같은 기호의 연산은 연산기호를 제일 앞에 표현하고,  대상 숫자를 줄이어 씁니다.

예시)
   1 + 2 + 3 + 4 + 5    ->   (+ 1 2 3 4 5)
   5 x 4 x 3 x 2 x 1    ->   (* 5 4 3 2 1)


   다른 기호의 연산, 기호를 혼용하는 경우 괄호의 우선 순위를
   보고 아래와 같이 한다.

   1 + ( 3 x 4 )        ->   (+ 1 (* 3 4))
   ( 4 / 2 ) - 4        ->   (- (/ 4 2) 4)

   괄호안의 연산을 먼저하고 그 외 연산들을 순서에 맞춰서
   표기하면 된다.

리습(Lisp) 변수의 정의 

리습에서의 변수를 정의하는 법은 변수를 통해 여러가지 동작을 제어하기 위함입니다.

1. 변수란 무엇인가?

변수는 간단히 '기억 공간'이라고 생각하면 됩니다. 어떤 값 어떤 정보를 기억하려면 그 저장공간이 필요한데, 그걸 '네이밍' 한 것이죠. 이름을 부여해 주는 것입니다. 그래야 연산을 하던 불어오던 비교를 하던 하니까 말이죠.

우리가 많이 사용하는 파이(PI)의 숫자는  3.141592~~ 이런식으로 복잡한 숫자인데, 이를 프로그램에서 계속 써야 하는데, 저 숫자를 'pi'라는 영문에 넣고 사용하고 싶다면?

이런 의문에서 출발하는 것이지요. 그러면, 3.141592 라는 숫자를 pi 로 정의해 놓으면, 간편하게 우리가 쓸 수 있으니, 변수라는 것이 이 역할을 해준다고 생각하시면 됩니다. 그 다음부터는 pi 라고만 써도 3.141592 라고 인식하는 것을 말하죠.



위의 내용을 리습으로 정의한다면 아래와 같이 되겠죠?
(setq pi 3.141592)

여기서 또 하나의 단어 'setq'가 나오네요.

2. 그렇다면, setq 란 무엇인가?

변수를 정의할때 꼭 등장하는 명령어 입니다.  내부 명령어라고 생각하세요. 배정, 설정하는 변수라고 설명하면 좋겠네요.

3. (setq a b)

b 의 값을 a에 넣는다, 저장한다, 뭐 이런 의미로 받으들이면 적절한 것 같습니다.

4. 숫자를 넣는 것도 마찬가지입니다.

(setq test1 123.456)

숫자 123.453를 test1이란 변수에 저장합니다.
test1 <-- 123.453 이렇게 이해해도 좋고, test1 = 123.453 이라고 이해해도 좋습니다.

그렇다면 위의 내용을 혼합해서 표현하는 예시를 보겠습니다.



(setq test1 123)
(setq test2 456)
(setq test3 (+ test1 test2))
결과값  test3에 저장된 것은  test1+test2 값인 123+456 즉, 579 입니다.



5. 문자의 정의도 숫자과 유사합니다.

(setq test4 "this is sample")

숫자와 차이점이 있다면, 문자는 "" 안에 있어야 합니다. 
test4 에 this is sample 이라는 글을 갖고 있는 것입니다.

6. 문자, 숫자 이외의 기타 데이터의 정의

숫자, 문자는 기본이고, 객체나 속성들도 변수로 정의할 수 있습니다. 이것이 정말 강력한 lisp의 기능인 것이죠.


여러변수의 나열방식 정의 및 주석(설명글) 달기

여러변수가 있다고 가정하면, 변수정의를 더 편리하게 하는 방법이 있다면 배워야 겠죠?



3개의 변수를 정의해야 하는데, 차례대로 적어놓으면...

(setq a 1)
(setq b 2)
(setq c 3)

위의 식은 a=1, b=2, c=3 을 대입하란 뜻이죠. 하지만 좀 길게 느껴집니다.

(setq a 1 b 2 c 3)

이렇게 표현해도 같다면? 여러분은 어떤 코드를 사용하시겠습니까? 아무래도 프로그램을 더 짧게 표현하는 방식이 있다면 그렇게 배우고 연습하는 것이 맞습니다.


방법은 setq 문은 한번만 써주고 차례대로 변수이름, 값들을 나열하면 됩니다.
아래처럼 다르게 표현도 가능합니다. (리습에서는 줄바꿈의 의미가 없습니다.)

(setq a 1
       b 2
       c 3
)
위의 표현식은 사람이 보기 좋은(가독성 좋은) 코드가 될 것입니다.

나중에 수정하고 할때 코드를 보면, 한눈에 들어오면 더 좋겠죠?

2. 주석(설명글)을 달아보겠습니다.

주석은 다음에 프로그램을 수정하거나 다른 사람이 볼때 도움을 줄 수 있는 설명문입니다.

주석은 세미콜론(;)을 사용해서 표현합니다.

; 이 리습은 test
(defun c:test()
     ; 변수를 정의합니다.
     (setq a 1           ; a값을 1로 정의합니다.
           b 2           ; b값을 2로 정의합니다.
           c 3           ; c값을 3로 정의합니다.
           d (+ a b c))  ; a+b+c 값을 d값으로 명명합니다.
     )
     ; 변수 정의가 끝났습니다.
  ); end of defun      

디버깅(에러 코드 수정)을 위해서 가장 많이 주석을 사용한다고 봐도 될 것 입니다.

주석의 위치는 위의 코드에서 보듯이 아무곳이나 가능합니다. 앞부분, 중간, 뒷부분... 전부 가능합니다.

세미콜론(;)만 있으면 그렇게 인식하는 것을 알 수 있습니다.


이젠 리습으로 Text창(command창)에 글자를 출력해 봅시다

캐드화면 중간하단, 즉 명령어나 글자를 쳐넣을 수 있는 곳 있죠?
거기가 바로 command창이고요, 그 곳에 글자를 출력하도록 해봅니다.

1. (prompt 내용)

(prompt "This is test")

이렇게 한번 써보세요.
캐드 text창에 "This is test"라고 출력됩니다.

줄바꿈을 하고 싶으세요?
줄바꿈은 "\n" 을 사용합니다. 위의 예제를 줄바꾸어서 출력하려면

(prompt "\nThis is test")

그럼 test라는 명령을 치면 화면에 "This is test" 라고
출력하게 해볼까요?

(defun c:test()
      (prompt "This is test")
) ; end of defun

아래도 해봅시다. (줄바꿈 연습)

(defun c:test() (prompt "\nThis is test"))

2. (princ 내용 []),
(prin1 내용 []),
(print 내용 [])

위의 3가지는 같은 결과를 나타냅니다. 아무거나 써도 됩니다.
왜 3가지가 있는지는 잘 모르겠습니다.
혹시 아시는 분은 글을 남겨주세요..
prompt 명령과 비슷하나 내용이 문자열이 아니어두 됩니다.
내용을 그대로 출력하고 내용을 응답합니다.
예를 들어보죠.

(princ 123)

이렇게 하면 화면에 123이라고 나오고 123이라고 다시한번 응답합니다.

주로 (princ) (print) (prin1)의 용도는 리습의 끝부분에 쓰여집니다.
왜냐면 리습의 실행후에 화면에 응답값을 표시하지 않기 위함이죠

위의 1번의 예제에서

(defun c:test()
      (prompt "This is test")
(princ)    ; <------------------이줄을 추가
) ; end of defun

(princ)를 추가한후와 추가하기전에 test를 실행하면
화면에 나타나는 것을 보세요
추가하기전에는 글자뒤에 nil이라는 글이 붙을 겁니다.
응답값이 nil이란 거죠.
(princ)를 추가하면 응답값을 표시하지 않죠?

그래서 주로 리습의 맨 끝부분에 써줍니다.  

------ 리습강의 (6) ------

▶ (command)문의 활용 ◀

(command)는 앞에서도 설명한 바와 같이 캐드에서 사람이 일일이
키보드로 Typing 하는 것과 같은 효과를 나타냅니다.
아래의 예제는 Text창에서 직접 입력하셔서 테스트 해보세요.

1. Line을 그려보자

(command "line" "0,0" "100,100" "")

(0,0)에서 (100,100)까지 선을 그러줍니다.
그렇다면 뒤의 ""은 무엇일까요.
캐드에서 Line 명령을 하면 from point, to point 를 물어보고
점을 하나 찍으면 또다시 to point 를 물어봅니다.
그때 [엔터]나 [스페이스바] 또는 [마우스의 오른쪽 버튼]을 누르죠?
""는 [엔터]를 의미합니다.
""를 써줘야 Line 명령을 끝을 냅니다.

""를 빼고 (command "line" "0,0" "100,100") 이라고 해보세요
그러면 다음 포인트를 또 물어볼것입니다.

(command)문은 스페이스(빈공간)으로 구분됩니다.

2. circle를 그려보자

(command "circle" "0,0" "100")  
     -> (0,0)에서 반지름 100인 원작성

(command "circle" "10,10" "d" "200")
     ->  (10,10)에서 지름이 200인 원작성

3. 글자를 써보자

(command "text" "100,100" "2.5" "90" "Test string")
     -> (100,100)에서 글자높이 2.5, 각도 90도,
        Test string 이란 글을 화면에 써줍니다.

(command "text" "j" "r" "100,100" "2.5" "90" "Test string")
     -> 위의 내용은 글자의 오른쪽 맞춤의 속성인 글자 생성
        "j" "r" 이란 "justify" "right" 이란거 다 아시죠?

4. Layer를 하나 생성해보자

(command "layer" "N" "test" "c" "yellow" "test" "")
     -> test라는 레이어를 하나 생성하고
        색을 노랑으로 하는 리습입니다.
        순서를 잘 모르면 (command "layer")까지만 치고
        순서를 익히시키는 것이 필요하겠죠.
        (command "layer") 라고 쳐도 좋고 -layer 이라고
        "-"를 앞에 붙여서 typing 해도 좋습니다.

5. 도면을 insert해보자

(command "insert" "c:/test" "0,0" "1" "1" "0")

      -> c:\test.dwg 라는 도면이 있을 경우입니다.
         c:\test.dwg 라는 도면을 아무거나 하나 만들고 테스트
         해보세요
         여기서, 주의!!
         리습의 디렉토리 구분글자 역슬래쉬, 또는 \ 글자는
         슬래쉬(/)로 대체합니다.
         꼭 "/" 로 디렉토리 구분을 해야합니다..꼭꼭꼭
         "\" 문자는 특수문자 입력시 사용하거든요.
        
         위의 리습은 test.dwg 도면을 좌표 (0,0)
         x scale : 1 , y scale : 1 , 회전각도 0도로
         삽입시킵니다.


------ 리습강의 (7) ------

▶ 사용자에게 입력값을 받아보자 ◀

리습의 제작은 사용자로 하여금 입력을 받고 싶은 경우가 있습니다.
이렇게 사용하는 방법을 알아보죠.
그중에서도 글자나 숫자를 입력받는 가장 쉬운 방법을 소개합니다.
또한 가장 많이 쓰이기도 하죠.

(getint)
(getreal)
(getstring)

1. 숫자의 입력 (1) - 숫자중 정수만을 입력받고 싶을때

(getint)

예로 알아 봅시다

(setq test1 (getint))

이렇게 하면 test1 이라는 변수에 사용자가 입력한 값을
넣어 줍니다. 정수만되죠.

(setq test1 (getint "값을 입력하시오 : "))

이렇게 하면 화면에 "값을 입력하시오 : " 라는 메세지가 화면에
표시 됩니다. 화면에 메세지를 출력해 주면 사용자가 어떤값을
입력해야 하는지를 쉽게 알 수 있습니다.

2. 숫자의 입력 (2) - 모든 숫자의 입력

(getreal)

(getint)가 정수만을 입력 받지만 (getreal)은 모든 숫자를 입력
받습니다.

아래 예제입니다.

(setq test2 (getreal "숫자를 입력하시오 : "))

3. 문자의 입력

(getstring)

문자를 입력 받습니다. 다음은 예제입니다.

(setq test3 (getstring "당신의 이름은? "))

캐드에서는 스페이스가 엔터기능입니다.
여기서 스페이스를 엔터기능으로 사용하지 않고 공백으로 사용하려면
(getstring <메세지> t) 하면 됩니다. 뒤에 t 만 달아주면 되죠..

4. 전체적인 예제입니다.

(defun c:test()
      (setq t1 (getint "첫번째 정수는 : "))  ; 사용자로 하여금 정수입력받음 (t1)
      (setq t2 (getreal "두번째 숫자는 : ")) ; 사용자로 하여금 실수입력받음 (t2)
      (setq t3 (+ t1 t2))                    ; 두 수의 합을 구함 (t3)
      (prompt "\n계산된 결과값은 = ")        ; 화면에 "계산된 결과값은 = "을 표시, \n은 줄바꿈
      (princ t3)                             ; 화면에 덧셈결과값인 t3 출력
      (princ)                                ; 기본적으로 꼭 써주는 연습. (응답값을 표시 하지 말라는 입력문)
)                                           ; end of defun
 

캐드화면에서 점(Point)를 요구해서 처리하는 리습을 작성한다면?

캐드화면에서 점(point)의 값을 받아오는 간단한 리습 명령어

(getpoint)
(getcorner)

1. (getpoint [기준점] [화면표시글])

한점의 좌표를 구해옵니다. [기준점]과 [화면표시글]은 생략가능.

(getpoint "한점을 클릭하시오 : ")

이렇게 하면 test1 값은 (x y z)의 좌표를 가진 리스트입니다.
리스트란 ( ) 안에 묶여서 한 그룹처럼 형성된 형태입니다.

<예제1>
   (defun c:test1()
         (setq p1 (getpoint "첫번째 점을 찍으세요"))
         (setq p2 (getpoint "두번째 점을 찍으세요"))
   (princ))

<예제2>
   (defun c:test2()
         (setq p1 (getpoint "첫번째 점을 찍으세요"))
         (setq p2 (getpoint p1 "두번째 점을 찍으세요"))
   (princ))

<예제1>과 <예제2>의 다른점을 (getpoint p1...) 입니다.
두가지 다 해보시면 알겠지만 <예제2>는 기준점을 제공합니다.
기준점에서 선이 항상 따라다니죠? 해보면 누구나 알 수 있습니다.

2. (getcorner 기준점 [화면표시글])

  (getpoint) 와 비슷하지만 사각형의 테두리선을 보여줍니다.
  기준점은 꼭 있어야 하고 화면표시글은 생략가능합니다.
  예제를 통해서 알아보겠습니다.

  (defun c:test3()
        (setq p1 (getpoint "첫번째 구석은?"))
        (setq p2 (getcorner p1 "두번째 구석은?"))
  (princ))

3. 예제를 통해 응용해 봅시다.
   다음은 점을 찍으면 그 자리에 반자름이 10인 원을 그립니다.  

  (defun c:test4()
     (setq r 10)              ; 반지름을 10 으로 r 이라는 변수로 정의
     (setq p1 (getpoint "원의 중심위치는 :"))           ;중심값 사용자 요구 (p1)
     (command "circle" p1 r)           ; p1위치에 r의 값인 원 작성
  (princ))

    다음은 두 점을 선택하면 그 점에 라인을 그리는 리습입니다.
    사실 선을 그리는 것은 이 리습이 없어도 되지만
    응용하기 위한 연습입니다. 필요없다 생각말고 따라해 봅시다.

  (defun c:test5()
     (setq p1 (getpoint "선의 시작위치는 :"))
     (setq p2 (getpoint "선의 끝위치는 :"))
     (command "line" p1 p2 "")
  (princ))
 
리습에서 사용하는 편리한 LIST란 무엇인가?

LIST란 ()안에 묶여서 하나의 그룹을 형성합니다.
주로 좌표를 작성하는데 사용하며, 때때로 데이터를 묶어서 사용하고자
할때 사용하기도 합니다.
우선 우리는 좌표만을 가지고 합시다.

1. LIST 만드는 방법

(list a b c)

list의 구분은 한칸의 공백으로 표현합니다.
a,b,c 는 각각 한칸의 공백간격이 필요하죠
a, b, c 세개를 그룹화하여 리스트를 만듭니다.
좌표로 사용할 경우 a,b,c 각각이 x,y,z 좌표입니다.
z좌표는 생략될 수 있습니다.

좌표는 리스트형태로 써주어도 되고 따움표("")안에 넣어서
사용할 수 있습니다.
예를 보겠습니다.

<방법1> (command "line" (list 100 100) (list 200 200) "")
<방법2> (command "line" "100,100" "200,200" "")

위의 두가지 방법은 모두 100,100 에서 200,200 으로 선을 그립니다.
그러나 x 또는 y 좌표를 계속적으로 변경할 필요가 있을경우는
List의 방법이 훨씬 쉽습니다.
그 예입니다. x와 y좌표를 바꾸어 가면서 반지름 1인 원을 10개 작성합니다.

(Defun c:test1()  
     (setq x 1) ; x의 초기값을 1로 설정 (x좌표로 사용목적)
     (setq y 1) ; y의 초기값을 1로 설정 (y좌표로 사용목적)
    
     (repeat 10    ; 10번을 반복합니다.
         (command "circle" (list x y) "1")   ; x,y좌표에 반지름 1인원을 작성
         (setq x (1+ x))                   ; x값을 1증가
         (setq y (1+ y))                   ; y값을 1증가
     )  
(princ))

만약 z 좌표를 사용하고 싶으면
(list 100 100 50) 처럼 세번째에 z좌표(여기선 50)을 써주면 됩니다.

2. 리스트의 형태

리스트는 좌표를 만들땐 숫자를 사용하지만, 다른 용도로 사용하고 싶으면
문자도 가능하고 리스트안에 리스트를 포함시킬 수도 있습니다.
리스트의 포함된 요소의 갯수는 정해진것이 없습니다.
아래 예를 보고 리스트에 대해 익혀봅시다.

☞ 좌표처럼 숫자만 사용
       (list 1 2 3)   ->   (1 2 3)
☞ 문자를 사용하여 리스트 생성
       (list "a" "bb" "ccc")   ->   ("a" "bb" "ccc")
☞ 숫자와 문자를 혼용
       (list "a" 123 "ccc" 44)   ->   ("a" 123 "ccc" 44)
☞ 리스트 안에 리스트 생성
       (list "a" (1 2) 3 (1 2 3))   ->   ("a" (1 2) 3 (1 2 3))
☞ 갯수제한이 없습니다.
       (list 1)   ->   (1)
       (list 1 2)  ->   (1 2)
       (list 1 2 3)  ->   (1 2 3)
       (list 1 2 3 4)  ->   (1 2 3 4)
       (list 1 2 3 4 5)  ->   (1 2 3 4 5

------ 리습강의 (10) ------

▶ LIST의 요소를 분리해보자 ◀

리스트 ()안의 요소들을 따로 분리해 봅시다.
즉, (x y z)의 좌표값중에서 x, y, z값을 축출하여 리습에 적용하는거죠

(car ) 의 첫 번째 요소를 구한다.
(cdr ) 의 첫 번째 요소를 제외한 모든 요소를 구한다.
(cadr ) 의 두 번째 요소를 구한다.

1. (car ) 함수    : X좌표만을 구할때 주로사용

(car)은 리스트의 첫번째 값을 취할 수 있습니다.
예로 (1 2 3)이라는 리스트가 있다면
(car '(1 2 3)) 의 결과값은 1 입니다.
작은따움표(')는 괄호()앞에 쓰이며
괄호()는 명령어를 의미하지만 작은따움표를 써주면 리스트로 인식합니다.
예를 하나 더 들어보죠

(defun c:test1()
      (setq a (list "aa" "bb" "cc"))
      (setq b (car a))


위의 예제는 a = ("aa" "bb" "cc") 를 의미하고
b = "aa" 를 의미합니다.

2. (cdr ) 함수

(cdr)은 리스트의 첫번째 요소를 제외한 전체 리스트값을 축출합니다.
예로 (1 2 3 4 5)라는 리스트가 있다면
(cdr '(1 2 3 4 5))의 결과값은 (2 3 4 5) 입니다.
첫번째 리스트인 1이 빠지고 두번째 이후의 값을 가져옵니다.

3. (cadr ) 함수    : Y좌표만을 구할때 주로 사용

(cadr)은 두번째 요소를 취합니다.
사실 두번째라고 말하는것보다 (cdr) + (car) 함수의 중복입니다.
예를 들어보겠습니다.

<예제1>
     (defun c:test2()
         (setq a (list 1 2 3))
         (setq c (cadr a))     ;(cadr) 두번째 요소 선택
     )

<예제2>
    (defun c:test3()
        (setq a (list 1 2 3))    
        (setq b (cdr a))       ;(cdr a)의 결과는 (2 3) 입니다.
        (setq c (car b))       ;(car '(2 3))의 결과는 2입니다.
    )

<예제3>
    (defun c:test4()
        (setq a (list 1 2 3))
        (setq c (car (cdr a)))   ;(cdr)을 먼저수행하고 (car)수행
    )

  위의 예제는 모두 c 값이 2인 같은 결과를 나타냅니다.
  저의 의도는 cadr이 cdr 과 car의 합성을 뜻한다는겁니다.

4. (car)과 (cdr)의 합성

① (caddr )   : Z 값을 구할때 주로 사용

    (caddr '(1 2 3))  ; 결과값은 3

    위의 예제는 (cdr)+(cdr)+(car)의 복합니다.
    (caddr)에서 d의 갯수가 1개이면 2번째 요소값
    d의 갯수가 2개이면 3번째 요소값
    그럼 (cadddr)처럼 d의 갯수가 3개이면 4번째 요소값이 되겠죠?

② (cadddr )    : 4번째의 요소선택

    (cadddr '(1 2 3 4 5))   ;결과값은 당연히 4
   
    이제 여러분이 조합을 잘 해보세요..생각도 잘 해보시구요.

5. 복합예제

<예제1> x←1, y←2, z←(x+y)값을 넣어서 좌표(xyz)에 반지름 1인 원을 그리는 리습
     (defun c:test5()
         (setq x 1)
         (setq y 2)
         (setq z (+ x y))           
         (setq xyz (list x y z))     ;좌표값으로 형성
         (command "circle" xyz "1")  ;반지름 1인 원을 작성
     )

<예제2> 한점을 캐드에서 입력받아서 x,y,z 의 값을 취하는 리습
     (defun c:test6()
         (setq pt (getpoint "점을 하나 선택하시죠? "))
         (setq x (car pt))
         (setq y (cadr pt))
         (setq z (caddr pt))
     )
 


명령의 수행을 반복해보자

(repeat 정수 ....)
(while 조건문 ...)

똑같은 명령을 반복하고자 할때 사용한다.
여기서는 (repeat)문만 설명하겠다. (while)문은 뒤에 조건문과 함께 설명하겠다.
반복문을 뒤에 설명하려 했으나 여기서 설명하는 이유는
이 명령을 이해하고 나면 아래의 "칸과 열을 자동으로 만드는 리습"의
명령들을 모두 설명하는 것이기 때문이다.

1. (repeat)의 설명

  (repeat <정수 또는 정수의 값을 가지는 변수>
     <명령문 1>
     <명령문 2>
     <명령문 3>
  )

  위의 '(repeat 정수' 에서 정수는 꼭 1,2,3,4... 같은 정수만 써야한다.
  실수는 물론 안되지만 1.0, 2.0, 3.0 과 같이 소숫점이 붙은 정수같은
  숫자들도 물론 안된다.
  지금은 소숫점을 숫자로 써놓아서 당연히 이해하겠지만
  정수자리에 변수가 들어가면 변수가 꼭 정수값인지 확인해야 한다.
 
2. 바로 예제로 들어가 보자

  아래의 예제는 n 값을 초기값인 1로 설정하고
  10번을 반복하면서 1씩 더해간다.
  결과값인 'n'은 '11'이 된다.

  (defun c:test1()
      (setq n 1)           ; 초기값 n ← 1 로 설정한다.
      (repeat 10           ; 10번을 반복한다.
          (setq n (1+ n))  ; n ← n+1
      )                    ; End of repeat
  )                        ; End of Defun

3. 지금까지의 배운 명령어를 바탕으로 10개의 원을 그리는 리습을
만들어 보자.
x좌표를 2만큼이 증가하면서 반지름 3인 원을 10개 그리는 예제이다.

(defun c:test2()
      (setq x 0 y 0 z 0)    ; 각각 x=0, y=0, z=0으로 설정
      (setq n 10)           ; n(반복횟수)=10회로 설정
      (repeat n
          (setq pt (list x y z))
          (command "circle" pt "3")    ; 반지름이 3인 원을 pt 즉 (x y z)에 그린다.
          (setq x (+ 2 x))    ; x좌표값에 2만큼을 더한다.
      )
(princ))
 
캐드의 화면에서 성분(?)을 선택해보자. 성분은 객체라고 해석하는 것이 요즘 트렌드에 맞습니다.

line, circle, recangle, text 등등 이런것은 객체의 개념이죠. 

캐드의 구성성분(라인,원,글자등등...이제부터는 'entity' 라고 하자.)을 선택하여 처리하는 방법에 대해서 알아보죠.

(ssget)
(entsel)

1. (ssget)

  캐드의 객체를 선택하라는 명령이다.

  우선 캐드의 text창에서 (ssget) 이라고 타이핑 해보자.
  그러면 'Selete Object : '라고 선택하라고 나온다.
  선택하고 나면 그 결과값도 텍스트창에 출력된다.

2. (ssget) 적용예제

  객체를 선택하여서 색을 Green 으로 바꾸어 보자.
 
  (defun c:test1()
      (prompt "\n녹색으로 바꿀 객체를 선택하시오. ")  ; 화면에 메세지 표시
      (setq ent (ssget))    ; 객체를 선택하여 ent 라는 변수에 담아 둠
      (command "change" ent "" "p" "c" "green" "")
          ; change 라는 모두다 아는 명령으로 ent의 색을 변화하는 부분
          ; ent 위에 "" 는 객체를 선택후 엔터를 입력해야 선택을 종료하므로 표시를 꼭 해줘야 하고,
          ; "green" 뒤의 ""를 삽입해야 change 명령을 종료한다.
          ; 위의 "" 두 군데를 한번씩 삭제해 보면서 에러나는 모습을 확인하기 바란다.
  (princ))

3. (entsel)

  (ssget)는 여러개를 선택할 수 있는것과는 달리 entity 딱 한개만 선택할 수 있다.
  이때, 선택한 entity와 선택한 점의 좌표를 돌려 받을 수 있다.

  이것도 마찬가지로 캐드화면에서 그냥 (entsel) 이라고 타이핑해보자
  'Select object: ' 라는 메세지에서 entity 하나를 선택하면
  아래와 비슷한 글자가 나온다.

  ( (132552.0 411316.0 0.0))

  이것도 ()안에 묶여 있고 LIST형태이다.
   이것은 내가 선택한 entity 이름이고,
  (132552.0 411316.0 0.0)) 이것은 선택한 점의 좌표이다.

4. 예제를 통해 알아보자.

<예제1> 이번에도 한개의 entity를 선택해서 색을 빨강으로 바꾸어 보자.

  (defun c:test2()
      (setq ent (entsel))
      (command "change" ent "" "p" "c" "red" "")
  (princ))

<예제2> 이번엔 선택한 entity를 빨강으로 변경하고 선택한 위치에 반지름 10인
        원을 하나 그려보자.

  (defun c:test2()
      (setq ent (entsel))
      (command "change" ent "" "p" "c" "red" "")
      (command "circle" (cadr ent) "10")
  (princ))

  위에서 ( (132552.0 411316.0 0.0)) 도 리스트이므로,
  두번째 좌표를 얻으려면 앞에서 강의했던 것과 같이
  (car) 명령을 사용하면 첫번째 리스트 요소를
  (cadr) 명령을 사용하면 두번째 리스트 요소 (즉, 좌표)를 얻을 수 있다.

 

리습의 조건문은 어떤 것이 있을까?

조건판단하는 명령어를 설명한다.

   (if (조건) (실행문1)
                 (실행문2)
   )

1. (if) 명령문
     (조건) 이 참이면 (실행문1)을 수행하고 거짓이면 (실행문2)을 수행한다.
     (실행문2)는 생략될 수 있다.
     엑셀의 if 문과 유사하고, 베이직 및 다른 언어의 조건문과도 비슷하다.

2. (조건) 이란?
   (조건)은 판단문이다. 즉 a=b , a>b , a<b , a<>b 등과 같다.
   여기서 주의할점, 리습에서는 연산과 마찬가지로 조건판단문도
   부호가 선행되고 비교요소가 뒤에 나열된다.
   예를 보면 쉽다.
   좌측은 일반적으로 쓰는 기호이고 우측은 리습에서 사용되는 조건문이다.
   a=b   →   (= a b)    a와 b가 같다
   a>b   →   (> a b)    a가 b보다 크다
   a<b   →   (< a b)    a가 b보다 작다
   a<>b  →   (/= a b)   a와 b가 다르다 (이것이 약간 다른 언어랑 다르다)
   a>=b  →   (>= a b)   a가 b보다 크거나 같다
   a<=b  →   (>= a b)   a가 b보다 작거나 같다

   <예제 1> 캐드의 TEXT창에서 다음과 같이 타이핑해보자.

       (= 1 1)

       결과값은 'T' 일것이다. 참이라는 뜻이다.

   <예제 2> 캐드의 TEXT창에서 다음과 같이 타이핑해보자.

       (> 1 2)

       결과값은 'nil' 일것이다. '거짓'이라는 뜻이다.
       "F"로 나오지않고 'nil'로 나오는것에 유의하자.

3. if문의 예제를 한번 보자.

   (defun c:test1()
      (setq a 1                 ;a=1
               b 2                 ;b=2
      )
      (if (> a b) (setq c 3)    ;a>b 인지 판단하여 참이면 c=3
                     (setq c 4)    ;아니면 c=4
      )
    )

    위를 실행시켜보면 a>b 는 거짓이므로 c의 값은 당연히 4이다.
    if문을 위에처럼 참일경우와 거짓일 경우를 두줄로 나누어 쓰면
    보기에 편리하다. 위의 (if~)문을 한줄로 써보겠다.

    (if (> a b) (setq c 3) (setq c 4))

    위와 같이 써도 좋다. 하지만 지금은 단순구문이라 알아보지만
    복잡한 실행문이 들어가면 어려우므로 구분지어서 코딩하는 연습을 해두자.

4. 좀더 유용한 예제를 해보자

    숫자 두개를 받아들여서 두번째 받아들인 숫자가 '0'이 아니면
    첫번째 숫자를 두번째 숫자로 나누는 리습이다.

    (defun c:test3()
        (setq num1 (getreal "첫번째 숫자를 입력하시오 : ")  ;첫번째 실수 입력받음
                 num2 (getreal "두번째 숫자를 입력하시오 : ")  ;두번째 실수 입력받음
        )
        (if (/= num2 0) (setq num3 (/ num1 num2))    ;두번째숫자가 '0'이 아니면 나누기
                              (prompt "0으로 나눌수 없습니다.") ;'0'이면 메세지 출력
        )
    (princ))
 

▶ 조건판단문(2) ◀

(if~)문에 대해서 알아보았다. 그 두번째 강의로서 (progn~)에 대해서 알아보자.

1. (progn~)
   (progn~)은  (if~)문과 함께 쓰이며 명령어들을 그룹화하여
   묶어 주는 역할을 한다.

2. 왜 (progn)으로 묶어 주어야 하는가?

   (if 조건 (실행문1)
            (실행문2)
   )

   여기서 (실행문1)과 (실행문2)는 앞선 강의에서 하나의 괄호()안에
   묶여 있었다. 그러나 하나의 명령어뿐만 아니라 여러개를 작성할때
   (progn)으로 묶어 주지 않으면 참일때 실행하라는 것인지
   거짓일때 실행하라는 것인지 판단을 리습에서는 자동으로 하지 못한다.

3. 다음의 예제에서 틀린점을 찾아보자

   우리는 a<b 판단이 참인경우 c=3, d=4 로 만들어 주고
   거짓이면 e=5, f=6 으로 해주어 보자.

   <예제1>

   (defun c:test1()
       (setq a 1)                ; a=1
       (setq b 2)                ; b=2
       (if (< a b) (setq c 3)    ; 참이면 c=3
                   (setq d 4)    ; 거짓이면 d=4
                   (setq e 5)    ; 참과 거짓을 다 판단했는데 다시 ()가 나와서 에러
                   (setq f 6)    ; 물론 에러
       )
   )

   <예제2>

   (defun c:test2()
       (setq a 1)               ; a=1
       (setq b 2)               ; b=2
       (if (< a b)              ; a<b 인가? 판단. 당연히 참(1<2)
           (progn               ; 참이면 (progn)으로 묶인 구문 실행
                (setq c 3)      ; 참일때 실행 c=3
                (setq d 4)      ; 참일때 실행 d=4
           )
           (progn               ; 거짓일때 (progn)으로 묶인 구문 실행
                (setq e 5)      ; 거짓일때 e=5
                (setq f 6)      ; 거짓일때 f=6
           )
       )
   )
   위의 예제에서 <예제1>은 에러가 난다.
   왜냐하면 (if)문은 두개의 괄호()만을 받아들여서 참과 거짓일때
   각각 실행하는데 <예제1>은 (if)문 안에 괄호가 4개나 있다.
   그러기 때문에 <예제2>와 같이 (progn)으로 그룹으로 만들어서 묶어주면
   (if)문은 (progn)으로 묶인 모든 명령을 참일때 또는 거짓일때 실행한다.
   좀 말이 어려웠다. 아래의 예제를 보면서 다시 이해해 보자.

4. 예제

   두개의 숫자를 입력받아서 a >= b 이면 c = a - b , d = "[a > b]"를
   a <= b 이면 c = b - a , d = "[a < b]" 를 출력하는 리습을 만들어 보자.
   (defun c:test3()
       (setq a (getreal "\n1st Number :"))  ; \n한줄넘기기 기호
       (setq b (getreal "\n2nd Number :"))
       (if (>= a b)
              (progn    ; 참일때 실행하는 그룹
                  (prompt "a - b = ")
                  (setq c (- a b))
                  (setq d " [a > b]")
                  (princ c)
                  (prompt d)
              )    ; end of 참 progn
              (progn    ; 거짓일때 실행하는 그룹
                  (prompt "b - a = ")
                  (setq c (- b a))
                  (setq d " [a < b]")
                  (princ c)
                  (prompt d)
              )    ; end of 거짓 progn
       )    ; end of if
   (princ))

5. 조건이 참일때만 실행하고 거짓일때는 다음 구문으로 보낼때

  (if)문에서 거짓일때의 실행구문을 생략할수 있다.
  아래와 같이 거짓일때 실행할문이 없다면 그냥 (if)의 괄호를 닫아버리자.

   (if 조건문
       (progn
           (참실행문 1)
           (참실행문 2)
           (참실행문 3)
       )
   )

   <예제1> 입력한 숫자가 10보다 클때만 텍스트 창에 "O.K." 와
           "에러가 없습니다" 글 보내기

   (defun c:test4()
       (setq a (getreal "숫자를 입력하시오 " ))
       (if (> a 10)
              (progn
                 (prompt "\nO.K")     ; \n은 한줄넘기기 기호
                 (prompt "\n에러가 없습니다")
              )
       )
    (princ))

리습의 또다른 조건판단문 (cond) condition의 약자겠죠?

if문은 다 해보았다. 여기서는 if문과 비슷하지만 방법이 좀 다른
(cond ~) 문에 대해서 알아보자.
(cond ~)문은 조건이 여러가지 있을경우에 사용하면 좋다.
(if~)문의 연속이라고 보아도 좋다.

예제를 보면서 익혀보겠다. (cond 다음의 괄호갯수를 유념하자.

1. (cond~)의 예제 (다른언어의 select case 또는 switch case와 유사하다.)

  아래의 예제는 1~5 사이의 숫자를 입력받아서 받은 숫자를 다시 "a="와
  함께 입력받은 숫자를 표시하고 1~5 밖의 숫자면 "Out of Range." 라고
  표시하는 리습이다.

(defun c:test1()
  (setq a (getint "input number (1~5) : "))
  (cond ((= a 1) (prompt "a=1"))    ;조건1 (a=1)일경우만 수행
        ((= a 2) (prompt "a=2"))    ;조건2 (a=2)일경우만 수행
        ((= a 3) (prompt "a=3"))    ;조건3 (a=3)일경우만 수행
        ((= a 4) (prompt "a=4"))    ;조건4 (a=4)일경우만 수행
        ((= a 5) (prompt "a=5"))    ;조건5 (a=5)일경우만 수행
        (prompt "Out of range.")
  )
(princ))

2. 위의 1번 예제를 (if~)문으로 구현해 보겠다. (같은 의미이다.)

(defun c:test2()
  (setq a (getint "input number (1~5) : "))
  (if (= a 1) (prompt "a=1"))    ;조건1 (a=1)일경우
  (if (= a 2) (prompt "a=2"))    ;조건2 (a=2)일경우
  (if (= a 3) (prompt "a=3"))    ;조건2 (a=3)일경우
  (if (= a 4) (prompt "a=4"))    ;조건2 (a=4)일경우
  (if (= a 5) (prompt "a=5"))    ;조건2 (a=5)일경우
  (if (or (< a 1) (> a 5))
        (prompt "Out of range.")
  )
(princ))


3. 다중 (if~)문으로도 사용할 수 있다.
  위의 예제와 비슷하지만, 위의 예제는 a 값에 따라 각각 한 줄씩
  모두 체크한다.
  하지만 아래의 예제는 거짓일때만 다음줄로 순서가 넘어가며
  참이면 결과값을 출력하고 (if)문을 그대로 빠져나간다.

(defun c:test3()
  (setq a (getint "input number (1~5) : "))
  (if (= a 1) (prompt "a=1")    ; a=1 일때만 수행하고 (if)종결
      (if (= a 2) (prompt "a=2")    ; a=1 이 아니면 수행
           (if (= a 3) (prompt "a=3")    ; a=1 도 a=2도 아니면 수행
               (if (= a 4) (prompt "a=4")    ; a=3 도 아니면 수행
                   (if (= a 5) (prompt "a=5")      ; a=4도 아니면 수행
                               (prompt "Out of Range")  ; a=5도 아니면 수행
                   )
               )
           )
       )
  )
(princ))

리습의 반복문 (While)

1. (while)문이란?

   (while (조건)
      (실행문1)
      (실행문2)
      (실행문3)
      .........
   )

   조건이 참이면 이하 실행문을 실행한다.
   달리 말해서 조건이 거짓(nil)이면 (while)문을 종료(탈출)한다.

2. 예제1

  1부터 100까지 더하는 리습을 한번 구현해 보겠다.

   (defun c:test1()
       (setq sum 0)   ; sum 변수는 합계를 의미하는 변수, 0으로 초기화
       (setq a 1)     ; 더해질 숫자 a 를 0 으로 초기화

       (while (< a 101)    ; a가 100보다 작으면 실행문(더하기)을 실행
            (setq sum (+ sum a))    ; 현재의 합에 a 값을 더함
            (setq a (1+ a))        ; 현재의 a 값에 1 더함
       )

       (prompt "\nSum=")
       (princ sum)
   (princ))

3. 예제2

  위의 예제1를 (repeat)함수로 한번 구현해 보겠다

   (defun c:test2()
       (setq sum 0)
       (setq a 1)

       (repeat 100
           (setq sum (+ sum a))
           (setq a (+ 1 a))
       )

       (prompt "\nSum=")
       (princ sum)
   (princ))
 
3. 예제3

   사용자가 숫자입력을 하도록 해보자.
   대신에 사용자가 숫자입력을 하지 않고 엔터를 누르면
   계속적으로 숫자를 입력하라고 요구해보자.

   (defun c:test3()
       (setq a nil)    ; a값을 초기값을 nil로 한다.
       (while (= a nil)  ;a값이 nil이면 계속 input 요청
           (setq a (getreal "Input Number : "))
       )
   )

   위에서 아무 입력없이 엔터나 스페이스를 누르면 nil값을 반환한다.
   그걸 이용한것이다.

리습을 이용하면 변수값은 어떤 변화가 있을까?

리습화일을 만들고 실행하면서 생성되는 변수는 어떤 과정으로 처리될까?

변수는 크게 임시 변수, 영구변수로 나뉩니다.

예를 들어 보면, 쉽게 이해가 됩니다. 명령창에 이렇게 입력해 보세요.
   (setq a 1)

위에서 많이 본 setq 명령을 이용해서 a라는 변수에 '1'을 넣는다는 의미죠.

이렇게 입력하게 되면 a=1 값을 가지고 기억하고 있고, 이를 바로 알 수 있는 방법이 
입력창에    !a  입력 후 엔터를 누르면
'1' 결과값이 나올 것입니다.

'!' 는 결국 화면에 출력하라는 의미겠죠?

예를 몇가지 들어보죠.
   <예제1>
       (setq b "TEST STRING")  ; b="TEST STRING"
       !b                      ; b값을 보여줘라.
       "TEST STRING"           ; b값을 보여준다.
   <예제2>
       (setq c (ssget))        ; 캐드화면에서 성분을 선택한다.
       !c                             ;   c값을 보여준다.
       <Selection set: 1>      ; 선택된 그룹번호를 알려준다.
                                          ; 뒤의 숫자는 사용자마다 다를수 있다.

리습 변수의 메모리상 처리과정

   (defun c:test1(/ e f g)
     (setq e 1 f 2 g 3)
   )
   위의 test1 뒤 (/ e f g) 에서 e f g 는 각각 변수 이름이고,   '/'기호는 임시변수라는 뜻이다.
   '/ e f g'는 리습명령이 종료됨과 동시에 메모리에서 사라진다. '/'가 없다면 계속 그 변수값이 메모리에 상주한다는 의미입니다.

   위의 리습을 실행시킨후 명령어창에 이렇게 입력해 보면 그 이유를 알 수 있다.
   !e
   !f
   !g  라고 캐드 텍스트창에 타이핑해보면 결과값이 각각 nil 일것이다.

   아래의 두가지 예를 비교하겠다.

   (setq c:test2(/ tt) (setq tt 10) )   ;..........예제1
   (setq c:test3()     (setq rr 20) )   ;..........에제2

첫번째는 실행하고 나면 tt 값이 nil(거짓)이 됩니다.
두번째는 실행하고 나서도 rr 값을 20으로 유지됨을 알 수 있습니다.

꿀팁) 리습을 완성하기 전까지는 영구변수로 사용하여,  중간중간 변수값이나 에러부분을 체크하는 것이 좋으며,  리습이 완성되면 임시변수값으로 만들어 주어 혹시 있을 리습의 변수 충돌을 방지하고,  메모리를 확보 차원에서도 좋습니다.
 영구 변수로 만들어 주면 메모리를 그 만큼 차지하지만 영구변수로 처리하여 상호 변수값을 참조할 경우에는 어쩔수 없이 영구변수로 해야함을 기억하면 됩니다.

리습의 문자관련 함수 (Ascii 문자활용, 문자대소문자, 나열, 문자분할 등)

(ascii <문자>)   <문자>의 ASCII 문자 CODE를 응답한다.
(chr <정수>)    <정수>를 해당 ASCII문자를 응답한다.
(atof <문자>)    <문자>를 실수로 변환한다.
(atoi <문자>)    <문자>을 정수로 변환한다.
(itoa <정수>)    정수를 문자로 변환한다.
(rtos <숫자> [<모드> <소숫자리>])  숫자를 문자로 변환한다.
(strcase <문자> [<t>])    <string>을 대문자 또는 소문자로 응답한다.
(strcat <문자1> <문자2> ...)    나열된 <문자1>, <문자2> ...을 연결하여 응답한다.
(strlen <문자>)    <문자>의 글자수를 구한다.
(substr <문자> <시작위치> [<길이>])    <문자>를 <시작위치>부터 <길이>수 만큼 응답한다.

1. (ascii 문자) 와 (chr 정수)

   'ascii' 란 무엇인가?
   'ascii' 는 "!,@,#...a,b,c...A,B,C" 등과 같은 문자 또는 특수문자의
   고유한 번호이다. 컴퓨터는 문자로 인식하지 않고 이 고유의 번호로
   처리하므로 ascii code 를 알아두면 편리하게 사용될 수 있다.
   (chr 정수)와 상반되는 개념이다.

   (ascii "A") 라고 캐드화면에 타이핑해보자.
   97 이란 답이 나올것이다.
   "A"의 ascii code 값은 97번이다.
   전체 문자의 ascii code 를 알고 싶으면 캐드도움말의 ascii code를 확인하라.

   (chr 97) 이라고 캐드화면에 타이핑해보자.
   "A" 라고 답이 나올것이다.

   즉 (ascii "A") -> 97 , (chr 97) -> "A" 서로 상반되는 내용이다.

2. 예제

   왜 이런 명령이 필요한지 예제를 통해 알아보자.

   한글자를 입력받아서 숫자인지 확인하여 숫자이면 숫자를
   문자이면 "Not Number" 라는 메세지를 출력해보자.
   (입력메세지에 꼭 한글자만 치고 엔터를 해야한다.)

   (defun c:test1(/ number)
     (Setq number (getstring "Input String : "))
     (if (and (>= (ascii number) 48) (<= (ascii number) 57))
          (progn
              (prompt "\nO.K. Number = ")
              (prompt number)
          )
          (prompt "Not Number")
     )
   (princ))

   위에서 숫자의 ascii code 는 48~57 사이이다. 이 사이를 벗어나면
   문자로 판단하는 것이다.
   ascii code를 사용하면 소문자를 대문자로 아니면 대문자를 소문자로
   변환한다던가 첫자가 대문자로 하고 나머지는 소문자로...
   이런것들의 처리가 가능해진다. (ascii 문자) 와 (chr 숫자) 명령의 조합으로....
 
(defun c:trans(/ str)
(setq str (getstring "input string : "))

(if (and (>= (ascii str) 97) (<= (ascii str) 122))
(setq str (- (ascii str) 32))
(setq str (+ (ascii str) 32))
)
(princ (chr str))
(princ))


리습의 문자관련 함수 (실수변환, 정수변환, 숫자->문자 등)

(atof <문자>)    <문자>를 실수로 변환한다.
(atoi <문자>)    <문자>을 정수로 변환한다.
(itoa <정수>)    정수를 문자로 변환한다.
(rtos <숫자> [(모드) (소수점자리)] 숫자를 문자로 변환한다.

1. (atof)   ascii to float 의 약자로 추정

   이 함수는 숫자로 구성된 문자를 실수로 변환하는 함수다.
   그 예제를 보자.
   리습화일을 만들기 전에 캐드 텍스트 화면에서 아래를 따라해 보자.

   (atof "123.456")

   그 결과값은 123.456 이다.

   (defun c:test1(/ var1 var2)
        (setq var1 "100.234")    ; var1 은 "100.234"인 문자이다.
        (setq var2 (atof var1))  ; var2 는 연산이 가능한 숫자 100.234 이다.
   )

2. (atoi) ascii to integer 이런 약자 같음.

   이 함수는 숫자로 구성된 문자를 무조건 정수로 바꾸는 함수다.
   소숫점 이하는 반올림 되지않고 그냥 버림이 되는걸 유의하자..
  
   (atoi "123.987")

   이 결과값은 123 이다.  버림이 된다는 것을 주의

3. (itoa)  integer to ascii 이런 약자 같다.

   이 함수는 정수를 문자로 바꾸는 함수다. (atoi)와 상반되는 함수다

   (itoa 123)

   이 결과값은 "123" 인 문자값이다.

4. (rtos)

   이 함수는 숫자를 문자로 변환하여 주는 함수이다.
   (itoa)는 정수만을 문자로 변환하여 주지만, 이 함수는 실수형태로
   다양하게 변환하여 준다.

   (rtos <숫자> <모드> <소숫점자리>) 에서

       <모드>는 아래와 같이 5가지를 적용할수 있다.

        1 Scientific
        2 Decimal
        3 Engineering (feet and decimal inches)
        4 Architectural (feet and fractional inches)
        5 Fractional

        그러나 우리는 십진수에 익숙하기 때문에 2번(decimal)을 주로 사용한다.

    (rots 24.4568 2 3) 라고 타이핑해보자.
    그러면 결과값은 "24.457"인 문자값으로 반올림되어 표시된다.
    아래에 소수점 자리수를 바꾸어 가면서 예제를 더 보여주겠다.

    (rtos 12.345678)       결과값 : "12.3456" (사용자에 따라 다름)
                           -> 현재 설정되어 있는 units에 따라 표시
    (rtos 12.345678 2)     결과값 : "12.3456" (사용자에 따라 다름)
                           -> 십진수(Decimal)로 표현하고 소숫점은 units에서 설정한 값을 따라감
    (rtos 12.345678 2 0)   결과값 : "12"
                           -> 소숫점 이하 표시안함

    (rtos 12.345678 2 1)   결과값 : "12.3"
                           -> 소숫점 이하 첫째짜리 까지 표시
    (rtos 12.345678 2 2)   결과값 : "12.35"
                           -> 소숫점 이하 둘째짜리 까지 표시
    (rtos 12.345678 2 3)   결과값 : "12.346"
                           -> 소숫점 이하 셋째짜리 까지 표시
    ........

    !주의사항!
    dim 명령중에 dimzin 이 있다. 만약 이것이 8 로 되어 있다면, 소숫점 이하의 결과값이 0 이면 소수점 이하 자리수는 표시되지 않는다.  원하는 소숫점 자리수를 표시하고 싶다면


    (setvar "dimzin" 0)

    이것을 꼭 리습 앞쪽에 기재해야 한다.
    기재했다가 원래대로 돌리는 것은 여러분들은 모두 다 할줄 알것이다.
    모른다면 앞에 강의를 읽어보기 바란다.

리습의  문자관련 함수 다루기 (대소문자 변환, 나열, 글자수 계산)

(strcase <문자> [<t>])    <string>을 대문자 또는 소문자로 응답한다.
(strcat <문자1> <문자2> ...)    나열된 <문자1>, <문자2> ...을 연결하여 응답한다.
(strlen <문자>)    <문자>의 글자수를 구한다.

1. 문자열 대소문자 (strcase) string uppercase, lowercase 의미

   문자를 대문자로 또는 소문자로 바꾸어 줍니다.

   (strcase "teST")    결과값 : TEST
   (strcase "teST" T)  결과값 : test

   뒤의 옵션인 T를 써주면 소문자로 없으면 대문자로 해줍니다.
   "teST" 대신에 문자변수로 해주어도 좋겠죠

   (defun c:test1(/ a b)
      (setq a "TesdfER")
      (setq b (strcase a))
   )

2. 문자열 나열해서 붙이기 (strcat) string catenation (문자연결)

   문자를 서로 붙여줍니다.
   !주의사항!으로는 숫자와 문자를 붙이려면 에러가 납니다.
   숫자의 형태는 꼭 문자형태로 (rtos)등으로 변환하셔야 합니다.

   (defun c:test2(/ a b c d e)
       (setq a "I am")
       (setq b "a boy")
       (setq c 1054235)            ;c 값은 숫자인 형태
       (setq d (rtos c 2 0))       ;숫자를 문자로 변환
       (setq e (strcat a b d))     ;a+b+d로 합침
   )

   위의 e값은 "I am a boy 1054235" 이다.
   (strcat <문자1> <문자2> ....)의 <문자1> <문자2> 등과 같이
   문자의 갯수는 상관없이 붙여준다.

3. 문자열 길이 산출 (strlen)

   문자의 갯수를 [정수]로 반환한다.

   (strlen "asdfg")
   결과값은 5이다. 
   이 함수의 적용예를 보자.

   (defun c:test3(/ str n c)
       (setq str (getstring "Input String : "))   ; 문자를 입력받는다.
       (setq n (strlen str))         ; 문자수를 n으로 정의
       (repeat n                  ; 문자의 갯수만큼 * 표시
          (prompt "*")
       )
       (prompt "---- string length = ")  
       (princ n)          ; 화면에 문자의 갯수 표시
   (princ)     ; 이 표시를 안해주면 갯수가 두번 찍힐 것이다.
   )

리습의 중요한 부분을 계속해서 다뤄보고 싶습니다.

반응형
댓글