 Author Topic: Circle Norm  (Read 5390 times)

0 Members and 1 Guest are viewing this topic.

Bryco

• Water Moccasin
• Posts: 1849 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? 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.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 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? 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 »
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 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: 1849 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. 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
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 Re: Circle Norm
« Reply #7 on: August 03, 2007, 05:03:29 PM »
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 » 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.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 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 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.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 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)
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 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.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.

Bryco

• Water Moccasin
• Posts: 1849 Re: Circle Norm
« Reply #13 on: January 02, 2008, 08:00:57 PM »
No wuckers Mick,  I still owe you I reckon. 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.
Forth is like the Tao: it is a Way, and is realized when followed.
Its fragility is its strength; its simplicity is its direction - Michael Ham

Lao Tzu: To attain knowledge, add things
every day; to obtain wisdom, remove things every day.