Author Topic: Circle Norm  (Read 10964 times)

0 Members and 1 Guest are viewing this topic.

Bryco

  • Water Moccasin
  • Posts: 1882
Circle Norm
« on: August 02, 2007, 07:21:56 PM »
I knew that a circle will take the current ucs normal when being inserted but I didn't know it also took that normal when being added to the block record.
I guess the answer is to set the active ucs to world before creating any block with vba.
Somewhat tedious.
Any better ideas?

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #1 on: August 02, 2007, 07:27:31 PM »
You should be able to calculate the normal in wcs terms given the current ucs normal you are using, same as getting points can sometimes trip you up with different ucs's, the bt record only sees the normal in the current ucs context which is quite different to wcs.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #2 on: August 02, 2007, 07:38:09 PM »
So either I set every objects normal or I make world current, it's probably a wash.
Mick is this happen in C# as well?

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #3 on: August 02, 2007, 08:10:33 PM »
yes, and ARX.
The db does not know the difference between a normal in a ucs or a wcs, it's just a value but all values are stored as 'world' values so when everything gets drawn it doesn't need to change between ucs's for every object that was created in a different ucs if that makes sense.
Either way you will need to calculate your normal or orientation in space, ie. even if you do set ucs to world you still need to calculate the >rotated< normal in wcs before you add your circle to the db.

