Hi,
I'm struggling with placing a cell along an arc in VBA.
I have a Complex Chain where I will place a cell along the whol chain with a fixed distance.
I have solved the rotation on the "Line" part of the chainm but having trouble with the arc.
The rotation is almost correct, but almost doesn't count :-)
Any one have a suggestion?
The code snippet for placing the cell:
Sub showLineElm(LinElm As ComplexStringElement) Dim elm As ElementEnumerator Dim aelm As ArcElement Dim lelm As LineElement Dim oPH As PropertyHandler Dim lastsegment As String Dim streng As String, streng1 As String Dim start As Point3d Dim skala As Point3d Dim oCell As CellElement Dim z As Integer Dim ant_cell As Double, distance As Double Dim vinkel As Double Dim mtrxRotation As Matrix3d skala.X = 1 skala.Y = 1 skala.z = 1 If LinElm.Type = msdElementTypeComplexString Then If LinElm.IsTraversableElement Then Set elm = LinElm.GetSubElements Do While elm.MoveNext
Select Case elm.Current.Type Case msdElementTypeLine Set lelm = elm.Current.AsLineElement lastsegment = "Segments[" & (lelm.VerticesCount - 2) & "]." Set oPH = CreatePropertyHandler(lelm) oPH.SelectByAccessString (lastsegment & "Start") start = oPH.GetValueAsPoint3d oPH.SelectByAccessString (lastsegment & "Direction") streng = oPH.GetValue vinkel = Degrees(CDbl(streng)) mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, CDbl(streng)) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) ActiveModelReference.AddElement oCell ant_cell = lelm.Length / 0.854 ant_cell = ant_cell \ 1 distance = 0 For z = 1 To ant_cell distance = distance + 0.854 If distance > lelm.Length Then Exit For End If start = lelm.PointAtDistance(distance) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) ActiveModelReference.AddElement oCell Next z
Case msdElementTypeArc Set aelm = elm.Current.AsArcElement Set oPH = CreatePropertyHandler(aelm) oPH.SelectByAccessString ("SweepAngle") vinkel = oPH.GetValue mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, vinkel) start = aelm.StartPoint Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) distance = 0 oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start) ActiveModelReference.AddElement oCell ant_cell = aelm.Length / 0.854 ant_cell = ant_cell \ 1 For z = 1 To ant_cell distance = distance + 0.854 If distance > aelm.Length Then Exit For End If start = aelm.PointAtDistance(distance) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start) ActiveModelReference.AddElement oCell Next z End Select Loop End If End IferrExit:End Sub 'showLineElm
Hi Finn,
please read and follow MicroStation Programming forum best practices and to share required information like what MicroStation version do you use. Also some example file would be nice.
Also please edit your post and use Insert > Insert Code tool to share your code in a proper form. Personally, long time ago I decided to don't read any code formatted as plain text, because it's ugly, hardly readable and time consuming.
Finn Mejding said:The rotation is almost correct
What does it mean. Why you don't provide better explanation?
Finn Mejding said:Any one have a suggestion?
Split your code into more functions with exactly specified responsibility (at least to process linear and arc elements). Approach "one function will do everything" always leads to dirty and buggy code.
Why do you use PropertyHandler object here? It's "the last chance" tool, but I am pretty sure to use it in any code processing elements is wrong. It's not only much slower than direct access to element properties, but I am also not quite sure about a precision of values returned.
With regards,
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
Finn Mejding said:ant_cell = lelm.Length / 0.854
In addition to Jan's comments, avoid using magic numbers...
Finn Mejding said:distance = distance + 0.854
... especially when those magic numbers are used plurally.
Prefer to use a symbolic constant. It will help you in 2 years time when you come to maintain or improve your code!
Const ALPHA_FACTOR As Double = 0.854 ... ant_cell = aelm.Length / ALPHA_FACTOR ... distance = distance + ALPHA_FACTOR
Finn Mejding said:
Sub showLineElm(LinElm As ComplexStringElement)
Your subroutine name is at odds with your comment! Comments wear out: they become disconnected from their object. Prefer to make the subroutine name tell its own story...
Sub CreateCellAtOffset (ByVal oTraversableElement As ComplexStringElement)
Regards, Jon Summers LA Solutions
Jan,
Thought I was OK by tagging the post with MicroStation V8i
My version is: 08.11.09.459 (SelectSeries 3).
This is what I mean by "Close, but no cigar", the blue ones are placed manually with the correct rotation, the black cells are drawn by my program.
The code:
Sub showLineElm(LinElm As ComplexStringElement) Dim elm As ElementEnumerator Dim aelm As ArcElement Dim lelm As LineElement Dim oPH As PropertyHandler Dim lastsegment As String Dim streng As String, streng1 As String Dim start As Point3d Dim skala As Point3d Dim oCell As CellElement Dim z As Integer Dim ant_cell As Double, distance As Double Dim vinkel As Double Dim mtrxRotation As Matrix3d skala.X = 1 skala.Y = 1 skala.z = 1 If LinElm.Type = msdElementTypeComplexString Then If LinElm.IsTraversableElement Then Set elm = LinElm.GetSubElements Do While elm.MoveNext Select Case elm.Current.Type Case msdElementTypeLine Set lelm = elm.Current.AsLineElement lastsegment = "Segments[" & (lelm.VerticesCount - 2) & "]." Set oPH = CreatePropertyHandler(lelm) oPH.SelectByAccessString (lastsegment & "Start") start = oPH.GetValueAsPoint3d oPH.SelectByAccessString (lastsegment & "Direction") streng = oPH.GetValue vinkel = Degrees(CDbl(streng)) mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, CDbl(streng)) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) ' oCell.GraphicGroup = ggNum ActiveModelReference.AddElement oCell ant_cell = lelm.Length / 0.854 ant_cell = ant_cell \ 1 distance = 0 For z = 1 To ant_cell distance = distance + 0.854 If distance > lelm.Length Then Exit For End If start = lelm.PointAtDistance(distance) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) ActiveModelReference.AddElement oCell Next z Case msdElementTypeArc Set aelm = elm.Current.AsArcElement Set oPH = CreatePropertyHandler(aelm) oPH.SelectByAccessString ("SweepAngle") vinkel = oPH.GetValue mtrxRotation = Matrix3dFromAxisAndRotationAngle(2, vinkel) start = aelm.StartPoint Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) ' oCell.GraphicGroup = ggNum distance = 0 oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start) ActiveModelReference.AddElement oCell ant_cell = aelm.Length / 0.854 ant_cell = ant_cell \ 1 For z = 1 To ant_cell distance = distance + 0.854 If distance > aelm.Length Then Exit For End If start = aelm.PointAtDistance(distance) Set oCell = CreateCellElement2("cellname", start, skala, True, mtrxRotation) oCell.Transform Transform3dFromMatrix3dAndFixedPoint3d(mtrxRotation, start) ActiveModelReference.AddElement oCell Next z End Select Loop End If End If errExit: End Sub 'showLineElm
The code is still "Work in Progress" and therefor not that pretty yet.
Regards,
Finn Mejding
CAD Manager
Railway and Metro
COWI
Finn Mejding said:Thought I was OK by tagging the post with MicroStation V8i
Ok, you did it, but it's not accordingly the forum best practices, so a probability anybody will check tags in the first place is close to zero in my opinion.
As defined in the article I linked, the version and language should be noted in subject like "[V8i VBA] Rotation and transformation matrix" and it's what frequent visitors of this group expect, not tags.
Finn Mejding said:The code is still "Work in Progress" and therefor not that pretty yet.
In my opinion (but it's really subjective personal ;-) "the code prettiness" is a way how to write code quickly and efficiently, not the final state how code looks like when it's finished.
What about my question about PropertyHandlers, this is something I recommend to remove in the first step (or to argue why this non standard construction is needed).
Finn Mejding said:I'm struggling with placing a cell along an arc in VBA
Here's an example VBA project that may help...
It probably doesn't do exactly what you want, but it's a good place to start. The startling bit is probably the use of a B-Spline curve to help calculate point-at-a-distance and tangent-at-a-distance for each cell placement.
Answer Verified By: Finn Mejding
I'm not here to question your coding...Are you trying to create a tool that will do just this for you, or is it a part of a larger workflow you are trying to automate?
MaryB
Power GeoPak 08.11.09.918Power InRoads 08.11.09.918OpenRoads Designer 2021 R2
MaryB,
This will be part of a toolbox do different automated processes.
Bu I guess I will use this as a "motor" for many of the tools. Ex. placing Sleepers along an alignment.
Thanks Jon, that really helpme.
I have the rotation matrix in place now, just need to fit the numger of cells.