My apps design is split into 3 major sections.
1] The top section gets persisted and holds simple parameters that define the sub assemblies in a Building Model.
2] The middle section creates, moves, deletes, etc, my objects based on project parameters, These objects are contained in generic lists. It boils down to just lists of solids, polylines, lines, tables, and mtexts.
3] The last section is just a few methods to open up transactions and iterate the generic lists and have Acad do work.
This scheme works quite well until the model gets bigger, On a 2 year old box with 1G Ram and a $100 NVidia card it takes about 7-10 seconds to create ~500 solids.
When I profile I see that 95% of the time is spent in just 1 method [3] ...example below
What I am thinking about doing is getting few these methods [3] that interface to Acad in their own native class and wrap it and call it from my managed code in the hopes that Native Arx is quicker than Net Arx.
This would be a big learning curve for unkown benefit if any, Any thoughts are appreciated
Friend Shared Sub DrawEntities()
Dim db As AcDb.Database = AcDb.HostApplicationServices.WorkingDatabase
Dim tr As AcDb.Transaction = db.TransactionManager.StartTransaction()
Dim dl As AcAs.DocumentLock = AcAp.DocumentManager.MdiActiveDocument.LockDocument()
Dim bt As AcDb.BlockTable = DirectCast(tr.GetObject(db.BlockTableId, _
AcDb.OpenMode.ForWrite, True), AcDb.BlockTable)
Dim br As AcDb.BlockTableRecord = DirectCast(tr.GetObject(bt(AcDb.BlockTableRecord.ModelSpace), _
AcDb.OpenMode.ForWrite, False), AcDb.BlockTableRecord)
For Each Line As AcDbLine In Lines
If Not Line.ID.Exists Then
'Create AcDb Entity
Dim en As New AcDb.Line(New AcGe.Point3d(0, 0, 0), New AcGe.Point3d(5, 0, 0))
en.Color = AcCm.Color.FromColor(Line.Color)
'Rotate Around Z Axis
en.TransformBy(AcGe.Matrix3d.Rotation(Rad(Line.Rotation), _
New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
'Move in ModelSpace
Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
Line.Origin.X + (Math.Cos(Rad(Line.Angle)) * Line.Position.X), _
Line.Origin.Y - (Math.Sin(Rad(Line.Angle)) * Line.Position.X), _
Line.Position.Z))
en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
'Add Entity to AcDb
br.AppendEntity(en)
tr.AddNewlyCreatedDBObject(en, True)
'Update FwHr Entity
Line.ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
Line.ID.Exists = True
End If
Next
For i As Integer = 0 To PolyLines.Count - 1
If Not PolyLines(i).ID.Exists Then
'Create AcDb Entity
Dim PointCol As New AcGe.Point3dCollection
For j As Integer = 0 To PolyLines(i).Points.Count - 1
PointCol.Add(New AcGe.Point3d(PolyLines(i).Points(j).XYZ))
Next
Dim en As New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, PointCol, True)
en.Visible = PolyLines(i).IsVisible
en.Color = AcCm.Color.FromColor(PolyLines(i).Color)
Select Case PolyLines(i).IsOnWCS
'Baselines are drawn in the WCS so they don't move and rotate
Case False
'Rotate Around Z Axis
en.TransformBy(AcGe.Matrix3d.Rotation(Rad(PolyLines(i).Rotation), _
New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
'Move in ModelSpace
Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
PolyLines(i).Origin.X + (Cos(Rad(PolyLines(i).Angle)) * PolyLines(i).Position.X), _
PolyLines(i).Origin.Y - (Sin(Rad(PolyLines(i).Angle)) * PolyLines(i).Position.X), _
PolyLines(i).Position.Z))
en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
en.List()
End Select
'Add Entity to AcDb
br.AppendEntity(en)
tr.AddNewlyCreatedDBObject(en, True)
'Update FwHr Entity
PolyLines(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
PolyLines(i).ID.Exists = True
End If
Next
For i As Integer = 0 To Solids.Count - 1
If Not Solids(i).ID.Exists Then
Dim en As AcDb.Solid3d = Nothing
Dim BasePointCol As New AcGe.Point3dCollection
For j As Integer = 0 To Solids(i).Points.Count - 1
BasePointCol.Add(New AcGe.Point3d(Solids(i).Points(j).XYZ))
Next
Dim Polyline3d As AcDb.Polyline3d = New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, BasePointCol, True)
'Create Region
Dim ColPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
Dim ColRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
ColPoly.Add(Polyline3d)
ColRegion = AcDb.Region.CreateFromCurves(ColPoly)
Dim Region As AcDb.Region = DirectCast(ColRegion(0), AcDb.Region)
ColPoly.Dispose()
ColRegion.Dispose()
Polyline3d.Dispose()
'Create AcDb Entity
en = New AcDb.Solid3d()
en.Extrude(Region, Solids(i).Extrude, 0)
Region.Dispose()
en.Color = AcCm.Color.FromColor(Solids(i).Color)
'Union Solids if needed
If Solids(i).AddRegions.Count > 0 Then
Dim AddPointCol As New AcGe.Point3dCollection
For j As Integer = 0 To Solids(i).AddRegions.Count - 1
'Get Union Points
For k As Integer = 0 To Solids(i).AddRegions.Item(j).Points.Count - 1
AddPointCol.Add(New AcGe.Point3d(Solids(i).AddRegions(j).Points(k).XYZ))
Next
'Create Union Region
Dim AddPolyline3d As AcDb.Polyline3d = New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, AddPointCol, True)
Dim AddPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
Dim AddRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
AddPoly.Add(AddPolyline3d)
AddRegion = AcDb.Region.CreateFromCurves(AddPoly)
Dim AcDbAddRegion As AcDb.Region = DirectCast(AddRegion(0), AcDb.Region)
'Create Union Solid
Dim AddSolid As New AcDb.Solid3d
AddSolid.Extrude(AcDbAddRegion, Solids(i).AddRegions(j).Extrude, 0)
AddSolid.Color = AcCm.Color.FromColor(Solids(i).AddRegions(j).Color)
'Union Solid
en.BooleanOperation(AcDb.BooleanOperationType.BoolUnite, AddSolid)
AcDbAddRegion.Dispose()
AddRegion.Dispose()
AddPointCol.Clear()
Next
AddPointCol.Dispose()
End If
'Subtract Solids if needed
If Solids(i).SubtractRegions.Count > 0 Then
Dim MinusPointCol As New AcGe.Point3dCollection
For j As Integer = 0 To Solids(i).SubtractRegions.Count - 1
'Get Minus Points
For k As Integer = 0 To Solids(i).SubtractRegions.Item(j).Points.Count - 1
MinusPointCol.Add(New AcGe.Point3d(Solids(i).SubtractRegions(j).Points(k).XYZ))
Next
'Create Minus Region
Dim MinusPolyline3d As AcDb.Polyline3d = New AcDb.Polyline3d(AcDb.Poly3dType.SimplePoly, MinusPointCol, True)
Dim MinusPoly As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
Dim MinusRegion As AcDb.DBObjectCollection = New AcDb.DBObjectCollection()
MinusPoly.Add(MinusPolyline3d)
MinusRegion = AcDb.Region.CreateFromCurves(MinusPoly)
Dim AcDbSubRegion As AcDb.Region = DirectCast(MinusRegion(0), AcDb.Region)
'Create Minus Solid
Dim MinusSolid As New AcDb.Solid3d
MinusSolid.Extrude(AcDbSubRegion, Solids(i).SubtractRegions(j).Extrude, 0)
MinusSolid.Color = AcCm.Color.FromColor(Solids(i).SubtractRegions(j).Color)
'Subtract Solid
en.BooleanOperation(AcDb.BooleanOperationType.BoolSubtract, MinusSolid)
AcDbSubRegion.Dispose()
MinusRegion.Dispose()
MinusPointCol.Clear()
Next
MinusPointCol.Dispose()
End If
'Color Faces
If Solids(i).ID.Description = g.c.Wall.PLATE_TOP_TOP Then
Dim ids As AcDb.ObjectId() = New AcDb.ObjectId(0) {}
Select Case Solids(i).Angle
Case g.c.FRONT, g.c.MINUS_FRONT
Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Green))
Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Red))
Case g.c.BACK
Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Green))
Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Red))
Case g.c.LEFT
Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Red))
Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Green))
Case g.c.RIGHT, g.c.MINUS_RIGHT
Dim Outside As New AcDb.SubentityId(AcDb.SubentityType.Face, 2)
Dim OutsidePath As New AcDb.FullSubentityPath(ids, Outside)
en.SetSubentityColor(Outside, AcCm.Color.FromColor(System.Drawing.Color.Red))
Dim Inside As New AcDb.SubentityId(AcDb.SubentityType.Face, 4)
Dim InsidePath As New AcDb.FullSubentityPath(ids, Inside)
en.SetSubentityColor(Inside, AcCm.Color.FromColor(System.Drawing.Color.Green))
End Select
End If
Select Case Solids(i).IsOnWCS
'Baselines are drawn in the WCS so they don't move and rotate
Case False
'Rotate Around Z Axis
en.TransformBy(AcGe.Matrix3d.Rotation(Rad(Solids(i).Rotation), New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
'Move in ModelSpace
Dim _Matrix3d As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d(Solids(i).Origin.XYZ))
en.TransformBy(en.Ecs.PostMultiplyBy(_Matrix3d))
End Select
'Add Entity to AcDb
br.AppendEntity(en)
tr.AddNewlyCreatedDBObject(en, True)
'Update FwHr Entity
Solids(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString
Solids(i).ID.Exists = True
Solids(i).Centroid = en.MassProperties.Centroid.ToArray
Solids(i).Weight = en.MassProperties.Volume * g.c.Weight.SPF
If Solids(i).IsSelectable Then
'Add xData to AcDb Entity
Dim xRec As New AcDb.Xrecord()
xRec.Data = New AcDb.ResultBuffer( _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Beam), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.BeamPocket), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Blocking), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Building), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Description), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Door), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.DoubleStud), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.FireStopping), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.FloorSheeting), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Item), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Joist), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Panel), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Partition), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Post), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Project), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.RimJoist), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Slab), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Stair), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Storey), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Strapping), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Wall), _
New AcDb.TypedValue(AcDb.DxfCode.Text, Solids(i).ID.Window))
en.CreateExtensionDictionary()
Dim SolidExtDict As AcDb.DBDictionary = DirectCast(tr.GetObject(en.ExtensionDictionary(), _
AcDb.OpenMode.ForWrite, False), AcDb.DBDictionary)
SolidExtDict.SetAt("EntityData", xRec)
'Add Entity to AcDb
tr.AddNewlyCreatedDBObject(xRec, True)
End If
End If
Next
For i As Integer = 0 To MTexts.Count - 1
If Not MTexts(i).ID.Exists Then
'Create AcDb Entity
Dim en As New AcDb.MText()
en.Contents = MTexts(i).Value
en.TextHeight = g.c.TEXT_HEGHT
en.Color = AcCm.Color.FromColor(MTexts(i).Color)
'Rotate Around Z Axis
en.TransformBy(AcGe.Matrix3d.Rotation(Rad(MTexts(i).Angle), New AcGe.Vector3d(0, 0, 1), New AcGe.Point3d(0, 0, 0)))
'Move in ModelSpace
Dim MatrixA As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
MTexts(i).Origin.X + (Cos(Rad(MTexts(i).Angle)) * MTexts(i).Position.X), _
MTexts(i).Origin.Y + (Sin(Rad(MTexts(i).Angle)) * MTexts(i).Position.X), _
MTexts(i).Position.Z))
en.TransformBy(en.Ecs.PostMultiplyBy(MatrixA))
Dim MatrixB As AcGe.Matrix3d = AcGe.Matrix3d.Displacement(New AcGe.Vector3d( _
-Sin(Rad(MTexts(i).Angle)) * MTexts(i).Position.Y, _
Cos(Rad(MTexts(i).Angle)) * MTexts(i).Position.Y, _
0))
en.TransformBy(en.Ecs.PostMultiplyBy(MatrixB))
'Add Entity to AcDb
br.AppendEntity(en)
tr.AddNewlyCreatedDBObject(en, True)
'Update FwHr Entity
MTexts(i).ID.AcDbHandle = en.ObjectId.Handle.Value.ToString()
End If
Next
dl.Dispose()
tr.Commit()
tr.Dispose()
Project.CommandLineTimeStamp("DrawingAids.DrawEntities" & " -Count [" & Solids.Count.ToString & "]")
End Sub