달수 ▷ ActiveX 처음 시작하기전에 읽어보세요

Auto CAD/lisp|2019. 4. 5. 17:37

하루님이 드디어 VLISP를 시작하시는군요..
제가 ActiveX에 대해 궁금할때 리습과 ActiveX의 연관관계를 설명해준 글을 찾았고 서적도 찾아봤지만 만족할만하게 없었습니다.
따라서 노가다식으로 하나씩 공부했습니다. 물론 중간에 캐도리님의 도움을 받았기도 했구요..

짧은 지식이지만 ActiveX에 입문하시는분에게 약간의 길잡이가 되었으면 합니다.
물론 제가 여기에 설명하는 글이 정답은 아닙니다. 참고만 하세요..


ActiveX는 함수 익히는것보다..
개념을 먼저 알고나면 나머지는 현재 알고 있는 리습 지식으로도 충분히 헤쳐나갈수 있습니다.

ActiveX는 응용프로그램간의 Object를 삽입하는 기술이라고 합니다.


캐드에서 VBA 도움말을 보면 설명도 잘 나와있고 예제도 많이 있습니다.

따라서 함수공부는 VBA도움말을 많이 활용하시고 저는 개념에 대해 접근하려고 합니다.
일단 아래 그림을 보고 시작해보겠습니다.

 

위 그림을 보면 캐드의 지도라고 생각하시면 됩니다.
우리는 저 지도를 보고 원하는 지점까지 가서 무언가를 만들수도 있고 조회도 하고 변경도 줄수 있습니다.

 

윈도우에서 보면 캐드는 하나의 객체입니다. 엑셀도 객체고..모든 것을 객체라고 생각하심 편합니다.
또한 캐드의 모든 요소가 다 객체라고 생각하세요..

 

나중에 함수 공부할적에 VBA를 보고 공부를 해야 하기 때문에 VBA와 LISP의 차이점 부터 설명합니다.

 

CAD에서 VBA로 라인을 하나 그리려면

Thisdrawing.Modelspace.addLine(StartPoint, EndPoint) <= 해석하면

Thisdrawing 이 도면에서      <= Object 1
Modelspace 모델공간에       <= Object 1-1
addLine 라인을 그려라          <= Method 
StartPoint에서 EndPoint로   <= Property

주소를 접근하는데 있어서..좌에서 우로 진행을 하고 각 단계마다 [ . ] 점으로 구분합니다.

 

그럼 이것을 Lisp으로 한다면
(vla-addLine (vla-get-ModelSpace (vla-get-activedocument (vlax-get-acad-object))(vlax-3d-point StartPoint)(vlax-3d-point EndPoint)))

vla-addLine 라인을 그려라
vla-ModelSpace 모형공간에서(객체1-2)
vla-get-activedocument 현재도면에서(객체1-1)
vlax-get-acad-object 캐드에서(객체1)
(vlax-3d-point StartPoint EndPoint) StartPoint에서 EndPoint로

결국 ("라인을그려라" "주소" "시작점 끝점") 
주소라고 표현했지만 주소도 객체입니다.

 

차이점이 느껴지나요?
제가 아는 차이점은

1. 주소를 접근하는 방식입니다.
    VBA는 대한민국 서울시 라인 <= 지도의 큰거부터 시작해서 작은쪽으로 내려가는 반면에
    LISP은 라인 서울시 대한민국 <= 지도의 작은쪽에서 큰쪽으로 접근합니다.

2. 같은주소이면서 라인을 그리는데 VBA와 LISP은 약간의 차이점이 있습니다.
   VBA는 vlax-get-acad-object <= 이 표현이 생략되었고..또한 LISP에서는 vla-addLine <= 이렇게 표현한것에 비해
   VBA는 addLine <= vla가 없이 addLine이라고만 표현되었네요..

   정확히는 모르지만 VBA는 ActiveX함수 자체로 이루어져서 vba를 앞에 붙이지를 않는거 같고...
   또한 캐드안에서 실행되기 때문에   vlax-get-acad-object <= 이 객체를 선언하지 않는거로 알고 있습니다.
   물론 엑셀이나 다른 응용프로그램에서 VBA로 캐드에 라인을 그리려 한다면 생략하면 안되겠져..

 

어찌되었든...지도를 보고 원하는것을 만들수가 있겠져..
LISP에서  (vla-get-ModelSpace (vla-get-activedocument (vlax-get-acad-object))) 이넘을 한번에 사용할때도 있지만 
변수를 이용해서 따로 따로 분류하여 관리 할 수도 있습니다.

 

Circle을 그리는 예를 하나더 들어볼께요..

(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq mSpace  (vla-get-ModelSpace aDoc))

(setq pt (getpoint "\n중심점 : "))
(setq dis (getdist pt "\n반경 : "))
(setq circleObj (vla-addCircle mSpace (vlax-3d-point pt ) dis))

 

