Author Topic: vector/matrix functions for acad  (Read 13162 times)

0 Members and 1 Guest are viewing this topic.

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
vector/matrix functions for acad
« on: December 06, 2007, 09:11:09 PM »
I'm working on a little lib for transforming entities etc in vba, I've made a bit of a start but as I haven't touched vba in years I am more than a little rusty on the finer points of some syntax and proper structure.
Any pointers on how to proceed with this?
My first problem I see is assigning arrays to other arrays, is there an easier way than assigning each item to each item in the other array, I don't seem to be able to do things like this without compile errors -

Dim a1(2) As Double, a2 As Double

'fill a1 up with some values
'
'assign a1 to a2
a2 = a1 ' <- don't work

as you can see in the code below I have been using Variants to pass return values and then assigning the individual elements to my proper arrays, is there a better way?
thanks.
Code: [Select]
'''''''''------- Vector Methods --------------'''''''''''
Public Function VecNorm(vec() As Double) As Double()
'Normalises the incoming vector.
Dim vecn(2) As Double
Dim unit As Double
unit = Sqr(vec(0) * vec(0) + vec(1) * vec(1) + vec(2) * vec(2))
vecn(0) = vec(0) / unit: vecn(1) = vec(1) / unit: vecn(2) = vec(2) / unit
VecNorm = vecn
End Function

Function VecCross(v1() As Double, v2() As Double) As Variant
    Dim vec(2)
    vec(0) = v1(1) * v2(2) - v2(1) * v1(2)
    vec(1) = v1(2) * v2(0) - v2(2) * v1(0)
    vec(2) = v1(0) * v2(1) - v2(0) * v1(1)
    VecCross = vec
End Function

'''''''''--------- Matrix Methods ------------'''''''''''
Public Function xFormMat(vx() As Double, vy() As Double, vz() As Double) As Variant
'Uses the incoming vectors to transform the entity being passed in
Dim mat(0 To 3, 0 To 3) As Double

mat(0, 0) = vx(0): mat(0, 1) = vy(0): mat(0, 2) = vz(0): mat(0, 3) = 0#
mat(1, 0) = vx(1): mat(1, 1) = vy(1): mat(1, 2) = vz(1): mat(1, 3) = 0#
mat(2, 0) = vx(2): mat(2, 1) = vy(2): mat(2, 2) = vz(2): mat(2, 3) = 0#
mat(3, 0) = 0#: mat(3, 1) = 0#: mat(3, 2) = 0#: mat(3, 3) = 1#

xFormMat = mat
End Function

Public Function GetMatFromLine(line As AcadLine) As Variant
'builds a matrix based on the line's sp, ep and normal
Dim mat(0 To 3, 0 To 3) As Double
Dim vx(2) As Double, vy(2) As Double, vz(2) As Double

'get the lines ep-sp vector to create the z axis:
vz(0) = line.EndPoint(0) - line.StartPoint(0)
vz(1) = line.EndPoint(1) - line.StartPoint(1)
vz(2) = line.EndPoint(2) - line.StartPoint(2)
'normalise it:
Dim retvec As Variant
retvec = VecNorm(vz)
vz(0) = retvec(0): vz(1) = retvec(1): vz(2) = retvec(2)

'get the line's normal for the x vector:
vx(0) = line.Normal(0)
vx(1) = line.Normal(1)
vx(2) = line.Normal(2)

'create the y vector by xproduct of z over x:
retvec = VecCross(vz, vx)
vy(0) = retvec(0): vy(1) = retvec(1): vy(2) = retvec(2)
'normalise it:
retvec = VecNorm(vy)
vy(0) = retvec(0): vy(1) = retvec(1): vy(2) = retvec(2)

'plug 'em into the matrix:
mat(0, 0) = vx(0): mat(0, 1) = vy(0): mat(0, 2) = vz(0): mat(0, 3) = 0#
mat(1, 0) = vx(1): mat(1, 1) = vy(1): mat(1, 2) = vz(1): mat(1, 3) = 0#
mat(2, 0) = vx(2): mat(2, 1) = vy(2): mat(2, 2) = vz(2): mat(2, 3) = 0#
mat(3, 0) = 0#: mat(3, 1) = 0#: mat(3, 2) = 0#: mat(3, 3) = 1#

GetMatFromLine = mat
End Function

I have quite a few more to add and will post them but I would like some advice before I produce too much rubbish :)

"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #1 on: December 06, 2007, 09:24:28 PM »
Hi Mick. Warning, the following is not the best expressed post I've ever authored.

