Planar Face Transform
Originally Published inHere is another contribution by Joe Offord of Enclos ↗, who already shared valuable insights on accessing curtain wall geometry, speeding up the interactive selection process, mirroring in a new family and changing the active view.
Above all, he implements all his stuff in VB, so this is also something for you VB aficionados.
This time, Joe looks at a command that redraws a planar face’s edges in a drafting view. The issue is somewhat related to the discussion of polygon transformations.
However, instead of using rotations and translations, which can be difficult to determine in 3D, Joe wrote a utility function that re-maps the global coordinate system to the planar face’s coordinate system using vectors and origins.
The command prompts the user to select a planar face on an elements, creates a new drafting view, retrieves the edges of the selected face, and transforms them from the 3D space to the drafting view.
To test this, I selected the following slightly lopsided wall in 3D:
The command generated a new drafting view showing the wall profile edges like this:
Here is the Execute method implementation for the mainline of the command:
Public Function Execute( _
ByVal commandData As ExternalCommandData, _
ByRef message As String, _
ByVal elements As ElementSet) As Result Implements IExternalCommand.Execute
Dim uiapp As UIApplication = commandData.Application
Dim app As Application = uiapp.Application
Dim uidoc As UIDocument = uiapp.ActiveUIDocument
Dim doc As Document = uidoc.Document
Dim sel As Selection = uidoc.Selection
Try
Dim ref As Reference = sel.PickObject( _
ObjectType.Face, "Select a face")
Dim elem As Element = doc.GetElement(ref)
Dim gObj As GeometryObject _
= elem.GetGeometryObjectFromReference(ref)
Dim face As PlanarFace = TryCast(gObj, PlanarFace)
If face Is Nothing Then
MsgBox("Not a planar face")
End If
Dim v As ViewDrafting = Nothing
Dim tr As New Transaction(doc, "Draw Face")
tr.Start()
Try
v = doc.Create.NewViewDrafting 'create a new view
v.Scale = 48 '1/4" = 1'-0"
'this transform re-orients the global
'coordinate system to the face's coordinate system
Dim trans As Transform _
= Util.PlanarFaceTransform(face)
For Each eArr As EdgeArray In face.EdgeLoops
For Each e As Edge In eArr
Dim c As Curve = e.AsCurveFollowingFace(face)
c = c.Transformed(trans) 'orient the curve on the XY plane
doc.Create.NewDetailCurve(v, c) 'draw the curve
Next
Next
tr.Commit()
Catch ex As Exception
tr.RollBack()
MsgBox("Error: " + ex.Message)
End Try
If tr.GetStatus = TransactionStatus.Committed Then
uidoc.ActiveView = v
End If
Catch ex As Exception
MsgBox("Error: " + ex.Message)
End Try
Return Result.Succeeded
End Function
The transformation from the planar face coordinate system is created by the following two utility methods:
''' <summary>
''' Return a transform that changes a x,y,z
''' coordinate system to a new x',y',z' system
''' </summary>
Public Shared Function TransformByVectors( _
ByVal oldX As XYZ, _
ByVal oldY As XYZ, _
ByVal oldZ As XYZ, _
ByVal oldOrigin As XYZ, _
ByVal newX As XYZ, _
ByVal newY As XYZ, _
ByVal newZ As XYZ, _
ByVal newOrigin As XYZ) As Transform
' [new vector] = [transform]*[old vector]
' [3x1] = [3x4] * [4x1]
'
' [v'x] [ i*i' j*i' k*i' translationX' ] [vx]
' [v'y] = [ i*j' j*j' k*j' translationY' ] * [vy]
' [v'z] [ i*k' j*k' k*k' translationZ' ] [vz]
' [1 ]
Dim t As Transform = Transform.Identity
Dim xx As Double = oldX.DotProduct(newX)
Dim xy As Double = oldX.DotProduct(newY)
Dim xz As Double = oldX.DotProduct(newZ)
Dim yx As Double = oldY.DotProduct(newX)
Dim yy As Double = oldY.DotProduct(newY)
Dim yz As Double = oldY.DotProduct(newZ)
Dim zx As Double = oldZ.DotProduct(newX)
Dim zy As Double = oldZ.DotProduct(newY)
Dim zz As Double = oldZ.DotProduct(newZ)
t.BasisX = New XYZ(xx, xy, xz)
t.BasisY = New XYZ(yx, yy, yz)
t.BasisZ = New XYZ(zx, zy, zz)
' The movement of the origin point
' in the old coordinate system
Dim translation As XYZ = newOrigin - oldOrigin
' Convert the translation into coordinates
' in the new coordinate system
Dim translationNewX As Double _
= xx * translation.X _
+ yx * translation.Y _
+ zx * translation.Z
Dim translationNewY As Double _
= xy * translation.X _
+ yy * translation.Y _
+ zy * translation.Z
Dim translationNewZ As Double _
= xz * translation.X _
+ yz * translation.Y _
+ zz * translation.Z
t.Origin = New XYZ( _
-translationNewX, _
-translationNewY, _
-translationNewZ)
Return t
End Function
Public Shared Function PlanarFaceTransform( _
ByVal face As PlanarFace) As Transform
Return Util.TransformByVectors( _
XYZ.BasisX, _
XYZ.BasisY, _
XYZ.BasisZ, _
XYZ.Zero, _
face.Vector(0), _
face.Vector(1), _
face.Normal, _
face.Origin)
End Function
Here is PlanarFaceTransform.zip including the complete source code and Visual Studio solution of this command.
Many thanks to Joe for sharing this!