AutoCAD

Just starting out? Need help? Post your questions and find answers here.
InGeomatics.com
New User
New User
Posts: 1
Joined: Thu Oct 10, 2019 4:02 am

AutoCAD

Post by InGeomatics.com »

How can I do this with PureBasic?
I try to use COMatePLUS but unsuccessfully. Don't know how to transfer variable values (like the arrays for coordinates startPoint and endPoint).

Code: Select all

Dim acadApp As AcadApplication
Dim acadDoc As AcadDocument
Dim lineObj As AcadLine

Private Sub Command2_Click()
    On Error Resume Next
    Dim x As Long
    Dim y As Long
    Dim startPoint(0 To 2) As Double
    Dim endPoint(0 To 2) As Double
    
    ' Connect to the AutoCAD drawing
    Set acadDoc = acadApp.ActiveDocument
    ' Establish the endpoints of the line
     startPoint(0) = 0
     startPoint(1) = 0
     startPoint(2) = 0
     endPoint(0) = 50
     endPoint(1) = 5
     endPoint(2) = 0
    ZoomWindow startPoint, endPoint
    Label1.Caption = "Working..."
    For x = 0 To 50
     startPoint(0) = x
     startPoint(1) = 0
     startPoint(2) = 0
     endPoint(0) = x + 5
     endPoint(1) = 5
     endPoint(2) = 0
     ' Create a Line object in model space
     Set lineObj = acadDoc.ModelSpace.AddLine(startPoint, endPoint)
     lineObj.Update
    Next x
    ZoomExtents
    acadApp.Visible = True
    Label1.Caption = "Done."
End Sub


Private Sub Form_Load()
    On Error Resume Next

    Set acadApp = GetObject(, "AutoCAD.Application.16")
    If Err Then
        Err.Clear
        Set acadApp = CreateObject("AutoCAD.Application.16")
        If Err Then
            MsgBox Err.Description
            Exit Sub
        End If
    End If

End Sub
Edit: Code tags added (Kiffi)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: AutoCAD

Post by spikey »

Sorry to take so long to reply - this isn't straightforward so took a while for me to work it all out. I can't test this because I haven't got Autocad, so you may have to tinker to get it to work properly (be liberal with 'Debug COMate_GetLastErrorDescription()'), but hopefully it should point you in the right direction.

You need to marshal each array parameter into a safearray and then into a variant type variable and supply the pointer to this variant as the array parameter value. There are some working demos in the COMate zip showing how to do this in Excel.
Look for Demo_Excel - FillSheetFromSafeArray.pb in the Basic Demos; particularly if you'll eventually want to put text into your drawing as this is needs an extra step.

Creating multiple lines is a question of including the create start/end point safearray bundling and the call to AddLine in a loop...
I couldn't find ZoomExtents in the DOM documentation so I don't know what its parent is, but the way to call it is to 'invoke' it as member of its parent.

Code: Select all

IncludeFile "COMatePLUS.pbi"