If you employ User Defined Types (UDT), (which to speak curly brace speak would be loosely analogous to structs) you can set one UDT var to another UDT var of the same type and it copies the data (kinda like an OO deep clone) from one to the other, rather than assigning the pointer (I'm abusing the language here because a UDT variable is not a pointer) to the other (which is what would happen if they were objects rather than UDTs).

Could this be exploited for your app?

Perhaps, via matrix and vector defined types. Having said that I'm a moron when it comes to matrix / vector math so I can't say.

Do you want a simple UDT code example?
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: vector/matrix functions for acad
« Reply #2 on: December 06, 2007, 09:52:21 PM »
Could this be exploited for your app?
I was thinking of creating some classes and it seems logical but I could get away with a few functions, I only have to write them once, I'm just being lazy :)

Quote
Do you want a simple UDT code example?

Yep, why not - we are talking about vb classes aren't we?
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #3 on: December 06, 2007, 09:56:04 PM »
we are talking about vb classes aren't we?

Nope. User Define Types are not classes. Think C structs for closest analogous data type that you're familiar with.

Let me bang out an example to illuminate ...
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: vector/matrix functions for acad
« Reply #4 on: December 06, 2007, 10:11:26 PM »
>>C structs

Cool!
I do have just one last problem though, say I have a matrix udt, I will still need to assign it to an array to pass to a transformBy method though...although I could right a function to do that on the fly I guess.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #5 on: December 06, 2007, 10:23:00 PM »
Quick and dirty, hope it illuminates.

Code: [Select]
Option Explicit

Type TPoint

    X As Double
    Y As Double
    Z As Double

End Type

Type TLine

    P1 As TPoint
    P2 As TPoint

End Type

Sub Demo ( )

    Dim P1 As TPoint, _
        P2 As TPoint

    With P1
        .X = 20
        .Y = 20
    End With
   
    ''  Set P2 = P1, remembering it's a copy of the data.
    ''  Not the same as setting one object to another.
    ''  If you're a .NET geek think of UDTs as value types
    ''  (as opposed to reference types).
   
    P2 = P1
   
    ''  Show P2's data

    With P2
        Debug.Print "P2's initial data:"
        Debug.Print "P2.X ="; .X; ", P2.Y = "; .Y
        Debug.Print
    End With
   
    ''  prove P2 is not a pointer to P1 by assigning new
    ''  data to P1 and reprinting P2's data
   
    With P1
        .X = 10
        .Y = 10
    End With

    ''  show p2's data again (ha, still 20, 20)

    With P2
        Debug.Print "P2's data after P1 given new values:"
        Debug.Print "P2.X ="; .X; ", P2.Y = "; .Y
        Debug.Print
    End With
   
    ''  now demonstrate a deeper copy
   
    Dim L1 As TLine, _
        L2 As TLine
       
    ''  initialize L1 using previously defined P1 and P2
   
    With L1
        .P1 = P1
        .P2 = P2
    End With
   
    ''  now force L2 to have a copy of L1's data (the deeper copy)
   
    L2 = L1
   
    ''  show L2's data
   
    With L2
        Debug.Print "L2's data:"
        Debug.Print "L2, P1.x = "; .P1.X; " , P1.y = "; .P1.Y
        Debug.Print "L2, P2.x = "; .P2.X; " , P2.y = "; .P2.Y
    End With
   
    ''  ha, cool you say; not too shabby for vb.

End Sub

Have fun.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: vector/matrix functions for acad
« Reply #6 on: December 06, 2007, 10:28:12 PM »
Thanks MP, will give that a go over the week end, the 19th is calling here ;)
I'll let you know how I get on.

thanks again.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #7 on: December 06, 2007, 10:31:08 PM »
My pleasure Mick. Will be interesting to see how your solution turns out.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

SEANT

  • Bull Frog
  • Posts: 345
Re: vector/matrix functions for acad
« Reply #8 on: December 07, 2007, 04:23:36 AM »
Wow, MP, that is very enlightening. 

I was about to suggest:

Dim a1(2) As Double, a2() As Double 'a2 as dynamic

'fill a1 up with some values
'
'assign a1 to a2
a2 = a1 ' <- Should work


and

Function VecCross(v1() As Double, v2() As Double) As Double()

But this method is not nearly as versatile as the one you posted.
« Last Edit: December 07, 2007, 04:28:45 AM by SEANT »
Sean Tessier
AutoCAD 2016 Mechanical

