Hello
Some context to this issue.
I was having issues with the built in command below to export face to DXF.
ThisApplication.CommandManager.ControlDefinitions.Item("GeomToDXFCommand")
There is no way to specify the export version (See related posts on this below). This meant that the exported dxf would export with splines and would fail on import by other programs requiring the splines to be linearized.
iLogic/API: Provide an API for exporting a face to DXF (with options) - Autodesk Community
Setting the ACAD Version for Export Surface from Part to dxf File with the API - Autodesk Community
So, I have this rule that creates a dxf file from a selected face. It linearizes all the edges on a face and writes to a dxf file.
The problem I have is that it only works on horizontal faces, because the XY coordinates of the edge vertices are global and not transformed to the normal of the face selected.
How would I transform these points to give me the local XY coordinates from the face selected?
Sub Main() Dim oDoc As PartDocument = ThisDoc.Document Dim oCompDef = oDoc.ComponentDefinition Dim entity = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Select a Face") oDoc.SelectSet.Select(entity) Dim oFace As Face Dim oTG As TransientGeometry = ThisApplication.TransientGeometry Dim oPointCol As New List(Of Double()) Try oFace = ThisApplication.ActiveDocument.SelectSet.Item(1) Catch MsgBox("A face must be selected.") End Try oDoc.SelectSet.Clear 'Dim oSketch As PlanarSketch 'oSketch = oCompDef.Sketches.Add(oFace) 'oSketch.OriginPoint = oCompDef.WorkPoints.Item(1) ' Create a new file Dim strUserProfile As String = System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile) 'MessageBox.Show(strUserProfile, "Title") Dim fileName As String = strUserProfile & "\Downloads\FaceToDXFExample.dxf" Dim file As New System.IO.StreamWriter(fileName) SharedVariable("DXF_Data_Exists") = False ' Write DXF header file.WriteLine("0") file.WriteLine("SECTION") file.WriteLine("2") file.WriteLine("ENTITIES") For Each oEL As EdgeLoop In oFace.EdgeLoops For k = 1 To oEL.Edges.Count 'Each oEdge As Edge In oEL.Edges oEdge = oEL.Edges(k) oEdge_StopVertex = oEdge.StopVertex oEdge_StartVertex = oEdge.StartVertex oEdge_StopVertex_Coordinates = "X" & oEdge.StopVertex.Point.X & "Y" & oEdge.StopVertex.Point.Y oEdge_StartVertex_Coordinates = "X" & oEdge.StartVertex.Point.X & "Y" & oEdge.StartVertex.Point.Y ' Dim oHSet As HighlightSet = oDoc.CreateHighlightSet() ' oHSet.Color = ThisApplication.TransientObjects.CreateColor(185, 0, 0) 'Red ' oHSet.AddItem(oEdge) ' MessageBox.Show("Edge type is " & oEdge.GeometryType) ' oHSet.Clear() If k = 1 Then 'first line in loop If oEdge.GeometryType = CurveTypeEnum.kLineCurve Or oEdge.GeometryType = CurveTypeEnum.kLineSegmentCurve Then PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y,oTG,oSketch) PointCollection(oPointCol,oEdge_StopVertex.Point.X,oEdge_StopVertex.Point.Y,oTG,oSketch) Else CalculateEdgeStrokes(oEdge,oPointCol,oTG,oSketch) End If Else 'Line is not first line in loop If oEdge.GeometryType = CurveTypeEnum.kLineCurve Or oEdge.GeometryType = CurveTypeEnum.kLineSegmentCurve Then oPreviousEdge = oEL.Edges(k - 1) oPreviousEdge_StopVertex_Coordinates = "X" & oPreviousEdge.StopVertex.Point.X & "Y" & oPreviousEdge.StopVertex.Point.Y oPreviousEdge_StartVertex_Coordinates = "X" & oPreviousEdge.StartVertex.Point.X & "Y" & oPreviousEdge.StartVertex.Point.Y If oEdge_StartVertex_Coordinates = oPreviousEdge_StopVertex_Coordinates Or oEdge_StartVertex_Coordinates = oPreviousEdge_StartVertex_Coordinates 'Good the start of the current line shares the start or stop of the previous line PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y,oTG,oSketch) PointCollection(oPointCol,oEdge_StopVertex.Point.X,oEdge_StopVertex.Point.Y,oTG,oSketch) Else 'switch current line start/stop positions PointCollection(oPointCol,oEdge_StopVertex.Point.X,oEdge_StopVertex.Point.Y,oTG,oSketch) PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y,oTG,oSketch) End If Else CalculateEdgeStrokes(oEdge,oPointCol,oTG,oSketch) End If End If Next WritePointsToDXF(file, oPointCol) oPointCol.Clear Next 'MessageBox.Show("Point collection contains " & oPointCol.Count, "Title") 'For i As Integer = 0 To oPointCol.Count - 1 ' oPoint = oTG.CreatePoint2d(oPointCol(i)(0), oPointCol(i)(1)) ' oSketch.SketchPoints.Add(oPoint) ' MessageBox.Show("Point Added", "Title") 'Next ' Write DXF footer file.WriteLine("0") file.WriteLine("ENDSEC") file.WriteLine("0") file.WriteLine("EOF") ' Close the file file.Close() If SharedVariable("DXF_Data_Exists") = False Then System.IO.File.Delete(fileName) End If End Sub Sub PointCollection(oPointCol As List(Of Double()), X As Double, Y As Double, oTG As TransientGeometry,oSketch As PlanarSketch) If oPointCol.Count = 0 Then oPointCol.Add({X, Y }) ' oPoint = oTG.CreatePoint2d(X, Y) ' oSketch.SketchPoints.Add(oPoint) ' MessageBox.Show("Point Added", "Title") Else intLastIndex = oPointCol.Count - 1 If oPointCol(intLastIndex)(0) = X And oPointCol(intLastIndex)(1) = Y Then ' MessageBox.Show("Points are equal - will skip") oPointCol.Add({X, Y }) Else oPointCol.Add({X, Y }) ' oPoint = oTG.CreatePoint2d(X, Y) ' oSketch.SketchPoints.Add(oPoint) ' MessageBox.Show("Point Added", "Title") End If End If Logger.Debug("X: " & X & ", Y: " & Y) End Sub Sub CalculateEdgeStrokes(oEdge As Edge,oPointCol As List(Of Double()),oTG As TransientGeometry,oSketch As PlanarSketch) Dim lVertexCount As Long Dim lSegmentCount As Long Dim adVertexCoords() As Double = {} Dim alVertexIndices() As Integer = {} oEdge.CalculateStrokes(0.01, lVertexCount, lSegmentCount, adVertexCoords, alVertexIndices) j = 1 For i = 0 To adVertexCoords.Length -1 If j = 1 Then strCoord_X = adVertexCoords(i) Else If j = 2 Then strCoord_Y = adVertexCoords(i) Else If j = 3 Then strCoord_Z = adVertexCoords(i) PointCollection(oPointCol,strCoord_X,strCoord_Y,oTG,oSketch) j = 0 'reset the counter End If j = j + 1 Next End Sub Sub WritePointsToDXF(file As System.IO.StreamWriter, oPointCol As List(Of Double())) SharedVariable("DXF_Data_Exists") = True ' Write lines to file For i = 0 To oPointCol.Count - 2 file.WriteLine("0") file.WriteLine("LINE") file.WriteLine("8") file.WriteLine("0") file.WriteLine("10") file.WriteLine(oPointCol(i)(0)) file.WriteLine("20") file.WriteLine(oPointCol(i)(1)) file.WriteLine("11") file.WriteLine(oPointCol(i+1)(0)) file.WriteLine("21") file.WriteLine(oPointCol(i+1)(1)) Next ' Add the last line to close the shape file.WriteLine("0") file.WriteLine("LINE") file.WriteLine("8") file.WriteLine("0") file.WriteLine("10") file.WriteLine(oPointCol((oPointCol.Count - 1))(0)) file.WriteLine("20") file.WriteLine(oPointCol((oPointCol.Count - 1))(1)) file.WriteLine("11") file.WriteLine(oPointCol(0)(0)) file.WriteLine("21") File.WriteLine(oPointCol(0)(1)) End Sub
Solved! Go to Solution.
Solved by william. Go to Solution.
Ok, I have it now.
I used the Face.Evaluator.GetParamAtPoint() method.
Full working code below, might help someone else.
Sub Main() Dim oDoc As PartDocument = ThisDoc.Document Dim oCompDef = oDoc.ComponentDefinition Dim entity = ThisApplication.CommandManager.Pick(SelectionFilterEnum.kPartFaceFilter, "Select a Face") oDoc.SelectSet.Select(entity) Dim oFace As Face Dim oTG As TransientGeometry = ThisApplication.TransientGeometry Dim oPointCol As New List(Of Double()) Try oFace = ThisApplication.ActiveDocument.SelectSet.Item(1) Catch MsgBox("A face must be selected.") Exit Sub End Try oDoc.SelectSet.Clear ' Create a new file Dim strUserProfile As String = System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile) 'MessageBox.Show(strUserProfile, "Title") Dim fileName As String = strUserProfile & "\Downloads\FaceToDXFExample.dxf" Dim file As New System.IO.StreamWriter(fileName) SharedVariable("DXF_Data_Exists") = False SharedVariable("PosX") = 0 'Placeholder value SharedVariable("PosY") = 0 'Placeholder value DXFHeader(file) ExportFace(oFace, file) 'Add Text to the DXF file Call DXFAddText(file, "Text to add, line 1", SharedVariable("PosX"), SharedVariable("PosY")) Call DXFAddText(file, "Text to add, line 2", SharedVariable("PosX"), SharedVariable("PosY") - 5) DXFFooter(file,fileName) End Sub Sub CalculatePosX_PosY(oPointCol As List(Of Double())) 'Calculates the centroid of the dxf face by looking at all the vertices in the dxf Dim Array_X As New ArrayList Dim Array_Y As New ArrayList For i = 0 To oPointCol.Count - 1 Array_X.Add(oPointCol(i)(0)) Array_Y.Add(oPointCol(i)(1)) Next Array_X.Sort() Array_Y.Sort() minX = Array_X(0) maxX = Array_X(Array_X.Count-1) minY = Array_Y(0) maxY = Array_Y(Array_X.Count - 1) SharedVariable("PosX") = ((maxX - minX) / 2) + minX SharedVariable("PosY") = ((maxY - minY) / 2) + minY Array_X.Clear Array_Y.Clear End Sub Sub DXFHeader(file As System.IO.StreamWriter) ' Write DXF header file.WriteLine("0") file.WriteLine("SECTION") file.WriteLine("2") file.WriteLine("ENTITIES") End Sub Sub DXFFooter(file As System.IO.StreamWriter,fileName As String) ' Write DXF footer file.WriteLine("0") file.WriteLine("ENDSEC") file.WriteLine("0") file.WriteLine("EOF") ' Close the file file.Close() If SharedVariable("DXF_Data_Exists") = False Then 'dxf file was created but no line entities were written to it. Dispose of it System.IO.File.Delete(fileName) End If End Sub Sub DXFAddText(file As System.IO.StreamWriter, TextToAdd As String, PosX As Double, PosY As Double) file.WriteLine(" 0") file.WriteLine("TEXT") 'ENTITY TYPE file.WriteLine(" 8") file.WriteLine("0") 'LAYERNAME file.WriteLine("100") file.WriteLine("AcDbText") file.WriteLine("10") file.WriteLine(PosX) 'X COORDINATE file.WriteLine("20") file.WriteLine(PosY) 'Y COORDINATE file.WriteLine("30") file.WriteLine("0.0") ' Z COORDINATE file.WriteLine("40") file.WriteLine("3.55") 'TEXT HEIGHT file.WriteLine(" 1") file.WriteLine(TextToAdd) 'TEXT STRING file.WriteLine("100") file.WriteLine("AcDbText") 'TEXT STRING End Sub Sub ExportFace(oFace As Face, file As System.IO.StreamWriter) Dim oTG As TransientGeometry = ThisApplication.TransientGeometry Dim oPointCol As New List(Of Double()) For Each oEL As EdgeLoop In oFace.EdgeLoops For k = 1 To oEL.Edges.Count oEdge = oEL.Edges(k) oEdge_StopVertex = oEdge.StopVertex oEdge_StartVertex = oEdge.StartVertex oEdge_StopVertex_Coordinates = "X" & oEdge.StopVertex.Point.X & "Y" & oEdge.StopVertex.Point.Y & "Z" & oEdge.StopVertex.Point.Z oEdge_StartVertex_Coordinates = "X" & oEdge.StartVertex.Point.X & "Y" & oEdge.StartVertex.Point.Y & "Z" & oEdge.StartVertex.Point.Z If k = 1 Then 'first line in loop If oEdge.GeometryType = CurveTypeEnum.kLineCurve Or oEdge.GeometryType = CurveTypeEnum.kLineSegmentCurve Then 'edge is straight PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y, oEdge_StartVertex.Point.Z, oTG,oSketch,oFace) PointCollection(oPointCol,oEdge_StopVertex.Point.X,oEdge_StopVertex.Point.Y, oEdge_StopVertex.Point.Z, oTG,oSketch,oFace) Else 'Edge is curved, or spline, polyline, eclipse, ect CalculateEdgeStrokes(oEdge,oPointCol,oTG,oSketch,k,"","",oFace) End If Else 'Line is not first line in loop oPreviousEdge = oEL.Edges(k - 1) oPreviousEdge_StopVertex_Coordinates = "X" & oPreviousEdge.StopVertex.Point.X & "Y" & oPreviousEdge.StopVertex.Point.Y & "Z" & oPreviousEdge.StopVertex.Point.Z oPreviousEdge_StartVertex_Coordinates = "X" & oPreviousEdge.StartVertex.Point.X & "Y" & oPreviousEdge.StartVertex.Point.Y & "Z" & oPreviousEdge.StartVertex.Point.Z If oEdge.GeometryType = CurveTypeEnum.kLineCurve Or oEdge.GeometryType = CurveTypeEnum.kLineSegmentCurve Then 'edge is straight If oEdge_StartVertex_Coordinates = oPreviousEdge_StopVertex_Coordinates Or oEdge_StartVertex_Coordinates = oPreviousEdge_StartVertex_Coordinates 'Good the start of the current line shares the start or stop of the previous line PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y, oEdge_StartVertex.Point.Z, oTG,oSketch,oFace) PointCollection(oPointCol,oEdge_StopVertex.Point.X, oEdge_StopVertex.Point.Y, oEdge_StopVertex.Point.Z, oTG,oSketch,oFace) Else 'switch current line start/stop positions PointCollection(oPointCol,oEdge_StopVertex.Point.X, oEdge_StopVertex.Point.Y, oEdge_StopVertex.Point.Z, oTG,oSketch,oFace) PointCollection(oPointCol, oEdge_StartVertex.Point.X, oEdge_StartVertex.Point.Y, oEdge_StartVertex.Point.Z, oTG,oSketch,oFace) End If Else 'Edge is curved, or spline, polyline, eclipse, ect CalculateEdgeStrokes(oEdge,oPointCol,oTG,oSketch,k,oPreviousEdge_StartVertex_Coordinates,oPreviousEdge_StopVertex_Coordinates,oFace) End If End If Next If oEL.IsOuterEdgeLoop = True Then CalculatePosX_PosY(oPointCol) End If WritePointsToDXF(file, oPointCol) oPointCol.Clear Next End Sub Sub PointCollection(oPointCol As List(Of Double()), X As Double, Y As Double, Z As Double, oTG As TransientGeometry, oSketch As PlanarSketch,oFace As Face) Dim oEval As SurfaceEvaluator oEval = oFace.Evaluator ' Set the coordinate point where you want to get the corresponding ' parametric point on the face. This point should lie on the face. Dim adPoints(2) As Double adPoints(0) = X adPoints(1) = Y adPoints(2) = Z Dim adGuessParams() As Double = {} Dim adMaxDeviations() As Double = {} Dim adParams() As Double = {} Dim alngSolutionNatures() As SolutionNatureEnum = {} Call oEval.GetParamAtPoint(adPoints, adGuessParams, adMaxDeviations,adParams, alngSolutionNatures) 'MessageBox.Show("X: " & adParams(0) & ", Y: " & adParams(1)) oPointCol.Add({adParams(0) * 10, adParams(1) * 10}) 'Logger.Debug("X: " & adParams(0) * 10 & ", adParams(1) * 10: " & Y) End Sub Sub CalculateEdgeStrokes(oEdge As Edge, oPointCol As List(Of Double()), oTG As TransientGeometry, oSketch As PlanarSketch, k As Integer, oPreviousEdge_StartVertex_Coordinates As String, oPreviousEdge_StopVertex_Coordinates As String,oFace As Face) Dim oTempPointCol As New List(Of Double()) Dim lVertexCount As Long Dim lSegmentCount As Long Dim adVertexCoords() As Double = {} Dim alVertexIndices() As Integer = {} oEdge.CalculateStrokes(0.01, lVertexCount, lSegmentCount, adVertexCoords, alVertexIndices) j = 1 For i = 0 To adVertexCoords.Length -1 If j = 1 Then strCoord_X = adVertexCoords(i) Else If j = 2 Then strCoord_Y = adVertexCoords(i) Else If j = 3 Then strCoord_Z = adVertexCoords(i) oTempPointCol.Add({strCoord_X, strCoord_Y, strCoord_Z}) j = 0 'reset the counter End If j = j + 1 Next If k = 1 Then For i = 0 To oTempPointCol.Count - 1 PointCollection(oPointCol, oTempPointCol(i)(0), oTempPointCol(i)(1), oTempPointCol(i)(2), oTG, oSketch,oFace) Next Else strCurrentEdgeStartVertex = "X" & oTempPointCol(0)(0) & "Y" & oTempPointCol(0)(1) & "Z" & oTempPointCol(0)(2) If strCurrentEdgeStartVertex = oPreviousEdge_StartVertex_Coordinates Or strCurrentEdgeStartVertex = oPreviousEdge_StopVertex_Coordinates Then 'Good, the starting point of the current line is equal to either the start/end vertex of the previous line For i = 0 To oTempPointCol.Count - 1 PointCollection(oPointCol, oTempPointCol(i)(0), oTempPointCol(i)(1), oTempPointCol(i)(2), oTG, oSketch,oFace) Next Else For i = oTempPointCol.Count - 1 To 0 Step -1 PointCollection(oPointCol, oTempPointCol(i)(0), oTempPointCol(i)(1), oTempPointCol(i)(2), oTG, oSketch,oFace) Next End If End If oTempPointCol.Clear End Sub Sub WritePointsToDXF(file As System.IO.StreamWriter, oPointCol As List(Of Double())) SharedVariable("DXF_Data_Exists") = True ' Write lines to file For i = 0 To oPointCol.Count - 2 file.WriteLine("0") file.WriteLine("LINE") file.WriteLine("8") file.WriteLine("0") file.WriteLine("10") file.WriteLine(oPointCol(i)(0)) file.WriteLine("20") file.WriteLine(oPointCol(i)(1)) file.WriteLine("11") file.WriteLine(oPointCol(i+1)(0)) file.WriteLine("21") file.WriteLine(oPointCol(i+1)(1)) Next ' Add the last line to close the shape file.WriteLine("0") file.WriteLine("LINE") file.WriteLine("8") file.WriteLine("0") file.WriteLine("10") file.WriteLine(oPointCol((oPointCol.Count - 1))(0)) file.WriteLine("20") file.WriteLine(oPointCol((oPointCol.Count - 1))(1)) file.WriteLine("11") file.WriteLine(oPointCol(0)(0)) file.WriteLine("21") file.WriteLine(oPointCol(0)(1)) End Sub
Can't find what you're looking for? Ask the community or share your knowledge.