;-Safe array structures - taken from "VariantHelper_Include.pb"
;==============================================================
CompilerIf Defined(SAFEARRAYBOUND, #PB_Structure)=0
  Structure SAFEARRAYBOUND 
    cElements.l 
    lLbound.l 
  EndStructure 
CompilerEndIf

CompilerIf Defined(SAFEARRAY, #PB_Structure)=0
  Structure SAFEARRAY 
    cDims.w 
    fFeatures.w 
    cbElements.l 
    cLocks.l 
    *pvData.pData 
    rgsabound.SAFEARRAYBOUND[0] 
  EndStructure 
CompilerEndIf

; Populate the array.
Dim startPoint.D(2)
startPoint(0) = 0
startPoint(1) = 0
startPoint(2) = 0

; Begin with an array of SAFEARRAYBOUND structures, one for each dimension - in this case one.
Dim safeArrayBound.SAFEARRAYBOUND(0)
With safeArrayBound(0)
  \lLbound = 0
  \cElements = 3
EndWith

; Now create the array and check for success.
Define *startPoint.SAFEARRAY
*startPoint = SafeArrayCreate_(#VT_R8, 1, @safeArrayBound())
If *startPoint = 0
  Debug "Couldn't create the Safearray *startPoint."
  End
EndIf

; Copy the source array content into the safearray.
; (I assume that your actual data will be coming from somewhere else, if not 
; you could just create the safearray and populate it directly, you don't _need_ the base array).
Define.I index, result

For index = 0 To 2
  
  result = SafeArrayPutElement_(*startPoint, @index, @startPoint(index))
  
  Select result
    Case #S_OK
      Debug "#S_OK"
    Case #DISP_E_BADINDEX
      Debug "#DISP_E_BADINDEX"
    Case #E_INVALIDARG
      Debug "#E_INVALIDARG"
    Case #E_OUTOFMEMORY
      Debug "#E_OUTOFMEMORY"
  EndSelect
      
Next index    

; Bundle the Safearray up into a variant suitable for passing to a COM method.
Define varStartPoint.VARIANT
With varStartPoint
  \vt = #VT_ARRAY | #VT_R8
  \parray = *startPoint
EndWith

; Repeat for the end point.

; Populate the array.
Dim endPoint.D(2)
endPoint(0) = 50
endPoint(1) = 5
endPoint(2) = 0

; I don't need to update safeArrayBound here because it's the same dimensions as before.

Define *endPoint.SAFEARRAY
*endPoint = SafeArrayCreate_(#VT_R8, 1, @safeArrayBound())
If *endPoint = 0
  Debug "Couldn't create the Safearray *endPoint."
  End
EndIf

; Transfer the source array content into the safearray.
For index = 0 To 2
  
  result = SafeArrayPutElement_(*endPoint, @index, @endPoint(index))
  
  Select result
    Case #S_OK
      Debug "#S_OK"
    Case #DISP_E_BADINDEX
      Debug "#DISP_E_BADINDEX"
    Case #E_INVALIDARG
      Debug "#E_INVALIDARG"
    Case #E_OUTOFMEMORY
      Debug "#E_OUTOFMEMORY"
  EndSelect
      
Next index    

; Bundle the Safearray up into a variant suitable for passing to a COM method.
Define varEndPoint.VARIANT
With varEndPoint
  \vt = #VT_ARRAY | #VT_R8
  \parray = *endPoint
EndWith

; Try to get a link to a running instance.
Define.COMateObject acadApp, acadDoc, lineObj
acadApp = COMate_GetObject("", "AutoCAD.Application.16")

; If this fails create a new instance.  
If Not acadApp
  acadApp = COMate_CreateObject("AutoCAD.Application.16")
EndIf

If Not acadApp
  Debug "Couldn't start AutoCAD."
  Debug COMate_GetLastErrorDescription()
  End
EndIf

Debug "Make it visible."
acadApp\SetProperty("Visible = #True")
Debug COMate_GetLastErrorDescription()

Debug "Get the active document."
acadDoc = acadApp\GetObjectProperty("ActiveDocument")
Debug COMate_GetLastErrorDescription()

Debug "Add a line to the document."
lineObj = acadDoc\GetObjectProperty("\ModelSpace\AddLine(" + StrU(*startPoint) + " as Variant, " + StrU(*endPoint) + " as Variant)")
Debug COMate_GetLastErrorDescription()

Debug "Invoke zoom extents when you've got the right parent object."
acadDoc\Invoke("ZoomExtents")

; Tidy up.
lineObj\Release()
acadDoc\Release()
acadApp\Release()
VariantClear_(varStartPoint)
VariantClear_(varEndPoint)
User avatar
spikey
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 22, 2010 1:17 pm
Location: United Kingdom

Re: AutoCAD

Post by spikey »

Looking at this again I see I made a mistake originally, this is still untested however so no guarantees!

Code: Select all

IncludeFile "COMatePLUS.pbi"

;-Safe array structures - taken from "VariantHelper_Include.pb"
;==============================================================
CompilerIf Defined(SAFEARRAYBOUND, #PB_Structure)=0
  Structure SAFEARRAYBOUND 
    cElements.l 
    lLbound.l 
  EndStructure 
CompilerEndIf

CompilerIf Defined(SAFEARRAY, #PB_Structure)=0
  Structure SAFEARRAY 
    cDims.w 
    fFeatures.w 
    cbElements.l 
    cLocks.l 
    *pvData.pData 
    rgsabound.SAFEARRAYBOUND[0] 
  EndStructure 
CompilerEndIf

; Populate the array.
Dim startPoint.D(2)
startPoint(0) = 0
startPoint(1) = 0
startPoint(2) = 0

; Begin with an array of SAFEARRAYBOUND structures, one for each dimension - in this case one.
Dim safeArrayBound.SAFEARRAYBOUND(0)
With safeArrayBound(0)
  \lLbound = 0
  \cElements = 3
EndWith

; Now create the array and check for success.
Define *startPoint.SAFEARRAY
*startPoint = SafeArrayCreate_(#VT_R8, 1, @safeArrayBound())
If *startPoint = 0
  Debug "Couldn't create the Safearray *startPoint."
  End
EndIf

; Copy the source array content into the safearray.
; (I assume that your actual data will be coming from somewhere else, if not 
; you could just create the safearray and populate it directly, you don't _need_ the base array).
Define.I index, result

For index = 0 To 2
  
  result = SafeArrayPutElement_(*startPoint, @index, @startPoint(index))
  
  Select result
    Case #S_OK
      Debug "#S_OK"
    Case #DISP_E_BADINDEX
      Debug "#DISP_E_BADINDEX"
    Case #E_INVALIDARG
      Debug "#E_INVALIDARG"
    Case #E_OUTOFMEMORY
      Debug "#E_OUTOFMEMORY"
  EndSelect
      
Next index    

; Bundle the Safearray up into a variant suitable for passing to a COM method.
Define varStartPoint.VARIANT
Define *varStartPoint
With varStartPoint
  \vt = #VT_ARRAY | #VT_R8
  \parray = *startPoint
EndWith
*varStartPoint = @varStartPoint

; Repeat for the end point.

; Populate the array.
Dim endPoint.D(2)
endPoint(0) = 50
endPoint(1) = 5
endPoint(2) = 0

; I don't need to update safeArrayBound here because it's the same dimensions as before.

Define *endPoint.SAFEARRAY
*endPoint = SafeArrayCreate_(#VT_R8, 1, @safeArrayBound())
If *endPoint = 0
  Debug "Couldn't create the Safearray *endPoint."
  End
EndIf

; Transfer the source array content into the safearray.
For index = 0 To 2
  
  result = SafeArrayPutElement_(*endPoint, @index, @endPoint(index))
  
  Select result
    Case #S_OK
      Debug "#S_OK"
    Case #DISP_E_BADINDEX
      Debug "#DISP_E_BADINDEX"
    Case #E_INVALIDARG
      Debug "#E_INVALIDARG"
    Case #E_OUTOFMEMORY
      Debug "#E_OUTOFMEMORY"
  EndSelect
      
Next index    

; Bundle the Safearray up into a variant suitable for passing to a COM method.
Define varEndPoint.VARIANT
Define *varEndPoint
With varEndPoint
  \vt = #VT_ARRAY | #VT_R8
  \parray = *endPoint
EndWith
*varEndPoint = @varEndPoint

; Try to get a link to a running instance.
Define.COMateObject acadApp, acadDoc, acadModel, lineObj
acadApp = COMate_GetObject("", "AutoCAD.Application.16")

; If this fails create a new instance.  
If Not acadApp
  acadApp = COMate_CreateObject("AutoCAD.Application.16")
EndIf

If Not acadApp
  Debug "Couldn't start AutoCAD."
  Debug COMate_GetLastErrorDescription()
  End
EndIf

Debug "Make it visible."
acadApp\SetProperty("Visible = #True")
Debug COMate_GetLastErrorDescription()

Debug "Get the active document."
acadDoc = acadApp\GetObjectProperty("ActiveDocument")
Debug COMate_GetLastErrorDescription()

Debug "Get the model space."
acadModel = acadDoc\GetObjectProperty("ModelSpace")
Debug COMate_GetLastErrorDescription()

Debug "Add a line to the document."
lineObj = acadModel\GetObjectProperty("AddLine(" + StrU(*varStartPoint) + " as Variant, " + StrU(*varEndPoint) + " as Variant)")
Debug COMate_GetLastErrorDescription()

Debug "Invoke zoom extents when you've got the right parent object."
acadDoc\Invoke("ZoomExtents")

; Tidy up.
lineObj\Release()
acadModel\Release()
acadDoc\Release()
acadApp\Release()
VariantClear_(varStartPoint)
VariantClear_(varEndPoint)
Post Reply