Dnereb

  • Guest
Re: vector/matrix functions for acad
« Reply #9 on: December 07, 2007, 08:16:37 AM »
To make your code more concise use these syntaxes

Code: [Select]
Sub Test()


    Dim A1(2) As Double
    Dim A2() As Double
    Dim A3() As Double

    Dim Var As Variant
   
   
    A1(0) = 1: A1(1) = 1: A1(2) = 2
    A2() = A1()
   
    Var = A1()
   
    A3() = Var
   
 
   
End Sub

Note: The array must de declared without any elements to be able to assign another array to  it.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #10 on: December 07, 2007, 09:11:29 AM »
Wow, MP, that is very enlightening.

It's what we had before BASIC went OO Lite.

 :-)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Dnereb

  • Guest
Re: vector/matrix functions for acad
« Reply #11 on: December 07, 2007, 09:46:51 AM »
@MP,

mytwocents
I think there's a flipside to your solution. Most, if any, Acad functions don't accept UDT's.
This can be a problem converting a point in WCS to UCS coordinates or vicaversa for instance.
using Doublearrays and variants won't have that problem.

Oh and an addition for copying initialized indexed arrays... the hard way. Use this if you can't avoid it.
Code: [Select]
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, Source As Any, ByVal numBytes As Long)

Sub Test()

Dim P1(2) As Double
Dim P2(2) As Double

'P1(0) = 1: P1(1) = 2: P1(2) = 3

CopyArray P1, P2

MsgBox (P2(2))

End Sub

Sub CopyArray(Source() As Double, Target() As Double)

    Dim NumOfBytes As Long
   
    On Error GoTo NoElements
    NumOfBytes = (UBound(Source) + 1) * LenB(Source(0))
    ReDim Target(UBound(Source))                              'no need for a diffrent number of items to be a
                                                            'true copy and save checking if the target is large enough...
   
       
    CopyMemory Target(0), Source(0), NumOfBytes
   
NoElements:

MsgBox "Empty Source array in Sub CopySourceArray() at " & Format$(Now(), "hh:nn ss"), vbCritical + vbOKOnly + vbMsgBoxSetForeground, "Void Array."
On Error GoTo 0
Exit Sub

End Sub


MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #12 on: December 07, 2007, 10:15:00 AM »
Hi Berend.

Agreed, AutoCAD doesn't generally accept UDTs.

I wouldn't however dismiss them outright solely for the reason. Like many encapsulated solutions, what is employed under the covers may be fully hidden to the caller.

The developer must ask him/herself lots of questions, like ... Intrinsic or Win32 API based techniques? Are there performance implications? Are there potential migration issues? How flexible is a given technique? Does it align well with with the problem domain and fundamental data types? Does it avoid variants (blech)? Does it easily map to other languages? etc.

I was just anteing up food for thought. It may or may not prove to be the most efficient way for Mick to pen his solution. I'm just trying to do my part by identifying some options. I thank you because you are doing the same.

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: vector/matrix functions for acad
« Reply #13 on: December 07, 2007, 10:59:21 AM »
Another example for Mick, observe --

Code: [Select]
Option Explicit

Type TPoint

    Coord(0 To 2) As Double

End Type

Sub AnotherDemo ( )

    Dim P1 As TPoint
   
    P1.Coord(0) = 10
    P1.Coord(1) = 20

    Dim P2 As TPoint
   
    P2 = P1
   
    Debug.Print P2.Coord(0)
    Debug.Print P2.Coord(1)

End Sub

:)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

Bryco

  • Water Moccasin
  • Posts: 1882
Re: vector/matrix functions for acad
« Reply #14 on: December 07, 2007, 12:35:34 PM »
I use a variant a lot to pass the double, while it is a little slower sometimes it comes in handy as you can use ismissing to detect whether it is passed or not.
The following sub shows the variant as being twice as slow though
Code: [Select]
Sub PassTheDoubly()

    Dim P1(2) As Double
    Dim P2(2) As Double
    Dim V As Variant
    Dim i As Long, j As Integer
    Dim T As Single
   
    T = Timer
    P1(0) = 23: P1(1) = 23: P1(2) = 23
    For i = 0 To 1000000
        For j = 0 To 2
            P2(j) = P1(j)
        Next j
    Next i
   
    Debug.Print "double time=" & Timer - T
   
    T = Timer
    For i = 0 To 1000000
      V = P1
    Next i
     Debug.Print "Var time=" & Timer - T
   
End Sub
double time=0.375
Var time=0.875