Hi All,
I am trying to rotate the current UCS to align with the first segment of a selected polyline. I did a previous version that converts the first line segment to a line object and align the UCS to it. Problem is, if the polyline was created on a rotated UCS by the user, then the UCS will not align correctly. Below is the code snippet of what I currently have
' Current AutoCAD document placeholder Dim ad_currentDwg As Autodesk.AutoCAD.ApplicationServices.Document ' Current AutoCAD document editor object placeholder Dim ed_currentEditor As Editor = Nothing ' Current AutoCAD document database object placeholder Dim db_currentDb As Database Dim m3d_userCoord As Matrix3d = Nothing Try ' Gets the currently active AutoCAD document ad_currentDwg = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument ' Gets the current document Editor object ed_currentEditor = ad_currentDwg.Editor ' Gets the current document Database object db_currentDb = ad_currentDwg.Database m3d_userCoord = ed_currentEditor.CurrentUserCoordinateSystem Dim peo_options As New PromptEntityOptions("Select polyline to align to") peo_options.SetRejectMessage("Selected entity must be a 2D polyline!" & vbNewLine) peo_options.AddAllowedClass(GetType(Polyline), True) Dim per_result As PromptEntityResult = ed_currentEditor.GetEntity(peo_options) If Not per_result.Status = PromptStatus.OK Then Exit Try ed_currentEditor.CurrentUserCoordinateSystem = Matrix3d.Identity ' Starts a transaction on the current document Database object Using t_currentTransaction As Transaction = db_currentDb.TransactionManager.StartTransaction ' Gets the current document block table object Dim bt_currentBT As BlockTable = t_currentTransaction.GetObject(db_currentDb.BlockTableId, OpenMode.ForRead) ' Gets the current document model space block table record object Dim btr_currentBTR As BlockTableRecord = t_currentTransaction.GetObject(bt_currentBT(BlockTableRecord.ModelSpace), OpenMode.ForRead) ' Your code(s) here . . . Dim pl_polyline As Polyline = t_currentTransaction.GetObject(per_result.ObjectId, OpenMode.ForRead) Dim c3d_sys As CoordinateSystem3d = ed_currentEditor.CurrentUserCoordinateSystem.CoordinateSystem3d ed_currentEditor.CurrentUserCoordinateSystem = Matrix3d.AlignCoordinateSystem(c3d_sys.Origin, c3d_sys.Xaxis, c3d_sys.Yaxis, c3d_sys.Zaxis, pl_polyline.StartPoint, pl_polyline.Ecs.CoordinateSystem3d.Xaxis, pl_polyline.Ecs.CoordinateSystem3d.Yaxis, pl_polyline.Ecs.CoordinateSystem3d.Zaxis) ' Append any pending objects here . . . ' Uncomment the line below to make changes to current block table record ' btr_currentBTR.UpgradeOpen() ' Writes changes to current document database object t_currentTransaction.Commit() End Using 'Ends Using t_transact Catch ex As Exception MessageBox.Show(ex.Message, "Unexpected Error!") Finally 'If Not ed_currentEditor Is Nothing Then ed_currentEditor.CurrentUserCoordinateSystem = m3d_userCoord End Try
The above code aligns the UCS to the rotated polyline XY plane, but the XAxis is not aligned with the vector of the first polyline segment.
So there're two things I need to know. How to figure out the angle from the first line segment to the current UCS XAxis, and to rotate the UCS using that angle using the current ZAxis as the rotation axis.
Thanks.
Edit: I also tried to rotate the UCS using the following code:
ed_currentEditor.CurrentUserCoordinateSystem = Matrix3d.Rotation( 90/180*Math.PI, pl_polyline.Ecs.CoordinateSystem3d.Zaxis, pl_polyline.StartPoint )
But the resulting UCS is not as I expected.
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Sorry for my incomplete and vague reply, but I have no VB code to show and I'm a little on the run, but just to give you a direction, that's what I'd do:
- There should be a GetEntity function that also return the point of selection other than the entity. Why this: you may want to identify the segment of the polyline and you cannot be sure which direction has the polyline, so you may want to discriminate the first from the last segment.
- iterate through the segments inside the polyline, using GetLineSegment2dAt(int vertex), and find the segment closer to the selection point
- the LineSegment2d has a direction and an angle you may want to use.
Alternatively you may retrieve a LineSegment3d, which has a matrix itself, if I don't remember wrong...
Sorry again, post written on the run and completely from memory, but I'm confident the path it's quite exact, I've done this kind of math many times...
Bye
Hi mcicognani,
Thanks for your reply. Yes I did try the GetLineSegment3dAt like you said and tried to align the UCS to the line segment and the XAzis did align to the line segment. But, there's a slight problem: the XY plane is not on the polyline, only the first line segment is.
Hi mcicognani,
Sorry, I have no idea how to use both Matrix3D and Matrix2D at the same time.
Could you kindly provide me with a code sample? I tried to use the following:
Dim pl_polyline As Polyline = t_currentTransaction.GetObject(per_result.ObjectId, OpenMode.ForRead) Dim ls3d_lineSeg As LineSegment3d = pl_polyline.GetLineSegmentAt(0) Dim v3d_lineVector As Vector3d = (ls3d_lineSeg.EndPoint - ls3d_lineSeg.StartPoint).GetNormal Dim c3d_polyLine As CoordinateSystem3d = pl_polyline.Ecs.CoordinateSystem3d Dim c3d_sys As CoordinateSystem3d = ed_currentEditor.CurrentUserCoordinateSystem.CoordinateSystem3d Dim dbl_angle As Double = c3d_polyLine.Xaxis.GetAngleTo(v3d_lineVector) Dim m3d_transform As Matrix3d = Matrix3d.AlignCoordinateSystem(c3d_sys.Origin, c3d_sys.Xaxis, c3d_sys.Yaxis, c3d_sys.Zaxis, pl_polyline.StartPoint, c3d_polyLine.Xaxis, c3d_polyLine.Yaxis, c3d_polyLine.Zaxis) ed_currentEditor.CurrentUserCoordinateSystem = Matrix3d.Rotation(dbl_angle, c3d_polyLine.Zaxis, c3d_polyLine.Origin).PreMultiplyBy(m3d_transform) c3d_sys = ed_currentEditor.CurrentUserCoordinateSystem.CoordinateSystem3d
But result is still not as I expected. I am out of ideas...
Hi Alex,
unfortunately I haven't still understood what the final result you want to accomplish.
So you have a polyline, I assume this polyline is planar, or not?
You want to select a segment and make this your X axis for a new UCS.
The Z axis should be normal to the polyline? Or what?
If my assumptions are correct, I'd try this: (sorry, still on the run, cannot test it myself until later...)
// let's assume p as our polyline and l as the LineSegment2d selected
// get matrix from Polyline using its normal
Matrix3d m = Matrix3d.PlaneToWorld(p.Normal);
// get translation vector from plane origin to our start point, maybe are coincident, I don't remember
Vector3d v = m.CoordinateSystem3d.Origin.GetVectorTo(p.StartPoint); // maybe it's null, maybe you need to reverse
Matrix3d mOrg = Matrix3d.Displacement(v);
// get rotation using linesegment angle (it lays on the polyline's plane)
Matrix3d mRot = Matrix3d.Rotation(l.Direction.Angle, p.Normal, p.StartPoint);
// do the chain transformation, not sure here, still running on memory 😞
Application.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem = m.PostMultiplyBy(mOrg).PostMultiplyBy(mRot); //????
Hi mcicognani,
Thank you for your reply. I tried your codes but I cant seem to find the l.Direction.Angle. I only have GetAngleTo(vector as Vector3d).
Yes, the result is as stated by your previious post. Attached is the drawing if it helps.
Once you open the drawing, the rotated UCS is what I'm after. And if you restore the UCS to World UCS, you will see that the Polyline was created on a rotated UCS on the x-axis.
Hi Mcicognani,
I finally got it to work using the codes below:
Dim pl_selected As Polyline = t_currentTransaction.GetObject(per_result.ObjectId, OpenMode.ForRead) Dim ls3d_firstSegment As LineSegment3d = pl_selected.GetLineSegmentAt(0) Dim c3d_polyCoord As CoordinateSystem3d = pl_selected.Ecs.CoordinateSystem3d Dim v3d_segVector As Vector3d = (ls3d_firstSegment.EndPoint - ls3d_firstSegment.StartPoint).GetNormal Dim dbl_angle As Double = v3d_segVector.GetAngleTo(c3d_polyCoord.Xaxis) Dim c3d_sys As CoordinateSystem3d = ed_currentEditor.CurrentUserCoordinateSystem.CoordinateSystem3d ed_currentEditor.CurrentUserCoordinateSystem = Matrix3d.AlignCoordinateSystem(c3d_sys.Origin, c3d_sys.Xaxis, c3d_sys.Yaxis, c3d_sys.Zaxis, ls3d_firstSegment.StartPoint, c3d_polyCoord.Zaxis, c3d_polyCoord.Yaxis, c3d_polyCoord.Xaxis). PreMultiplyBy(Matrix3d.Rotation(dbl_angle, c3d_polyCoord.Zaxis, ls3d_firstSegment.StartPoint))
And the attached drawing is the result I am after...
But there's a slight issue. If I reverse the polyline then the function "GetAngleTo" got me the wrong angle to rotate the UCS on. Any other functions that I can get the correct angle? Thanks.
Hi mcicognani,
Yeah, my mistake in usage of wording. The angle returned is correct, but it does not care if the direction of the angle is clockwise or counter clockwise from the axis specified. My final goal is to place a region at the end of the polyline to be swept using the polyline as the path.
Anyway the program seems to work now, all that's left is to test it. Thanks for your help.
Hi,
Here's a, may be, more self-explanatory way:
private Matrix3d GetPolylineCoordSystem(Polyline pline) { Point3d origin = pline.StartPoint; Vector3d zAxis = pline.Normal; Vector3d xAxis = origin.GetVectorTo(pline.GetPoint3dAt(1)); Vector3d yAxis = zAxis.CrossProduct(xAxis); return Matrix3d.AlignCoordinateSystem( Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis, origin, xAxis, yAxis, zAxis); }
Can't find what you're looking for? Ask the community or share your knowledge.