AutoCAD Application을 aObj에 저장하고
현재도면을 aDoc에 저장하고
모형공간을 mSpace에 저장하고
원을 mSpace에 그려라

 

여기서 좌표점을 pt로 바로 쓰지 않고 (vlax-3d-point pt)라고 했는데..
ActiveX에서는 좌표점을 배열로 만들어서 사용합니다.
vlax-3d-point함수가 Lisp의 좌표점을 ActiveX에서 인식하는 배열로 바꾸어줍니다. <= 나중에 다시 설명하겠습니다.


그런데 가만히 보니 어떨때는 vl로 쓰여지고 어떨때는 vla로 쓰여지고 어떨때는 vlax 가 쓰여지는데..무슨 차이점이 있을까요?
제가 내린 결론은 이렇습니다. <= 이것또한 정확하지 않습니다.

 

ActiveX를 캐드에서 사용하려면 vlax가 붙어야 하는데
그게 붙지 않은넘중에 vla는 AutoCAD에서 ActiveX를 직접사용할 수 있게 내장된 함수인거 같구요..
vl는 일반LISP의 기능을 보강하여 VisulLISP에서 전용으로 사용할 수 있게 만들어진 함수인거 같아요..
vl로만 사용되어지는 함수는 다른 언어에서는 사용할 수가 없겠져(저의 추정입니다. 맞는지 틀리는지는 정확히 모름)

 

이번에는 vla-get과 vla-put에 대해 알아볼께요..
좀전에 원을 그리고 변수 circleObj에 저장했는데..

circleObj를 확인해보면 
#<VLA-OBJECT IAcadCircle2 00000000260067a8> <= 이런식으로 나오네요..

이 속에 무엇이 있는지 확인해 보겠습니다.


ActiveX에서는 어떤것을 확인할때는 (vlax-dump-object "객체" T) <= dump함수로 알아볼 수가 있습니다.

그럼 편집기에서 (vlax-dump-object circleObj T) 엔터
;IAcadCircle2: AutoCAD Circle Interface
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 0000000140532e28>
;   Area = 383230.0
;   Center = (3019.69 1197.18 0.0)
;   Circumference = 2194.5
;   Diameter = 698.53
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000000025beeb50>
;   EntityTransparency = "ByLayer"
;   Handle (RO) = "217"
;   HasExtensionDictionary (RO) = 0
;   Hyperlinks (RO) = #<VLA-OBJECT IAcadHyperlinks 0000000026186a28>
;   Layer = "0"
;   Linetype = "ByLayer"
;   LinetypeScale = 1.0
;   Lineweight = -1
;   Material = "ByLayer"
;   Normal = (0.0 0.0 1.0)
;   ObjectID (RO) = 42
;   ObjectID32 (RO) = 42
;   ObjectName (RO) = "AcDbCircle"
;   OwnerID (RO) = 43
;   OwnerID32 (RO) = 43
;   PlotStyleName = "ByLayer"
;   Radius = 349.265
;   Thickness = 0.0
;   TrueColor = #<VLA-OBJECT IAcadAcCmColor 0000000026186840>
;   Visible = -1
; Methods supported:
;   ArrayPolar (3)
;   ArrayRectangular (6)
;   Copy ()
;   Delete ()
;   GetBoundingBox (2)
;   GetExtensionDictionary ()
;   GetXData (3)
;   Highlight (1)
;   IntersectWith (2)
;   Mirror (2)
;   Mirror3D (3)
;   Move (2)
;   Offset (1)
;   Rotate (2)
;   Rotate3D (3)
;   ScaleEntity (2)
;   SetXData (2)
;   TransformBy (1)
;   Update ()
T

특성(Property)하고 메소스(Methods)가 나오네요..
면적도 보이고 중심점도 보이고 직경도 보이고 레이어도 보이고...등등...
특성과 메소스에 대한것은 인터넷검색에서 확인해보시면 자세한 설명글들이 있습니다.
여기서는 생략합니다.

 

그럼 그 값들을 변수로 잡아볼께요..
(setq cenPoint (vla-get-Center circleObj)) <= dxf로 잡아올때
(cdr (assoc 10 (entget "객체"))) <= 이거와 같은값입니다.

 

그럼 레이어 잡아올때는 (setq layerName (vla-get-Layer circleObj)) 
가만히 보니 특성에서 vla-get-하고나서 나머지를 타이핑하면 다 변수로 잡아올수가 있네요..

무엇을 가져와라 할때는 vla-get-무엇 <= 간단하져?
그럼 변경을 하려 한다면 vla-put-무엇 <= 이것도 간단하져...


변경시켜볼까요?
(vla-put-layer circleObj "1") <= circleObj 객체의 레이어를 1번으로 변경해라...(레이어 1 이 있다는 가정하에..)

 

반경도 바꾸어 볼까요..
(vla-put-Radius circleObj 400) <= circleObj 객체의 반경을 400으로 바꾸어라...

참고로 특성이름뒤에 (RO) <= 이건 변경못하고 ReadOnly 읽기만 가능한겁니다.

 

