.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Rotate UCS to align with Polyline

11 REPLIES 11
SOLVED
Reply
Message 1 of 12
AlexSu
2776 Views, 11 Replies

Rotate UCS to align with Polyline

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.

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Tags (1)
11 REPLIES 11
Message 2 of 12
mcicognani
in reply to: AlexSu

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

Message 3 of 12
AlexSu
in reply to: mcicognani

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. 

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Message 4 of 12
mcicognani
in reply to: AlexSu

Sorry, you said you wanted the UCS aligned to the first segment...

Maybe you can keep the Polyline entity matrix as XY plane, and use the LineSegment2D (2D, not 3d) for origin and rotation angle.
Message 5 of 12
AlexSu
in reply to: mcicognani

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...

 

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Message 6 of 12
mcicognani
in reply to: AlexSu

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);   //????

 

 

Message 7 of 12
AlexSu
in reply to: mcicognani

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.

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Message 8 of 12
AlexSu
in reply to: mcicognani

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.

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Message 9 of 12
mcicognani
in reply to: AlexSu

the .Direction.Angle is member of a 2d linear entity or vector, in my example a LineSegmend2d, while you used a LineSegment3d.
If you have a 3d vector, you have to specify what angle you want specifyng the reference plane, of course.
Also in your code, you get a normal vector from a segment, but I guess this way, the plane is undefined... If you need the plane of the polyline, just use its Normal property.

When you say the angle returned is 'wrong', what you mean? The angle returned is always 'right'. If you want your Y axis goes, generally speaking, toward the top of your screen, you need to add more checks, and also involve the current view, since 'top' and 'bottom' of the screen are relative terms...
To simplify things, instead of asking for a segment, you may want to ask for a third point or entity, so that you may better define the plane the user wants to work on.
Message 10 of 12
AlexSu
in reply to: mcicognani

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.

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)
Message 11 of 12
_gile
in reply to: AlexSu

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);
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 12 of 12
AlexSu
in reply to: _gile

Thank you gile!

 

Your code snippet works! I will use it in my next project.

Regards,
Alex Su
Autodesk Autocad & Inventor 2012 Certified Pro
Autodesk Inventor 2012 Certified Instructor (ACI)
Autodesk Inventor 2012 Certification Evaluator (ACE)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost