All dublicate objects Overkill c#

All dublicate objects Overkill c#

k005
Advisor Advisor
7,089 Views
28 Replies
Message 1 of 29

All dublicate objects Overkill c#

k005
Advisor
Advisor

Hello guys

 

How can I delete all duplicate objects in the dwg file?

overkill


* I will integrate this into another code...

 

Thanks.

0 Likes
Accepted solutions (1)
7,090 Views
28 Replies
Replies (28)
Message 2 of 29

jtoverka
Advocate
Advocate
  1. Create a class called Duplicates or something
  2. In the constructor do the following
    • Database database, Transaction transaction as parameters
      1. The calling function should be responsible for creating the starting transaction.
      2. Your class should have checks to verify that Database, Transaction, ObjectIds are valid and usable.
    • Scan all of the layouts (to ensure the entire drawing is scanned), sort each entity id in a dictionary.
      1. Example: Dictionary<Type, List<ObjectId>> entitiesField = new();
      2. An Example of type is BlockReference
      3. Putting these into buckets will make your application more efficient instead of scanning the drawing for every entity

  3. Create a public method called RemoveDuplicate_Entity
    • _Entity can be replaced with say BlockReference as an Example
      1. List<ObjectId> ids = entitiesField[typeof(BlockReference)];
      2. Scan the ids and find duplicates, remove as needed
    • Create as many as you need for your application.
  4. Create a public method called RemoveAllDuplicates
    • Invoke all of the other RemoveDuplicate_Entity methods.
  5. Create properties of duplication parameters
    • Example, layer matching, linetype matching, tolerances, etc.
  6. Put it all together
    • Create the transaction to the database.
    • Create the object, pass constructor parameters transaction and database.
    • Pass properties to adjust the duplicate matching.
    • Invoke the remove duplicates methods
  7. Notes
    • Only store object ids in fields, not references, it's harder to keep track of disposing these objects when the references are stored in fields. Get the object id and get the object from the transaction.
Message 3 of 29

k005
Advisor
Advisor

Thank you very much for the suggestion. But I'm not that good at C# yet.

 

* If there is a small example, I think I will.

0 Likes
Message 4 of 29

jtoverka
Advocate
Advocate

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
	}
}

 

Message 5 of 29

k005
Advisor
Advisor

Thank you very much, I will review the code and try it. I will write the result again here.

0 Likes
Message 6 of 29

k005
Advisor
Advisor

 

  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;
        }
        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;
        }
        private bool check = true;
        private readonly Database databaseField = null;
        private readonly Transaction transactionField = null;


        public void Overkill_PolyLine()
        {
            if (check)
            {
                CheckDatabase(databaseField, false);
                CheckTransaction(transactionField, false);
            }
            // Insert additional code here
        }

 

I tried to adapt the code.

I just called overkill_polyline.

but I got "database null" error.

A sample drawing is attached.

0 Likes
Message 7 of 29

jtoverka
Advocate
Advocate

It would be best to attach the code file you used so I can look at it.

0 Likes
Message 8 of 29

k005
Advisor
Advisor
 [CommandMethod("dht")]
        public void BreaComtest()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            birimCeviri(); //BİRİM ÇEVİRİ METODUM. DEĞİŞKENLER ÜSTTE
            ed.WriteMessage("\nAktif Birim : {0}", cZimBrimi);

            PromptPointResult ppr = ed.GetPoint("\nHesaplanacak Alan Tıkla >");
            if (ppr.Status != PromptStatus.OK) return;


            DBObjectCollection objs = ed.TraceBoundary(ppr.Value, true);
            if (objs.Count == 0) return;
            ObjectIdCollection ids = new ObjectIdCollection();
            ObjectId idmain = ObjectId.Null;
            
            double area = 0;

            //using (DocumentLock docLock = doc.LockDocument())
            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                BlockTableRecord cspace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                foreach (DBObject obj in objs)
                {
                    Curve c = obj as Curve;
                    if (c != null)
                    {
                        ObjectId curveId = cspace.AppendEntity(c);
                        tr.AddNewlyCreatedDBObject(c, true);
                        ids.Add(curveId);
                        if (c.Area > area)
                        {
                            idmain = curveId; area = c.Area;
                        }
                    }
                }
                tr.Commit();
            }

            using (Transaction tr = doc.TransactionManager.StartTransaction())
            {
                BlockTableRecord cspace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);

                Hatch hat = new Hatch();
                hat.SetDatabaseDefaults();
                cspace.AppendEntity(hat);
                tr.AddNewlyCreatedDBObject(hat, true);
                hat.HatchStyle = HatchStyle.Outer;
                hat.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
                hat.Associative = true;
                hat.AppendLoop(HatchLoopTypes.External, new ObjectIdCollection() { idmain });
                foreach (ObjectId id in ids)
                {
                    if (id != idmain)
                        hat.AppendLoop(HatchLoopTypes.Default, new ObjectIdCollection() { id });
                }
                hat.EvaluateHatch(true);

                ed.WriteMessage("\nTaranmış Alan : {0}", (hat.Area / BolenA).ToString("F2") + " m²");
                tr.Commit();
            }
            Overkill_PolyLine();
        }
0 Likes
Message 9 of 29

jtoverka
Advocate
Advocate

That's not the correct use of the class.
So my class file will be separate, modify that file only in the scope of overkill. Add your code to remove duplicates of polylines in the class file I provided.

To use the class appropriately, create the commands in another file and use the following:

// C# 9.0
Duplicates duplicates = new(tr, db);
duplicates.Overkill_Polyline();

 

Message 10 of 29

k005
Advisor
Advisor

 

How in another file? I do not understand., all the codes you sent?

0 Likes
Message 11 of 29

jtoverka
Advocate
Advocate

What application are you using to compile your code? Is it visual studio?

0 Likes
Message 12 of 29

k005
Advisor
Advisor

Yes. Visual Studio 2019 

 

File type : dll ( plug-in)

0 Likes
Message 13 of 29

jtoverka
Advocate
Advocate

So your hierarchy is this:

  • Solution
    • Project
      • References
      • Files
        • Class1.cs
        • Class2.cs
        •  and so on

Make a class called Duplicates.cs, put the code I wrote in that class.
Make another class called Commands.cs and make your AutoCAD commands there.

 

These separate classes will be compiled into one dll.

Message 14 of 29

k005
Advisor
Advisor

 

Can you create the class and add it?

I created it. but there are errors.

0 Likes
Message 15 of 29

jtoverka
Advocate
Advocate

I can't see the errors from the photo, what are the errors?

0 Likes
Message 16 of 29

k005
Advisor
Advisor

 

 

I created Duplicate.cs but it gave 17 errors.
you send me the file, let's talk about it.

0 Likes
Message 17 of 29

k005
Advisor
Advisor

@jtoverka 

 

All right, I've added Dublicates.cs.

Duplicates duplicates = new(tr, db); --> I'm getting an error in this part. C# 7.3

 

0 Likes
Message 18 of 29

jtoverka
Advocate
Advocate

Yes,

This is where you open KalayCad.csproj

Insert 

<LangVersion>9.0</LangVersion>

under the first ProjectGroup you see.

Message 19 of 29

jtoverka
Advocate
Advocate
Make sure you save your project before doing this.
This will ensure your project allows C# 9.0
It's the language version that I wrote the code in.
0 Likes
Message 20 of 29

k005
Advisor
Advisor

 

there is an error again... 😞

 

 

0 Likes