현재까지는 지도의 가장 우측편에 있는것을 다루어 봤습니다.
라인을 그려라 (모형공간에서-현재도면에-캐드에서) 시작점 끝점 ;<= 괄호속은 주소이면서 객체입니다.


이번에는 레이어에 대해 알아보겠습니다.
일단 지도를 봐야겠네요..


캐드에서-현재도면에-레이어

(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(vlax-dump-object aDoc t)


; IAcadDocument: An AutoCAD drawing
; Property values:
;   Active (RO) = -1
;   ActiveDimStyle = #<VLA-OBJECT IAcadDimStyle 0000000025fcb228>
;   ActiveLayer = #<VLA-OBJECT IAcadLayer 0000000025fcba98>
;   ActiveLayout = #<VLA-OBJECT IAcadLayout 0000000025fcbbb8>
;   ActiveLinetype = #<VLA-OBJECT IAcadLineType 0000000025fcbc48>
;   ActiveMaterial = #<VLA-OBJECT IAcadMaterial 0000000025fcbcd8>
;   ActivePViewport = AutoCAD: No active viewport in paperspace
;   ActiveSelectionSet (RO) = #<VLA-OBJECT IAcadSelectionSet 0000000026186908>
;   ActiveSpace = 1
;   ActiveTextStyle = #<VLA-OBJECT IAcadTextStyle 0000000025fcbdf8>
;   ActiveUCS = AutoCAD: Null object ID
;   ActiveViewport = #<VLA-OBJECT IAcadViewport 0000000025fcbe88>
;   Application (RO) = #<VLA-OBJECT IAcadApplication 0000000140532e28>
;   Blocks (RO) = #<VLA-OBJECT IAcadBlocks 0000000025fcbf18>
;   Database (RO) = #<VLA-OBJECT IAcadDatabase 0000000026186548>
;   Dictionaries (RO) = #<VLA-OBJECT IAcadDictionaries 0000000025fcbfa8>
;   DimStyles (RO) = #<VLA-OBJECT IAcadDimStyles 0000000025fcc038>
;   ElevationModelSpace = 0.0
;   ElevationPaperSpace = 0.0
;   FileDependencies (RO) = #<VLA-OBJECT IAcadFileDependencies 000000002624f1c8>
;   FullName (RO) = ""
;   Groups (RO) = #<VLA-OBJECT IAcadGroups 0000000025fcc0c8>
;   Height = 917
;   HWND (RO) = 920200
;   HWND32 (RO) = 920200
;   Layers (RO) = #<VLA-OBJECT IAcadLayers 0000000025fcc158>
;   Layouts (RO) = #<VLA-OBJECT IAcadLayouts 0000000025fcc1e8>
;   Limits = (0.0 0.0 420.0 297.0)
;   Linetypes (RO) = #<VLA-OBJECT IAcadLineTypes 0000000025fcc278>
;   Materials (RO) = #<VLA-OBJECT IAcadMaterials 0000000025fcc308>
;   ModelSpace (RO) = #<VLA-OBJECT IAcadModelSpace 0000000025dfbf08>
;   MSpace = AutoCAD: Invalid mode
;   Name (RO) = "Drawing1.dwg"
;   ObjectSnapMode = 0
;   PaperSpace (RO) = #<VLA-OBJECT IAcadPaperSpace 0000000025dfbfa8>
;   Path (RO) = "C:\\Program Files\\Autodesk\\AutoCAD 2011"
;   PickfirstSelectionSet (RO) = #<VLA-OBJECT IAcadSelectionSet 00000000261867e8>
;   Plot (RO) = #<VLA-OBJECT IAcadPlot 000000002624f658>
;   PlotConfigurations (RO) = #<VLA-OBJECT IAcadPlotConfigurations 0000000025fcc398>
;   Preferences (RO) = #<VLA-OBJECT IAcadDatabasePreferences 000000002624f188>
;   ReadOnly (RO) = 0
;   RegisteredApplications (RO) = #<VLA-OBJECT IAcadRegisteredApplications 0000000025fcc428>
;   Saved (RO) = 0
;   SectionManager (RO) = 예외가 발생했습니다
;   SelectionSets (RO) = #<VLA-OBJECT IAcadSelectionSets 0000000025d83948>
;   SummaryInfo (RO) = #<VLA-OBJECT IAcadSummaryInfo 0000000025ed50c8>
;   TextStyles (RO) = #<VLA-OBJECT IAcadTextStyles 0000000025fcc4b8>
;   UserCoordinateSystems (RO) = #<VLA-OBJECT IAcadUCSs 0000000025fcc548>
;   Utility (RO) = #<VLA-OBJECT IAcadUtility 000000002624f688>
;   Viewports (RO) = #<VLA-OBJECT IAcadViewports 0000000025fcc5d8>
;   Views (RO) = #<VLA-OBJECT IAcadViews 0000000025fcc668>
;   Width = 1834
;   WindowState = 3
;   WindowTitle (RO) = "Drawing1.dwg"
; Methods supported:
;   Activate ()
;   AuditInfo (1)
;   Close (2)
;   CopyObjects (3)
;   EndUndoMark ()
;   Export (3)
;   GetVariable (1)
;   HandleToObject (1)
;   Import (3)
;   LoadShapeFile (1)
;   New (1)
;   ObjectIdToObject (1)
;   ObjectIdToObject32 (1)
;   Open (2)
;   PurgeAll ()
;   Regen (1)
;   Save ()
;   SaveAs (3)
;   SendCommand (1)
;   SetVariable (2)
;   StartUndoMark ()
;   Wblock (2)
T

 

ActiveLayer = #<VLA-OBJECT IAcadLayer 0000000025fcba98> <= 요넘을 변수로 잡아서 확인하면
(setq aLay (vla-get-ActiveLayer aDoc))
(vlax-dump-object aLay t)

; IAcadLayer: A logical grouping of data, similar to transparent acetate overlays on a drawing
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 0000000140532e28>
;   Description = ""
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000000025beeb50>
;   Freeze = 0
;   Handle (RO) = "10"
;   HasExtensionDictionary (RO) = -1
;   LayerOn = -1
;   Linetype = "Continuous"
;   Lineweight = -3
;   Lock = 0
;   Material = "Global"
;   Name = "0"
;   ObjectID (RO) = 44
;   ObjectID32 (RO) = 44
;   ObjectName (RO) = "AcDbLayerTableRecord"
;   OwnerID (RO) = 45
;   OwnerID32 (RO) = 45
;   PlotStyleName = "Color_7"
;   Plottable = -1
;   TrueColor = #<VLA-OBJECT IAcadAcCmColor 0000000026188ca0>
;   Used (RO) = -1
;   ViewportDefault = 0
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   SetXData (2)
T

 

현재레이어 정보가 들어가 있습니다.
현재레이어의 이름을 알고자 한다면


(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq aLay (vla-get-ActiveLayer aDoc))
(vla-get-name aLay)

 

이것을 한줄로 만든다면
(setq layerName (vla-get-name (vla-get-ActiveLayer (vla-get-activedocument (vlax-get-acad-object)))))

 

(vlax-dump-object aDoc t) ;엔터해서 다시 확인해보고
Layers (RO) = #<VLA-OBJECT IAcadLayers 0000000025fcc158> <=요넘을 변수로 잡아서 확인하면
(setq Lays (vla-get-layers aDoc))

Lays에 무엇이 들어있나 확인하려면 dump해봐야져..
(vlax-dump-object Lays t) or (vlax-dump-object (vla-get-layers aDoc) t)


; IAcadLayers: The collection of all layers in the drawing
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 0000000140532e28>
;   Count (RO) = 5
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000000025beeb50>
;   Handle (RO) = "2"
;   HasExtensionDictionary (RO) = -1
;   ObjectID (RO) = 45
;   ObjectID32 (RO) = 45
;   ObjectName (RO) = "AcDbLayerTable"
;   OwnerID (RO) = 0
;   OwnerID32 (RO) = 0
; Methods supported:
;   Add (1)
;   Delete ()
;   GenerateUsageData ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   Item (1)
;   SetXData (2)
T


Count (RO) = 5 <= 5는 레이어가 다섯개있다는 뜻
그 다섯개를 확인해서 리스트화 시키려면
 
 (setq LayerNames '()) ;<= 빈 리스트 하나 정의하고
 (vlax-for x (vla-get-layers aDoc)
  (setq LayerNames (append LayerNames (list (vla-get-name x))))
 )
LayerNames 변수에 현재도면의 모든 레이어가 리스트로 저장됩니다.
 
 *참고
  (vlax-for 변수 객체 실행함수) <= 리습의 foreach 함수와 비슷한데 리습에선 리스트인데 여긴 객체네요
  객체지만 그곳에 내포한 정보가 있으니 그것또한 리스트이겠쪄..


메소스에 add가 있네요..add가 있다는것은 추가가능한 상태라고 해석하구요
새로운 레이어를 만들어보겠습니다.

 

(setq NewLayer (vla-add Lays "연습삼아1"))
지도에서 Layers 까지 왔으니 여기서 add "연습삼아1" 하니 새로운 레이어 "연습삼아1"이 만들어졌습니다.

(vlax-dump-object NewLayer t)


; IAcadLayer: A logical grouping of data, similar to transparent acetate overlays on a drawing
; Property values:
;   Application (RO) = #<VLA-OBJECT IAcadApplication 0000000140532e28>
;   Description = ""
;   Document (RO) = #<VLA-OBJECT IAcadDocument 0000000025beeb50>
;   Freeze = 0
;   Handle (RO) = "218"
;   HasExtensionDictionary (RO) = 0
;   LayerOn = -1
;   Linetype = "Continuous"
;   Lineweight = -3
;   Lock = 0
;   Material = "Global"
;   Name = "연습삼아1"
;   ObjectID (RO) = 46
;   ObjectID32 (RO) = 46
;   ObjectName (RO) = "AcDbLayerTableRecord"
;   OwnerID (RO) = 45
;   OwnerID32 (RO) = 45
;   PlotStyleName = "Color_2"
;   Plottable = -1
;   TrueColor = #<VLA-OBJECT IAcadAcCmColor 00000000261884c0>
;   Used (RO) = 0
;   ViewportDefault = 0
; Methods supported:
;   Delete ()
;   GetExtensionDictionary ()
;   GetXData (3)
;   SetXData (2)
T

 

만들어진 레이어를 변수 NewLayer에 저장했으니 여기서 변경가능하겠네요..

(vla-put-color NewLayer 2)
(vla-put-linetype NewLayer "HIDDEN") ;<=HIDDEN이 로드되었다는 가정하에
만약 잠그고 싶다면
(vla-put-Lock NewLayer :vlax-true) ;<= 덤프의 결과는 숫자이지만 변경할때는 참 거짓으로 합니다.


(setq Lays (vla-get-layers aDoc)) ;<= 위에서 복사해온거로...
만약 현재도면에 내가 알고 있는 레이어에 대한 정보를 보려면
(setq aLay (vla-item Lays "연습삼아1")) ;<= "연습삼아1" 레이어를 알고있다는 전제하에..

 

대충 정리하자면

캐드에서 현재도면에서 레이어를 열어라.(지도에서 보듯이 레이어는 모형공간까지 갈 필요가 없군요)
(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq Lays (vla-get-layers aDoc))

 

실전에서 사용되어지는 예를 들어보겠습니다..

현재도면에 레이어 "연습삼아1"이 있다면 칼라를 5번으로 바꾸고
없으면 칼라 5번인 새로운 레이어 "연습삼아1"을 만들어라

 

 (setq LayerNames '())
 (vlax-for x (vla-get-layers aDoc)
  (setq LayerNames (cons (vla-get-name x) LayerNames))
 ) ;여기까진 레이어이름 추출해서 리스트화
 (if (member "연습삼아1" LayerNames) ;추출된 리스트중에 "연습삼아1" 이 있으면
  (progn ;있다면
   (vla-put-color (vla-item Lays "연습삼아1") 5)
   ;(vla-put-xxx    레이어에 대한 각종 정보변경
   ;
  )
  (progn ;없다면
   (setq NewLayer (vla-add Lays "연습삼아1")) ;레이어 새로 만들고
   (vla-put-color NewLayer 5)
   ;(vla-put-xxx   새로 만든 레이어의 각종 정보변경
   ;
  )
 )
 레이어를 리스트화 시켜서 그중에 "연습삼아1" 있으면 칼라를 5번으로 변경하고
 없으면 새로운 레이어 "연습삼아1" 만들고 칼라를 5번으로 변경
 그 이외의 것들도 변경가능하겠져..


(vlax-dump-object NewLayer t) ;엔터하고 확인하면
아래쪽 메소스에 Delete가 있네요..삭제라는거겠져..
(vla-Delete NewLayer) 레이어가 삭제 되겠지만..객체가 있으면 삭제 안되는거로 알고있습니다.


객체모델 지도에서 Layer에 대해 알아봤으니 나머지는 다 거기서 거기겠네요..
그런데 Utility는 리습에서도 생소한건데 한번 들여다 보겠습니다.
 
(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq util (vla-get-Utility aDoc))
(vlax-dump-object util t)

; IAcadUtility: A series of methods provided for utility purposes
; No properties
; Methods supported:
;   AngleFromXAxis (2)
;   AngleToReal (2)
;   AngleToString (3)
;   CreateTypedArray (3)
;   DistanceToReal (2)
;   GetAngle (2)
;   GetCorner (2)
;   GetDistance (2)
;   GetEntity (3)
;   GetInput ()
;   GetInteger (1)
;   GetKeyword (1)
;   GetObjectIdString (2)
;   GetOrientation (2)
;   GetPoint (2)
;   GetReal (1)
;   GetRemoteFile (3)
;   GetString (2)
;   GetSubEntity (5)
;   GetSubEntity32 (5)
;   InitializeUserInput (2)
;   IsRemoteFile (2)
;   IsURL (1)
;   LaunchBrowserDialog (6)
;   ObjectId32ToObjectIdString (1)
;   PolarPoint (3)
;   Prompt (1)
;   PutRemoteFile (2)
;   RealToString (3)
;   SendModelessOperationEnded (1)
;   TranslateCoordinates (5)
T

 

여러가지가 있지만 GetPoint한개만 설명합니다. 나머지는 VBA도움말 보고 공부하세요..

 

(setq pt (getpoint "\n 한지점 클릭: ")) ;<= LISP

 

(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq util (vla-get-Utility aDoc))

 

;(vla-getpoint util [point] [prompt]) <= VBA 설명서

(setq pt1 (vla-GetPoint util nil "\n 한지점 클릭: "))
(setq pt2 (vla-GetPoint util pt1 "\n 다른지점 클릭: "))

 

비슷한데 무엇이 다른지 결과값을 보고 확인해보져..
(setq pt (getpoint "\n 한지점 클릭: ")) ;<= 이것의 결과는
(10.7139 4.37798 0.0) <= 이렇게 좌표로 나오네요..

 

(setq pt1 (vla-GetPoint util nil "\n 한지점 클릭: ")) ;<= 이것의 결과는
#<variant 8197 ...> <= 이렇게 나오네요..

 

위에서 AxtiveX에서 좌표는 배열이라고 했던거 기억나시져..

서로 다른 방식으로 정보를 가지고 있어서 필요에 따라 변환을 시켜주어야 합니다.


좌표를 배열로 변환할때는 (vlax-3d-point pt)
배열을 좌표로 변환할때는 (vlax-safearray->list (vlax-variant-value pt1))

 

최종적으로 하려는 목적에 따라 getpoint를 쓸것인지 vla-getpoint를 쓸것인지 
작성자가 편한거 선택해서 사용하면 되겠네요..

 

이글 시작부에 라인그리기를 다시한번 해볼께요..
(setq aObj (vlax-get-acad-object))
(setq aDoc (vla-get-activedocument aObj))
(setq mSpace  (vla-get-ModelSpace aDoc))
(setq util (vla-get-Utility aDoc))
(setq pt1 (vla-GetPoint util nil "\n 한지점 클릭: "))
(setq pt2 (vla-GetPoint util pt1 "\n 다른지점 클릭: "))
(vla-addLine mSpace pt1 pt2) ;<= vlax-3d point 없이 하니깐 간단해지네요..

 
vla-getpoint 설명 하나가지곤 조금 아쉬우니..다른거 하나 더 해볼께요..


vla-GetEntity <= 요넘은 무엇일까요? VBA 도움말 보시면 알수 있어요..

설명보다 예제가 이해하는데 더 빠를거 같네요..


(setq ent (entsel "\n 객체선택: ")) ;<= LISP에서 하나의 객체 선택하는 방법이고 (car ent)=객체 (cadr ent)=선택지점좌표
ActiveX에선 entsel의 기능을 vla-GetEntity <= 요넘으로 합니다.
(vla-GetEntity util 'ent 'ip) ;<= ent가 객체 변수이고 ip가 선택지점
나머진 직접확인해 보세요..

 

이 정도 설명이면 입문하는데 도움이 되리라 봅니다.
참고로 LISP과 ActiveX는 정보를 저장하는데 있어서 다른것들이 몇가지 있습니다.
이 다른것들을 변환시키는 법만 알고 있으면 두 언어의 함수들을 마음대로 조작할수 있져..
또한 LISP에서 기능이 부족한것을 ActiveX에선 보강한 함수들도 있구요..
모르는 함수에 대해서는 VBA 도움말을 보시면 됩니다.

중요한것은 개념입니다. 개념만 있으면 어떠한것도 만들수 있습니다.


우리카페에 ¥Lisp자료 & 서브루틴 주말농부님이 올려주신 리습함수 도움말로된 설명서와..
다른 싸이트에서 다운받은 VBA도움말 화일을 첨부하니 다운받으셔서 참고하세요..

 

 

 

;-----------------------------------------------------------------------------------------
캐드는 도면이다보니 좌표가 거의 대부분을 차지합니다.

이 좌표를 마음대로 다룰수 있으면 리습의 반은 해결되었다고 봐야겠져..

▼ 함께풀어보는 LISP 에서 Vlax-Curve 함수 응용하는 방법 참조하시구요..

편집기는 ▲ LISP자료 & SUBroutine 에서 노트패드 사용법 참조하세요^^

 

;-----------------------------------------------------------------------------------------
댓글에 
 "제 vl 도움말에는 vlax-invoke oSpace 'addlightweightpolyline 이런거...없네여??"
 
 vlax-invoke 는 함수포맷만 약간 다르지만 결과는 같아집니다.
 
 (setq aObj (vlax-get-acad-object))
 (setq aDoc (vla-get-activedocument aObj))
 (setq util (vla-get-Utility aDoc))
 (setq pt1 (vla-GetPoint util nil "\n 한지점 클릭: "))
 (setq pt2 (vla-GetPoint util pt1 "\n 다른지점 클릭: "))
 (vla-addLine mSpace pt1 pt2) <= 이것을 
 (vlax-invoke-method mSpace 'addLine pt1 pt2) <= 이렇게도 해도 됩니다.
 
 이런 method란 꼬리가 붙어있네요..그럼 꼬리 없이 해볼까요..
 (vlax-invoke mSpace 'addLine pt1 pt2) <= 에러가 나네요..
 
 method꼬리 안붙이고 에러없이 되게 하려면
 (vlax-invoke mSpace 'addLine (vlax-safearray->list (vlax-variant-value pt1)) (vlax-safearray->list (vlax-variant-value pt1)))
 좌표를 배열에서 일반리습 좌표로 변환하면 되네요..
 
 그럼 이번엔 좌표를 리습으로 받아서 해볼께요
 (setq pt1 (getpoint "\n 한지점 클릭: "))
 (setq pt2 (getpoint "\n 다른지점 클릭: "))
 (vlax-invoke mSpace 'addLine pt1 pt2) <= 에러없이 됩니다.
 (vlax-invoke-method mSpace 'addLine pt1 pt2) <=에러가 납니다.
 (vlax-invoke-method mSpace 'addLine (vlax-3d-point pt1)(vlax-3d-point pt2)) <= 에러가 없이 됩니다.
 

 vlax-invoke 또는 vlax-invoke-method 함수에서 좌표의 형태에 따라 약간씩 차이가 있지만 모두 결과가 같습니다.

 

;********************************************************************************** 
cadgroup 싸이트 설명서에 보면

 http://www.cadgroup.info/lisp/index03.htm

 

 vlax-invoke-method 함수 
    지정된 ActiveX 메써드를 호출합니다.
        (vlax-invoke-method obj method arg [arg...])

 

 인수
  obj
   VLA 객체

    method
        호출될 메써드의 이름을 나타내는 기호 또는 문자열
    arg
        호출되는 메써드에 전달될 인수. 인수 형식이 검사되지 않습니다.

 리턴값
        호출된 메써드에 따라 다름.
 
 보기
  다음은 AddCircle 메써드를 사용하여 현재의 AutoCAD 도면에 원을 그립니다.

  AddCircle의 첫번째 인수는 원점의 위치를 나타냅니다. 이 메써드의 원점은 double형의 세 요소를
  갖는 배열이 포함된 variant로 지정되어야 합니다. vlax-3d-point 함수를 사용하여 
  AutoLISP 점 목록을 필요한 variant 데이터 형식으로 변환할 수 있습니다.

   _$ (setq circCenter (vlax-3d-point '(3.0 3.0 0.0)))
    #< variant 8197 ... >

  이제 vlax-invoke-method 명령으로 AddCircle 메써드를 호출하여 원을 그립니다.

   _$ (setq mycircle (vlax-invoke-method mspace 'AddCircle circCenter 3.0))
    #< VLA-OBJECT IAcadCircle 00bfd6e4 >
  

 

;**********************************************************************************


vba를 공부하다보니 남이 만든거에서 vl-catch-all-apply <= 요넘을 자주접하는데  
뜻을 몰라 한동안 분석하는데 어려움이 있었기에 추가설명을 합니다. 

apply 함수의 기능은 
        (apply 함수 리스트) <= 리스트의 내용을 함수로 처리해라.. 
         
        (apply '+ (list 1 2 3 4)) 
        결과 10 

        (apply 'strcat (list "a" "b" "c" "d") 
        결과 "abcd" 
         
        그럼 이번엔 에러가 나도록 해보겠습니다. 
        (apply '+ (list 1 2 3 "d"))  ;더해라 하면서 숫자가 아닌 문자를 넣었네요..
        결과 error:  
        (apply 'strcat (list 1 "b" "c" "d"))  ;문자끼리 연결해야 하는데 숫자가 있네요..
        결과 error:  

;-------------------------------------------------------------------------------------


        (apply 'vla-GetEntity (list util 'OBJ 'ip)) = (vla-GetEntity util 'OBJ 'ip)  ;두 문장은 같은 뜻입니다.
        (vla-GetEntity util 'OBJ 'ip)  ;객체 선택하면 OBJ에 객체가 저장되고 ip에 선택지점이 저장됩니다.
        (vla-GetEntity util 'OBJ 'ip)  ;객체 선택을 하지 않았다면 결과는 error:

        선택하지 않았을때 에러없이 다음으로 진행하는 함수가 있으면 좋겠네요.. 

        vl-catch-all-apply <= 요넘이 그런 함수입니다. 

        (vl-catch-all-apply '+ (list 1 2 3 4)) 
        결과 10 

        (vl-catch-all-apply '+ (list 1 2 3 "d")) 
        결과  #<%catch-all-apply-error%> 

        에러는 아니고 #<%catch-all-apply-error%> <= 이렇게 나오네요.. 
        만약 "d" 가 문자가 아니고 숫자였다면 오류없이 처리값을 돌려주겠져.. 

        vl-catch-all-error-p  ;<= 인수가 vl-catch-all-apply로부터 리턴된 오류 객체인지를 결정합니다.
        (vl-catch-all-error-p (setq test (vl-catch-all-apply '+ (list 1 2 3 4)))) 
        ;test변수에 10이 저장되고 nil을 응답

        (vl-catch-all-error-p (setq test (vl-catch-all-apply '+ (list 1 2 3 "d")))) 
        ;test변수에 #<%catch-all-apply-error%>가 저장되고 T를 응답
        ;변수 test의 내용을 보려한다면 
        (vl-catch-all-error-message test)  ;왜 오류가 발생했는지 알려줍니다.
                 
        vl-catch-all-error-p <=요넘은 vl-catch-all-apply 에서 오류가 나면 T를 응답하고 오류가 안나면 nil을 응답합니다. 


        테스트 구문 하나 만들어 보겠습니다. 
        (setq aObj (vlax-get-acad-object)) 
        (setq aDoc (vla-get-activedocument aObj)) 
        (setq mSpace  (vla-get-ModelSpace aDoc)) 
        (setq util (vla-get-Utility aDoc)) 
        (vla-GetEntity util 'OBJ 'ip "\n객체선택: ")  ;객체를 선택해라
        (vla-put-color OBJ 1)  ;선택한 객체의 색상을 빨강색으로 변경해라
        (vla-addCircle mSpace ip 1)  ;선택한 지점에 반지름이 1인 원을 그려라..
  
        위 구문은 아무런 문제가 없습니다. 
        그런데 객체가 선택되지 않았다면 에러가 발생합니다. 
        (vla-GetEntity util 'OBJ 'ip)  ;객체를 선택해라 <= 만약 이 부분에서 객체가 선택하지 않고 빈공간을 클릭했다면
        리습은 에러와 함께 종료됩니다. 
         
        일반리습에서는  
        (setq ent (entsel "\n객체선택: ")) 
        (setq OBJ (car ent) ip (cadr ent)) 
        (if OBJ 
                (어쩌구 저쩌구....) 
        ) 
        이런식으로 처리가 되지만 VBA에서  
        (vla-GetEntity util 'OBJ 'ip "\n객체선택: ")  ;<= 선택을 안하는 자체에서 에러가 발생됩니다.
        따라서 에러를 방지하려면 vl-catch-all-apply 함수와 vla-GetEntity 두 함수를 엮어야 합니다. 
         
        그럼 엮어볼께요.. 
        vl-catch-all-apply 추가하고 
        vla-GetEntity 요넘앞에 ' <= 어퍼스트로피 추가해서 'vla-GetEntity <= 이렇게 변경해주고 
        util 'OBJ 'ip "\n객체선택: " <= 요넘들은 리스트로 묶어줘서 (list util 'OBJ 'ip "\n객체선택: ") <= 이렇게 해주고 
         
        하나로 묶어주면 
        (vl-catch-all-apply 'vla-GetEntity (list util 'OBJ 'ip "\n객체선택: "))  ;<= 이렇게 되겠져..


        결국..(vla-GetEntity util 'OBJ 'ip "\n객체선택: ")과

             (vl-catch-all-apply 'vla-GetEntity (list util 'OBJ 'ip "\n객체선택: "))는  
        에러가 없을때는 같은 기능을 합니다. 
         
        아래처럼 테스트 함수를 만들어서...객체를 선택해보기도 하고 빈공간을 클릭도 해보세요.. 
        (defun c:test (/ aObj aDoc mSpace test util OBJ ip) 
           (setq aObj (vlax-get-acad-object)) 
           (setq aDoc (vla-get-activedocument aObj)) 
           (setq mSpace  (vla-get-ModelSpace aDoc)) 
           (setq util (vla-get-Utility aDoc)) 
             (if (vl-catch-all-error-p (setq test (vl-catch-all-apply 'vla-GetEntity (list util 'OBJ 'ip "\n객체선택: ")))) 
                (progn 
                   (princ (vl-catch-all-error-message test)) ;<= 오류가 발생하면 오류 메세지를 전달하고
                   (princ "\n진행을 종료합니다.")  ;<= 종료메세지 전달
                ) 
                (progn 
                   (vla-put-color OBJ 1)  ;선택한 객체의 색상을 1번으로 변경시키고
                   (vla-addCircle mSpace ip 1)  ;선택한 지점에 원을 그리겠네요..
                ) 
             ) 
             (princ) 
        ) 

억지로 만든 테스트문장이지만 
        vl-catch-all-error-message 와  vl-catch-all-error-p  vl-catch-all-apply 의 의미는 이해되었을거라 생각됩니다.

 

 

 

acadauto.chm
1.70MB
acad_vlr.chm
0.85MB
acadauto(vba-한글).chm
1.70MB
2010-acadauto(vba).chm
1.87MB

출처 : 아키모아 달수 http://cafe.daum.net/archimore/IP9e/12 

 

 

 

'Auto CAD > lisp' 카테고리의 다른 글

Prompting with a Default Option  (0) 2021.02.20
Mapcar & Lambda  (0) 2021.02.20
VL-remove (리스트에서 요소제거하기)  (0) 2019.04.04
vla-ZoomScaled (메써드)  (0) 2019.04.04
vla-ZoomCenter (메써드)  (0) 2019.04.04

댓글()