edit: clarified that normal needed is the rotated from world normal
« Last Edit: August 02, 2007, 10:13:41 PM by MickD »
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #4 on: August 02, 2007, 09:52:23 PM »
Thanks for the reply,
actually if I make Wcs current the normal is fine (0,0,1).
The blockref also receives the ucs normal when inserted so I was looking at working out the rotation and leaving the normal as is. The math is a bit tricky (I can see it all but I seem to need a matrix so it's not worth while) so I think I'll insert it set the normal to 0,0,1 then transform it using the ucs matrix. It's the easy solution but I wouldn't say the best.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #5 on: August 02, 2007, 10:00:57 PM »
In case someone knows the math. The rotation would be found by transforming the ucs xdir vector from the ucs normal (crossproduct x and y) to a world normal, then comparing the new vector angle to the world x axis.

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #6 on: August 02, 2007, 10:20:13 PM »
it sounds like you need to do what you said in the op, create the block in wcs then xform it to its required position, this is good practice anyway and keeps the origin-al math simple. If you can get the destination ucs when inserting the block it will be easy -

create block @ origin,
get current ucs (or similar)
build matrix with ucs
xform block and done.

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

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #7 on: August 03, 2007, 05:03:29 PM »
Good advice Mick.
As an insert function the following works fine, but I do have to change the insertion point later (oBref.InsertionPoint = insPt), don't know why.


Code: [Select]
Function InsertBlockref(Space As AcadBlock, insPt As Variant, sName As String, Optional Sc As Double = 1, Optional Rot As Double = 0) As AcadBlockReference

    Dim oBref As AcadBlockReference
    Dim Zero(2) As Double
    Dim N(2) As Double, oUcs As AcadUCS
    Dim Att
   
    Set oBref = Space.InsertBlock(Zero, sName, Sc, Sc, Sc, Rot)
    If ThisDrawing.GetVariable("Worlducs") = 1 Then
        Set InsertBlockref = oBref
        Exit Function
    End If
   
    N(2) = 1
    oBref.Normal = N
    If oBref.HasAttributes Then
        For Each Att In oBref.GetAttributes
            Att.Normal = N
        Next Att
    End If
    Set oUcs = GetActiveUcs
    oBref.TransformBy oUcs.GetUCSMatrix
    oBref.InsertionPoint = insPt
    Set InsertBlockref = oBref
End Function

and a function


Code: [Select]
Function GetActiveUcs() As AcadUCS

    Dim Origin
    Dim Xaxis
    Dim Yaxis
    Dim strNm As String, sUcs As String

    sUcs = ThisDrawing.GetVariable("UCSNAME")
    If sUcs = "" Then
        ' Current UCS is not saved so get the data and save it
        'A ucs is saved when a user makes and saves one or
        ' a user clicks on an isoview button
        With ThisDrawing
            If .GetVariable("WORLDUCS") = 1 Then
                Xaxis = Zero: Yaxis = Zero
                Xaxis(0) = 1: Yaxis(1) = 1
                Set GetActiveUcs = ThisDrawing.UserCoordinateSystems.Add(Zero, Xaxis, Yaxis, "World")
                Exit Function
            End If
            Origin = .GetVariable("UCSORG")
            Xaxis = .GetVariable("UCSXDIR")
            Yaxis = .GetVariable("UCSYDIR")
            strNm = "Active"
        End With
        Set GetActiveUcs = ThisDrawing.UserCoordinateSystems.Add(Zero, Xaxis, Yaxis, strNm)
        'Changing the origin later stops the error message
        '-2145320930   UCS X axis and Y axis are not perpendicular
        GetActiveUcs.Origin = Origin
        ThisDrawing.ActiveUCS = GetActiveUcs
    Else
        Select Case sUcs
            Case "*TOP*", "TOP"
                Set GetActiveUcs = SetOrthoUCS("Top")
            Case "*BOTTOM*"
                Set GetActiveUcs = SetOrthoUCS("Bottom")
            Case "*LEFT*"
                Set GetActiveUcs = SetOrthoUCS("Left")
            Case "*RIGHT*"
                Set GetActiveUcs = SetOrthoUCS("Right")
            Case "*FRONT*"
                Set GetActiveUcs = SetOrthoUCS("Front")
            Case "*BACK*"
                Set GetActiveUcs = SetOrthoUCS("Back")

            Case Else
                Set GetActiveUcs = ThisDrawing.ActiveUCS  'current UCS is saved
            End Select
    End If

End Function
« Last Edit: August 03, 2007, 05:16:12 PM by Bryco »

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #8 on: January 02, 2008, 05:47:44 PM »
Hi Bryco, thought I'd resurrect this thread as I'm having the same problem myself now, I can't for the life of me know why they didn't implement more geometry classes in vba, particularly the matrix. Oh well...

I take it from the function above that if there is no ucs name i.e. it is "" that we will get a null object id error so we have to save the current ucs to the ucs table and grab it from there to transform an object to current ucs, is this right??

Also, do you have the SetOrthoUCS function handy?
thanks,
Mick.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #9 on: January 02, 2008, 07:17:00 PM »
Agreed Mick, C# has so much good math on tap.
Code: [Select]
Public Function SetOrthoUCS(Optional strUcs As String = "Top") As AcadUCS

    Dim dOrigin(2) As Double
    Dim dXaxisPnt(2) As Double
    Dim dYaxisPnt(2) As Double
    'all the ucs' will originate from 0,0,0 as per the behavior in acad
    Select Case strUcs
        Case "Top"
            dXaxisPnt(0) = 1: dXaxisPnt(1) = 0: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 1: dYaxisPnt(2) = 0
       
        Case "Bottom"
            dXaxisPnt(0) = -1: dXaxisPnt(1) = 0: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 1: dYaxisPnt(2) = 0
       
        Case "Right"
            dXaxisPnt(0) = 0: dXaxisPnt(1) = 1: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 0: dYaxisPnt(2) = 1
       
   
        Case "Left"
            dXaxisPnt(0) = 0: dXaxisPnt(1) = -1: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 0: dYaxisPnt(2) = 1
       
   
        Case "Front"
            dXaxisPnt(0) = 1: dXaxisPnt(1) = 0: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 0: dYaxisPnt(2) = 1
   
     
        Case "Back"
            dXaxisPnt(0) = -1: dXaxisPnt(1) = 0: dXaxisPnt(2) = 0
            dYaxisPnt(0) = 0: dYaxisPnt(1) = 0: dYaxisPnt(2) = 1
           
        Case Else
            Exit Function
    End Select

    Set SetOrthoUCS = ThisDrawing.UserCoordinateSystems.Add(dOrigin, dXaxisPnt, dYaxisPnt, strUcs)
    ThisDrawing.ActiveUCS = SetOrthoUCS

End Function

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #10 on: January 02, 2008, 07:30:10 PM »
Thanks Bryco, I'll give those a run and see how it goes.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #11 on: January 02, 2008, 07:32:17 PM »
As far as matrices. You are ok for the ucs as the getvars are updated
Code: [Select]
Function UcsM() As Variant

    Dim M(3, 3) As Double
    Dim Orig As Variant
    Orig = ThisDrawing.GetVariable("Ucsorg")
    Dim x, Y, Z
    x = ThisDrawing.GetVariable("UCSXDIR")
    Y = ThisDrawing.GetVariable("UCSYDIR")
    Z = Crossproduct(x, Y)
    M(0, 0) = x(0): M(0, 1) = Y(0): M(0, 2) = Z(0): M(0, 3) = Orig(0)
    M(1, 0) = x(1): M(1, 1) = Y(1): M(1, 2) = Z(1): M(1, 3) = Orig(1)
    M(2, 0) = x(2): M(2, 1) = Y(2): M(2, 2) = Z(2): M(2, 3) = Orig(2)
    M(3, 0) = 0: M(3, 1) = 0: M(3, 2) = 0: M(3, 3) = 1
    
    UcsM = M
    
End Function









'Vectors

Function XYZ(x As Double, Y As Double, Z As Double) As Variant
    Dim P(2) As Double
    P(0) = x: P(1) = Y: P(2) = Z
    XYZ = P
End Function

Function AddVectors(v1, v2) As Variant
    Dim V3(2) As Double
    V3(0) = v1(0) + v2(0)
    V3(1) = v1(1) + v2(1)
    V3(2) = v1(2) + v2(2)
    AddVectors = V3
End Function

Function SubtractVectors(v1, v2) As Variant
    Dim V3(2) As Double
    V3(0) = v1(0) - v2(0)
    V3(1) = v1(1) - v2(1)
    V3(2) = v1(2) - v2(2)
    SubtractVectors = V3
End Function

Function DotProduct(v1, v2)
    Dim V3(2) As Double
    V3(0) = v1(0) * v2(0)
    V3(1) = v1(1) * v2(1)
    V3(2) = v1(2) * v2(2)
    DotProduct = V3
End Function


Function Crossproduct(A, b) As Variant

    Dim Ax As Double, Ay As Double, Az As Double
    Dim Bx As Double, By As Double, Bz As Double
    Dim Unit As Double
    Dim c(2) As Double
    'get CrossProduct
    Ax = A(0): Ay = A(1): Az = A(2)
    Bx = b(0): By = b(1): Bz = b(2)
    
    c(0) = Ay * Bz - Az * By
    c(1) = Az * Bx - Ax * Bz
    c(2) = Ax * By - Ay * Bx
    
    'Convert to unit normal
    Unit = Sqr(c(0) * c(0) + c(1) * c(1) + c(2) * c(2))
    c(0) = c(0) / Unit: c(1) = c(1) / Unit: c(2) = c(2) / Unit
    Crossproduct = c

End Function

Function NormaliseVector(V As Variant) As Variant
    Dim Unit As Double
    Dim Vn(2) As Double
    Unit = Sqr(V(0) * V(0) + V(1) * V(1) + V(2) * V(2))
    Vn(0) = V(0) / Unit: Vn(1) = V(1) / Unit: Vn(2) = V(2) / Unit
    NormaliseVector = Vn
End Function







Mick there's some matrix stuff in the text file.
The inverse matrix will be handy as it is a bear to write

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #12 on: January 02, 2008, 07:42:01 PM »
Nice code there Bryco! will come in handy for sure.
thanks again.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Circle Norm
« Reply #13 on: January 02, 2008, 08:00:57 PM »
No wuckers Mick,  I still owe you I reckon.

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Circle Norm
« Reply #14 on: January 02, 2008, 09:42:29 PM »
I don't know about that, what I do know though is the UCS is a pig to work with in vba though!

All I'm trying to do is save the current ucs, set the ucs to world, do my mojo then set it back. How I have it 'should' work though I still get strange results if a user picked ucs's vector lines up with a std ucs...strange

Code: [Select]
Dim ucs As AcadUCS
Set ucs = GetActiveUcs
SetOrthoUCS
ent.TransformBy (ThisDrawing.ActiveUCS.GetUCSMatrix)
ThisDrawing.ActiveUCS = ucs

The SetOrthoUcs sets the ucs to 'top' by default so it should be going to 'world' and it also looks after any conditions where it is set to world.

It's no real biggie and I can live with it, just annoying.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien