Message 1 of 25
		
    
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hello!
I want to create an outermost border for curves in a selection, some work well and some polylines don't. I've tried everything but can't fix it, hope you can help me fix it 
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.BoundaryRepresentation
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.Runtime
Imports CadDb = Autodesk.AutoCAD.DatabaseServices
Public Module M_Boundary
    Public Class OutLiner
        Private _dwg As Document
        Public Sub New(dwg As Document)
            _dwg = dwg
        End Sub
        Public Sub DrawOutline(entIds As IEnumerable(Of ObjectId))
            Using polyline = GetOutline(entIds)
                Using tran = _dwg.TransactionManager.StartTransaction()
                    Dim space = DirectCast(tran.GetObject(_dwg.Database.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)
                    space.AppendEntity(TryCast(polyline, Entity))
                    tran.AddNewlyCreatedDBObject(TryCast(polyline, Entity), True)
                    tran.Commit()
                End Using
            End Using
        End Sub
        Public Function GetOutline(entIds As IEnumerable(Of ObjectId)) As Entity
            Dim regions = New List(Of Region)()
            Using tran = _dwg.TransactionManager.StartTransaction()
                For Each entId In entIds
                    Dim entity = TryCast(tran.GetObject(entId, OpenMode.ForRead), Entity)
                    If entity IsNot Nothing Then
                        Dim entityRegion As List(Of Region) = Nothing
                        Select Case entity.GetType()
                            Case GetType(Polyline)
                                entityRegion = GetRegionFromPolyline(TryCast(entity, Polyline))
                            Case GetType(Circle)
                                entityRegion = GetRegionFromCircle(TryCast(entity, Circle))
                            Case GetType(Arc)
                                entityRegion = GetRegionFromArc(TryCast(entity, Arc))
                            Case GetType(Ellipse)
                                entityRegion = GetRegionFromEllipse(TryCast(entity, Ellipse))
                            Case GetType(Line)
                                entityRegion = GetRegionFromLine(TryCast(entity, Line))
                            Case Else
                                ' Unsupported type
                                Continue For
                        End Select
                        If entityRegion IsNot Nothing Then
                            regions.AddRange(entityRegion)
                        End If
                    End If
                Next
                tran.Commit()
            End Using
            Using region = MergeRegions(regions)
                If region IsNot Nothing Then
                    Dim brep = New Brep(region)
                    Dim points = New List(Of Point2d)()
                    Dim faceCount = brep.Faces.Count()
                    Dim face = brep.Faces.First()
                    For Each iloop In face.Loops
                        If iloop.LoopType = LoopType.LoopExterior Then
                            For Each vertex In iloop.Vertices
                                points.Add(New Point2d(vertex.Point.X, vertex.Point.Y))
                            Next
                            Exit For
                        End If
                    Next
                    Return CreatePolyline(points)
                Else
                    Return Nothing
                End If
            End Using
        End Function
        'Private Function GetRegionFromPolyline(poly As CadDb.Polyline) As List(Of Region)
        '    Return GetRegionFromCurve(poly)
        'End Function
        Private Function GetRegionFromPolyline(poly As CadDb.Polyline) As List(Of Region)
            Dim regions = New List(Of Region)()
            Dim sourceCol = New DBObjectCollection()
            ' Create a list of all points in the polyline
            Dim points = New List(Of Point3d)()
            For i = 0 To poly.NumberOfVertices - 1
                points.Add(poly.GetPoint3dAt(i))
            Next
            ' Calculate the centroid of points
            Dim centroid = New Point3d(points.Average(Function(p) p.X), points.Average(Function(p) p.Y), points.Average(Function(p) p.Z))
            ' Sort points by angle
            points.Sort(Function(p1, p2) Math.Atan2(p1.Y - centroid.Y, p1.X - centroid.X).CompareTo(Math.Atan2(p2.Y - centroid.Y, p2.X - centroid.X)))
            ' Create a new closed polyline from the sorted points
            Dim sortedPoly = New CadDb.Polyline()
            For i As Integer = 0 To points.Count - 1
                sortedPoly.AddVertexAt(i, New Point2d(points(i).X, points(i).Y), 0, 0, 0)
            Next
            sortedPoly.Closed = True
            ' Add the polyline to the source collection
            sourceCol.Add(sortedPoly)
            ' Create regions from the source collection
            Dim dbObjs = Region.CreateFromCurves(sourceCol)
            For Each obj In dbObjs
                If TypeOf obj Is Region Then regions.Add(TryCast(obj, Region))
            Next
            Return regions
        End Function
        Public Function GetRegionFromCircle(circle As CadDb.Circle) As List(Of Region)
            Dim regions = New List(Of Region)()
            Dim sourceCol = New DBObjectCollection()
            Dim dbObj = New CadDb.Polyline()
            Dim numPoints As Integer = 100 ' increase this for higher precision
            For i = 0 To numPoints
                Dim param = 2 * Math.PI * i / numPoints
                Dim point = New Point2d(circle.Center.X + circle.Radius * Math.Cos(param), circle.Center.Y + circle.Radius * Math.Sin(param))
                dbObj.AddVertexAt(i, point, 0.0, 0.3, 0.3)
            Next
            dbObj.Closed = True
            sourceCol.Add(dbObj)
            Dim dbObjs = Region.CreateFromCurves(sourceCol)
            For Each obj In dbObjs
                If TypeOf obj Is Region Then regions.Add(TryCast(obj, Region))
            Next
            Return regions
        End Function
        Public Function GetRegionFromLine(line As CadDb.Line) As List(Of Region)
            Dim regions = New List(Of Region)()
            Dim sourceCol = New DBObjectCollection()
            ' Create a parallel line
            Dim offsetVector = (line.EndPoint - line.StartPoint).RotateBy(Math.PI / 2, New Vector3d(0, 0, 1)) * 0.1
            Dim parallelLine = DirectCast(line.GetOffsetCurves(offsetVector.Length)(0), CadDb.Line)
            ' Create a polyline from the two lines
            Dim poly = New CadDb.Polyline()
            poly.AddVertexAt(0, New Point2d(line.StartPoint.X, line.StartPoint.Y), 0.0, 0.3, 0.3)
            poly.AddVertexAt(1, New Point2d(line.EndPoint.X, line.EndPoint.Y), 0.0, 0.3, 0.3)
            poly.AddVertexAt(2, New Point2d(parallelLine.EndPoint.X, parallelLine.EndPoint.Y), 0.0, 0.3, 0.3)
            poly.AddVertexAt(3, New Point2d(parallelLine.StartPoint.X, parallelLine.StartPoint.Y), 0.0, 0.3, 0.3)
            poly.Closed = True
            sourceCol.Add(poly)
            Dim dbObjs = Region.CreateFromCurves(sourceCol)
            For Each obj In dbObjs
                If TypeOf obj Is Region Then regions.Add(TryCast(obj, Region))
            Next
            Return regions
        End Function
        Private Function GetRegionFromEllipse(ellipse As CadDb.Ellipse) As List(Of Region)
            Dim regions = New List(Of Region)()
            Using tran = _dwg.TransactionManager.StartTransaction()
                Dim tempEllipse = ellipse.Clone()
                tempEllipse.TransformBy(Matrix3d.Displacement(ellipse.Center.GetVectorTo(Point3d.Origin)))
                tran.AddNewlyCreatedDBObject(tempEllipse, True)
                Dim outlineId = tempEllipse.GetOffsetCurves(0.001)(0)
                Dim outline = tran.GetObject(outlineId, OpenMode.ForWrite)
                tran.AddNewlyCreatedDBObject(outline, True)
                If TypeOf outline Is CadDb.Polyline Then
                    regions.AddRange(GetRegionFromPolyline(TryCast(outline, CadDb.Polyline)))
                ElseIf TypeOf outline Is CadDb.Arc Then
                    regions.AddRange(GetRegionFromArc(TryCast(outline, CadDb.Arc)))
                End If
                outline.Erase()
                tempEllipse.Erase()
                tran.Commit()
            End Using
            Return regions
        End Function
        Public Function GetRegionFromArc(arc As CadDb.Arc) As List(Of Region)
            Dim regions = New List(Of Region)()
            Dim sourceCol = New DBObjectCollection()
            Dim dbObj = New CadDb.Polyline()
            Dim numPoints As Integer = 100 ' increase this for higher precision
            For i = 0 To numPoints
                Dim param = arc.StartAngle + (arc.EndAngle - arc.StartAngle) * i / numPoints
                Dim point = New Point2d(arc.Center.X + arc.Radius * Math.Cos(param), arc.Center.Y + arc.Radius * Math.Sin(param))
                dbObj.AddVertexAt(i, point, 0.0, 0.3, 0.3)
            Next
            dbObj.AddVertexAt(numPoints + 1, New Point2d(arc.Center.X, arc.Center.Y), 0.0, 0.3, 0.3) ' add center point
            dbObj.Closed = True
            sourceCol.Add(dbObj)
            Dim dbObjs = Region.CreateFromCurves(sourceCol)
            For Each obj In dbObjs
                If TypeOf obj Is Region Then regions.Add(TryCast(obj, Region))
            Next
            Return regions
        End Function
        Private Function GetRegionFromCurve(curve As CadDb.Curve) As List(Of Region)
            Dim regions = New List(Of Region)()
            Dim sourceCol = New DBObjectCollection()
            Dim dbObj = DirectCast(curve.Clone(), CadDb.Curve)
            sourceCol.Add(dbObj)
            Dim dbObjs = Region.CreateFromCurves(sourceCol)
            For Each obj In dbObjs
                If TypeOf obj Is Region Then regions.Add(TryCast(obj, Region))
            Next
            Return regions
        End Function
        Private Function MergeRegions(regions As List(Of Region)) As Region
            If regions.Count = 0 Then Return Nothing
            If regions.Count = 1 Then Return regions(0)
            Dim region = regions(0)
            For i = 1 To regions.Count - 1
                Dim rg = regions(i)
                region.BooleanOperation(BooleanOperationType.BoolUnite, rg)
                rg.Dispose()
            Next
            Return region
        End Function
        Private Function CreatePolyline(points As List(Of Point2d)) As CadDb.Polyline
            Dim poly = New CadDb.Polyline(points.Count())
            For i = 0 To points.Count - 1
                poly.AddVertexAt(i, points(i), 0.0, 0.1, 0.1)
            Next
            poly.SetDatabaseDefaults(_dwg.Database)
            poly.ColorIndex = 1
            poly.Closed = True
            Return poly
        End Function
    End Class
    <CommandMethod("Outline")>
    Public Sub RunMyCommand()
        Dim dwg = Application.DocumentManager.MdiActiveDocument
        Dim ed = dwg.Editor
        Try
            Dim ids = SelectEntities(ed)
            If ids IsNot Nothing Then
                Dim liner = New OutLiner(dwg)
                liner.DrawOutline(ids)
            Else
                ed.WriteMessage(vbLf & "*Cancel*")
            End If
        Catch ex As System.Exception
            ed.WriteMessage(vbLf & "Command failed:" & vbLf & "{0}", ex.Message)
            ed.WriteMessage(vbLf & "*Cancel*")
        End Try
    End Sub
    Private Function SelectEntities(ed As Editor) As ObjectId()
        ' Allow selection of all types of entities.
        Dim res = ed.GetSelection()
        If res.Status = PromptStatus.OK Then
            Return res.Value.GetObjectIds()
        Else
            Return Nothing
        End If
    End Function
End Module
Solved! Go to Solution.
 
             
		
			 
					
				
		
 
		
			 
 
					
				
		
 
		
			 
		
			