PDA

View Full Version : UCS and Z-Axis Vector method



coondog45
2008-11-03, 08:36 AM
I am trying to automate the creation of a series of UCS's that align the z direction with the axis of a polyline. (The x-axis may remain in the world ucs x-y plane).When you create a ucs manually there is a z-axis option in the contex menu. I have not been able to find this method in the axtive-X reference. Is there a subroutine or a function that can use a point located on the z-axis of the ucs as a reference for rotation about the x-axis? Does any one have any advice as to how I might construct these ucs's?
John C

seant61
2008-11-04, 12:27 AM
I don’t have a real good visual of what it is that you need to accomplish but will venture to say that a smattering of vector cross product, along with a good helping of ThisDrawing.Utility.TranslateCoordinates would do the trick.

If you post an example of a polyline, and where you’d like to see the UCS oriented, I’ll try my hand at a routine.

coondog45
2008-11-04, 10:36 AM
Thanks for the tips sean,
Let me explain what I am doing. I am working with civil 3D and would like to create a UCS every 100 ft along a roadway alignment. I can get the cords of these points with station offset methods of the alignment object. After I set up the UCS I make each one active and insert a raster cross-section drawing that is scaled correctly. I can the create points for surface creation etc. It is a way of digitizing the cross sections on the computer screen. It works like a charm but creating thousands of UCS's by keystrokes is a chore. I can get point cords for each station and a station a few feet before the origin station. the vector beterrn these points would be the positive z -axis. Maybe using some form of transforming proceedure could rotate the x any axis as needed. I use the Z-axies function in the ucs contex menu to do this manualy.
Thanks for any advice you might have.
John C

seant61
2008-11-04, 01:20 PM
Unfortunately, I don’t have time to do thorough testing right now but this routine may be headed in the right direction.


Option Explicit

Sub TestUCS() 'Test routine

Dim dblPt1() As Double
Dim dblPt2() As Double
Dim objUCSTest As AcadUCS

dblPt1 = ThisDrawing.Utility.GetPoint(, "Get first pt.")
dblPt2 = ThisDrawing.Utility.GetPoint(dblPt1, "Get second pt.")
Set objUCSTest = UCSFromZVector(dblPt1, dblPt2, "TempUCS1")
End Sub

Function UCSFromZVector(dblOrigin() As Double, dblPtAtPosZ() As Double, strUCSName As String) As AcadUCS 'Primary function

Dim dblWCSZ(0 To 2) As Double
Dim dblNewZ() As Double
Dim dblNewX() As Double
Dim dblNewY() As Double
Dim dblTempOR(0 To 2) As Double 'temporary origin at 0,0,0
Dim objUCS As AcadUCS

