I don't have it complete, but it should be working, I think.
Basically you create an object Duplicates, and you call the methods on that object that you want to use.
// Name: J. Overkamp
// Date: 09/02/2021
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Utilities
{
/// <summary>
/// Represents a .NET database container to implement overkill.
/// </summary>
public class Duplicates : INotifyPropertyChanged
{
#region Static FIelds
private static readonly RXClass rxLine = RXObject.GetClass(typeof(Line));
private static readonly RXClass rxPolyLine = RXObject.GetClass(typeof(Polyline));
private static readonly RXClass rxPolyLine2d = RXObject.GetClass(typeof(Polyline2d));
private static readonly RXClass rxPolyLine3d = RXObject.GetClass(typeof(Polyline3d));
private static readonly RXClass rxBlockReference = RXObject.GetClass(typeof(BlockReference));
private static readonly RXClass rxAttributeDefinition = RXObject.GetClass(typeof(AttributeDefinition));
private static readonly RXClass rxAttributeReference = RXObject.GetClass(typeof(AttributeReference));
private static readonly RXClass rxDbText = RXObject.GetClass(typeof(DBText));
private static readonly RXClass rxMText = RXObject.GetClass(typeof(MText));
private static readonly RXClass rxCircle = RXObject.GetClass(typeof(Circle));
#endregion
#region Fields
// flag for error checks.
private bool check = true;
private readonly Transaction transactionField = null;
private readonly Database databaseField = null;
// Dictionary to sort out buckets of entities by type.
private readonly Dictionary<RXClass, List<ObjectId>> entityDictionary = new();
// Property field defaults.
private bool removeZeroLengthLinesField = true;
private bool removeZeroDiameterCirclesField = true;
private double toleranceField = 0.0000001;
#endregion
#region Properties
/// <summary>
/// Gets or sets the flag to remove zero length lines.
/// </summary>
public bool RemoveZeroLengthLines
{
get { return removeZeroLengthLinesField; }
set
{
if (removeZeroLengthLinesField == value)
return;
removeZeroLengthLinesField = value;
OnPropertyChanged(this, new(nameof(RemoveZeroLengthLines)));
}
}
/// <summary>
/// Gets or sets the flag to remove zero diameter circles.
/// </summary>
public bool RemoveZeroDiameterCircles
{
get { return removeZeroDiameterCirclesField; }
set
{
if (removeZeroLengthLinesField == value)
return;
removeZeroDiameterCirclesField = value;
OnPropertyChanged(this, new(nameof(RemoveZeroDiameterCircles)));
}
}
/// <summary>
/// Gets or sets the measurement tolerance to determine a match.
/// </summary>
public double Tolerance
{
get { return toleranceField; }
set
{
if (toleranceField == value)
return;
toleranceField = value;
OnPropertyChanged(this, new(nameof(Tolerance)));
}
}
#endregion
#region Constructor
/// <summary>
/// Create a new instance of this class.
/// </summary>
/// <param name="transaction"></param>
/// <param name="database"></param>
public Duplicates(Transaction transaction, Database database)
{
if (check)
{
CheckDatabase(database, true);
CheckTransaction(transaction, true);
}
databaseField = database;
transactionField = transaction;
InitializeDictionary();
// Get Layout dictionary
using DBDictionary layouts = transaction.GetObject(database.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
// Iterate through the layouts
foreach (DBDictionaryEntry layout in layouts)
{
ObjectId layoutId = layout.Value;
if (!CheckObjectId(layoutId, false))
continue;
// Get the layout
using BlockTableRecord space = transaction.GetObject(layoutId, OpenMode.ForRead) as BlockTableRecord;
// Iterate through the entities in each layout
foreach (ObjectId entityId in space)
{
// Put each entity type into it's respective buckets.
if (!CheckObjectId(entityId, false))
continue;
if (entityId.ObjectClass == rxLine)
entityDictionary[rxLine].Add(entityId);
else if (entityId.ObjectClass == rxPolyLine)
entityDictionary[rxPolyLine].Add(entityId);
else if (entityId.ObjectClass == rxPolyLine2d)
entityDictionary[rxPolyLine2d].Add(entityId);
else if (entityId.ObjectClass == rxPolyLine3d)
entityDictionary[rxPolyLine3d].Add(entityId);
else if (entityId.ObjectClass == rxBlockReference)
entityDictionary[rxBlockReference].Add(entityId);
else if (entityId.ObjectClass == rxAttributeDefinition)
entityDictionary[rxAttributeDefinition].Add(entityId);
else if (entityId.ObjectClass == rxAttributeReference)
entityDictionary[rxAttributeReference].Add(entityId);
else if (entityId.ObjectClass == rxDbText)
entityDictionary[rxDbText].Add(entityId);
else if (entityId.ObjectClass == rxMText)
entityDictionary[rxMText].Add(entityId);
else if (entityId.ObjectClass == rxCircle)
entityDictionary[rxCircle].Add(entityId);
}
}
}
#endregion
#region Static Methods
/// <summary>
/// Check Object Id for errors.
/// </summary>
/// <param name="id">ObjectId to check.</param>
/// <param name="error">Flag to throw error.</param>
/// <returns>True if no errors found; otherwise, false.</returns>
private static bool CheckObjectId(ObjectId id, bool error)
{
if (error)
{
if (id.IsNull)
throw new NullReferenceException("Transaction is null");
if (id.IsEffectivelyErased || id.IsErased)
throw new AccessViolationException("Object Id is erased");
if (!id.IsValid)
throw new System.Exception("Object Id is not valid");
}
else
{
if (id.IsNull || id.IsEffectivelyErased || id.IsErased || !id.IsValid)
return false;
}
return true;
}
/// <summary>
/// Check transaction for errors.
/// </summary>
/// <param name="transaction">Transaction to check.</param>
/// <param name="argument">Flag whether it is an argument check.</param>
/// <returns></returns>
private static bool CheckTransaction(Transaction transaction, bool argument)
{
if (argument)
{
if (transaction == null)
throw new ArgumentNullException("Transaction is null");
}
else
{
if (transaction == null)
throw new NullReferenceException("Transaction is null");
}
if (transaction.IsDisposed)
throw new ArgumentException("Transaction has been disposed");
return true;
}
/// <summary>
/// Check database for errors.
/// </summary>
/// <param name="database">Database to check.</param>
/// <param name="argument">Flag whether it is an argument check.</param>
/// <returns></returns>
private static bool CheckDatabase(Database database, bool argument)
{
if (argument)
{
if (database == null)
throw new ArgumentNullException("Database is null");
}
else
{
if (database == null)
throw new NullReferenceException("Database is null");
}
if (database.IsBeingDestroyed)
throw new AccessViolationException("Database cannot be used, it is being destroyed");
if (database.IsDisposed)
throw new ObjectDisposedException("Database has been disposed");
return true;
}
#endregion
#region Methods
/// <summary>
/// Invoke property change event.
/// </summary>
/// <param name="sender">The object that invoked the event.</param>
/// <param name="e">The property that changed.</param>
protected void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(sender, e);
}
/// <summary>
/// Initialize each entity key in the dictionary with a list.
/// </summary>
private void InitializeDictionary()
{
entityDictionary[rxLine] = new();
entityDictionary[rxPolyLine] = new();
entityDictionary[rxPolyLine2d] = new();
entityDictionary[rxPolyLine3d] = new();
entityDictionary[rxBlockReference] = new();
entityDictionary[rxAttributeDefinition] = new();
entityDictionary[rxAttributeReference] = new();
entityDictionary[rxDbText] = new();
entityDictionary[rxMText] = new();
entityDictionary[rxCircle] = new();
}
/// <summary>
/// Remove duplicate lines.
/// </summary>
public void Overkill_Line()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
foreach (ObjectId lineId in entityDictionary[rxLine])
{
if (!CheckObjectId(lineId, false))
continue;
using Line line = transactionField.GetObject(lineId, OpenMode.ForRead) as Line;
if (RemoveZeroLengthLines)
{
if (line.Length < Tolerance)
line.Erase();
}
}
}
/// <summary>
/// Remove duplicate polylines.
/// </summary>
public void Overkill_PolyLine()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate polyline2d objects.
/// </summary>
public void Overkill_PolyLine2d()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate polyline3d objects.
/// </summary>
public void Overkill_PolyLine3d()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate block references.
/// </summary>
public void Overkill_BlockReference()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate attribute definitions.
/// </summary>
public void Overkill_AttributeDefinition()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate attribute references.
/// </summary>
public void Overkill_AttributeReference()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate text.
/// </summary>
public void Overkill_DBText()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate MText.
/// </summary>
public void Overkill_MText()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicate Circles.
/// </summary>
public void Overkill_Circle()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
// Insert additional code here
}
/// <summary>
/// Remove duplicates of all entities.
/// </summary>
public void Overkill()
{
if (check)
{
CheckDatabase(databaseField, false);
CheckTransaction(transactionField, false);
}
check = false;
try
{
Overkill_Line();
Overkill_PolyLine();
Overkill_PolyLine2d();
Overkill_PolyLine3d();
Overkill_BlockReference();
Overkill_AttributeDefinition();
Overkill_AttributeReference();
Overkill_DBText();
Overkill_MText();
Overkill_Circle();
}
catch
{
throw;
}
finally
{
check = true;
}
}
#endregion
#region Delegates, Events, Handlers
/// <summary>
/// Invoked on property changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}