dblWCSZ(2) = 1#
dblNewZ = VectorFrom2PtsST(dblOrigin, dblPtAtPosZ)
If Not IsVectorZero(dblNewZ) Then
dblNewZ = NormalizeST(dblNewZ)
If dblNewZ(2) <> Round(1#, 6) Then
dblNewX = VectorCrossST(dblWCSZ, dblNewZ)
dblNewY = VectorCrossST(dblNewZ, dblNewX)
Set objUCS = ThisDrawing.UserCoordinateSystems.Add( _
dblTempOR, _
dblNewX, _
dblNewY, _
strUCSName)
objUCS.Origin = dblOrigin
Set UCSFromZVector = objUCS
ThisDrawing.ActiveUCS = objUCS
End If
End If

End Function

Function VectorFrom2PtsST(dbl1stPt() As Double, dbl2ndPt() As Double) As Double()
Dim dblDummy(0 To 2) As Double
dblDummy(0) = dbl2ndPt(0) - dbl1stPt(0)
dblDummy(1) = dbl2ndPt(1) - dbl1stPt(1)
dblDummy(2) = dbl2ndPt(2) - dbl1stPt(2)
VectorFrom2PtsST = dblDummy
End Function

Public Function VectorCrossST(dblVect1() As Double, dblVect2() As Double) As Double()
Dim dblDummy(0 To 2) As Double
dblDummy(0) = dblVect1(1) * dblVect2(2) - dblVect1(2) * dblVect2(1)
dblDummy(1) = dblVect1(2) * dblVect2(0) - dblVect1(0) * dblVect2(2)
dblDummy(2) = dblVect1(0) * dblVect2(1) - dblVect1(1) * dblVect2(0)
VectorCrossST = dblDummy
End Function

Function NormalizeST(dblVect() As Double) As Double()
Dim dblMag As Double
If Not IsVectorZero(dblVect, 6) Then
dblMag = (dblVect(0) ^ 2 + dblVect(1) ^ 2 + dblVect(2) ^ 2) ^ 0.5
dblVect(0) = dblVect(0) / dblMag
dblVect(1) = dblVect(1) / dblMag
dblVect(2) = dblVect(2) / dblMag
End If
NormalizeST = dblVect
End Function

Function IsVectorZero(dblVector() As Double, Optional lngPrecision As Long = 6) As Boolean
IsVectorZero = False
If Round(dblVector(2), lngPrecision) <> 0# Then Exit Function
If Round(dblVector(1), lngPrecision) <> 0# Then Exit Function
If Round(dblVector(0), lngPrecision) <> 0# Then Exit Function
IsVectorZero = True
End Function

coondog45
2008-11-04, 03:03 PM
Thanks a lot.
I will work with it a little and let you know how it works.
John C

MikeJarosz
2008-11-04, 05:34 PM
Hope you're up on vector arithmetic. I had to get "linear algebra demystified" for a 3D solar energy project a couple of years ago. I still can't understand why Autodesk had to make the z axis a vector. Why not just a cartesian x,y,z coordinate?

I posted my problem on AUGI and Sean came to the rescue. Ultimately, I wrote dot product and cross product functions in Excel and did most of my analysis in a spreadsheet.

I understand your problem. I did an airport terminal years back that was a giant semi circle. Each part plan had to have the radius pointing straight up on the sheet. We had hundreds of coordinate systems. It was in release 12 and we didn't have VBA nor did we have anybody who knew LISP. We did it manually. :cry::cry:

seant61
2008-11-04, 11:12 PM
I understand your problem. I did an airport terminal years back that was a giant semi circle. Each part plan had to have the radius pointing straight up on the sheet. We had hundreds of coordinate systems. It was in release 12 and we didn't have VBA nor did we have anybody who knew LISP. We did it manually. :cry::cry:


That sounds like a recipe for Carpal Tunnel.

Hi Mike, it’s been a while. How did the Solar energy project turn out? With the way energy prices were climbing this past summer, programmers with that type of background must be in high demand.

I believe you mentioned an intent switch focus more towards .NET for AutoCAD customization. I, too, have devoted resources in that direction and finally feel like the investment is paying back.

I was pleasantly surprised at how comprehensive AutoCAD’s .NET API was with regard to Vector and Matrix manipulation. Most (if not all) of the functions needed for projects such as yours and John's here are already there for the taking.

John, the vba routine posted above is setup with WCS polylines in mind. If the polyline are not coplanar to the WCS, or are 3dPolylines, then some additional tweaking would be required.

MikeJarosz
2008-11-05, 05:16 PM
AUGI users don't post enough pictures. So here's one for y'all.

The center of the circle is in the parking ramp. The right hand of the picture is incomplete. The final phase of the project will create one more pier.

Try and get that building on paper in Acad!

B_Roche
2008-11-07, 01:24 AM
[QUOTE=MikeJarosz;907138]I still can't understand why Autodesk had to make the z axis a vector. Why not just a cartesian x,y,z coordinate?
QUOTE]

Because its not needed, and its one more way to get a *slight* round off error somewhere, that will make the entire thing not mathematically possible. Once you have your XY, you have your plane, so your Z axis is just a direction normal to that plane - hell, the z could be a *boolean*.

seant61
2008-11-07, 10:53 AM
I believe the comment was intended in the context of AutoCAD’s Object Coordinate System. And I think the second sentence of that quote references the dance one has to perform to get a WCS coordinate from an OCS coordinate, Normal, and Elevation.

coondog45
2008-11-14, 11:45 AM
Unfortunately, I don’t have time to do thorough testing right now but this routine may be headed in the right direction.


Option Explicit

Sub TestUCS() 'Test routine

Dim dblPt1() As Double
Dim dblPt2() As Double
Dim objUCSTest As AcadUCS

dblPt1 = ThisDrawing.Utility.GetPoint(, "Get first pt.")
dblPt2 = ThisDrawing.Utility.GetPoint(dblPt1, "Get second pt.")
Set objUCSTest = UCSFromZVector(dblPt1, dblPt2, "TempUCS1")
End Sub

Function UCSFromZVector(dblOrigin() As Double, dblPtAtPosZ() As Double, strUCSName As String) As AcadUCS 'Primary function

Dim dblWCSZ(0 To 2) As Double
Dim dblNewZ() As Double
Dim dblNewX() As Double
Dim dblNewY() As Double
Dim dblTempOR(0 To 2) As Double 'temporary origin at 0,0,0
Dim objUCS As AcadUCS

dblWCSZ(2) = 1#
dblNewZ = VectorFrom2PtsST(dblOrigin, dblPtAtPosZ)
If Not IsVectorZero(dblNewZ) Then
dblNewZ = NormalizeST(dblNewZ)
If dblNewZ(2) <> Round(1#, 6) Then
dblNewX = VectorCrossST(dblWCSZ, dblNewZ)
dblNewY = VectorCrossST(dblNewZ, dblNewX)
Set objUCS = ThisDrawing.UserCoordinateSystems.Add( _
dblTempOR, _
dblNewX, _
dblNewY, _
strUCSName)
objUCS.Origin = dblOrigin
Set UCSFromZVector = objUCS
ThisDrawing.ActiveUCS = objUCS
End If
End If

End Function

Function VectorFrom2PtsST(dbl1stPt() As Double, dbl2ndPt() As Double) As Double()
Dim dblDummy(0 To 2) As Double
dblDummy(0) = dbl2ndPt(0) - dbl1stPt(0)
dblDummy(1) = dbl2ndPt(1) - dbl1stPt(1)
dblDummy(2) = dbl2ndPt(2) - dbl1stPt(2)
VectorFrom2PtsST = dblDummy
End Function

Public Function VectorCrossST(dblVect1() As Double, dblVect2() As Double) As Double()
Dim dblDummy(0 To 2) As Double
dblDummy(0) = dblVect1(1) * dblVect2(2) - dblVect1(2) * dblVect2(1)
dblDummy(1) = dblVect1(2) * dblVect2(0) - dblVect1(0) * dblVect2(2)
dblDummy(2) = dblVect1(0) * dblVect2(1) - dblVect1(1) * dblVect2(0)
VectorCrossST = dblDummy
End Function

Function NormalizeST(dblVect() As Double) As Double()
Dim dblMag As Double
If Not IsVectorZero(dblVect, 6) Then
dblMag = (dblVect(0) ^ 2 + dblVect(1) ^ 2 + dblVect(2) ^ 2) ^ 0.5
dblVect(0) = dblVect(0) / dblMag
dblVect(1) = dblVect(1) / dblMag
dblVect(2) = dblVect(2) / dblMag
End If
NormalizeST = dblVect
End Function

Function IsVectorZero(dblVector() As Double, Optional lngPrecision As Long = 6) As Boolean
IsVectorZero = False
If Round(dblVector(2), lngPrecision) <> 0# Then Exit Function
If Round(dblVector(1), lngPrecision) <> 0# Then Exit Function
If Round(dblVector(0), lngPrecision) <> 0# Then Exit Function
IsVectorZero = True
End Function

Sean,
I have had good success with my USC creation code thanks to your help. On the first few trials I was getting the new UCS with completely inverse semetry than expected. (X axis to left , and positive z going away from the direction of stationing. After a few manipulations of the WCS unit vector that I used to perform the first cross product function with I was able to straighten it out.
In your sample code you had set the 2nd(Z) component of the WCS vector to 1 and left the o and 1 component to reset to zero. I was able to get the desired orentation with the following values for the WCS unit vector.'new x vector is Cross Product of new z and wcs z
dblWCSZ(2) = 0#
dblWCSZ(1) = 1#
dblWCSZ(0) = 1#
I am not quite sure why it is working this way. Would it make sense that you would set the component of the known new vector(in this case Z) to zero in the unit WCS vector to perform the initioal cross product multiplication? Is this a way to insure that the resulting product would be one axis other than the already known vector? I know there is some logic to this manipulation and I just want to write it down so I can remember it. If you have any additional info on this process I sure would like to look at it. Thanks for your help. This code will save me hundeds of hours on the keyboard I am sure.

seant61
2008-11-14, 09:01 PM
It sounds like your initial trials had an order of operation different from what I was anticipating.

First thing I should say is that I generally do a poor job of commenting code. If this were a few more weeks down the road, I’d even have a tough time figuring out why I did what.

To clear up my intentions, bear with me if they seem obvious:

dblWCSZ is an array of doubles to serve as a premade WCS Z axis, hence the setting 0,0,1.

dblNewZ (generated by the two pick points) was intended to be a vector that describes the new UCS’s Z axis. The first pick point acting as the UCS’s origin, the second as a point in the positive Z direction. Assigning the two points in the opposite order would create that inversion you mentioned.

The Cross Product function will return a vector mutually perpendicular to the two input vectors. The Function follows the ‘Right Hand Rule” (web search for more info) so here too an order of operation is important.

Now the setup:
dblWCSZ(2) = 0#
dblWCSZ(1) = 1#
dblWCSZ(0) = 1#

may very well work with a order of op. different from what I had anticipated, but I’d be weary of such a change lest it not work at some as of yet tried orientation.

coondog45
2008-11-14, 09:28 PM
Ok Sean Good discription of the purpose of the premade Wcs Z vector. I think I understand it now. Even though it is working correctly I think I will tweak it a bit so it will work with the intended sequence of point picks. Thanks for your explaination.