Referencing of CadXRecord

Hi,
I was looking the customs properties of my block (Name: Visibilité1, Value: DISCRET_D) and I finally find it here:

            using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load(dwgPath))
            {
                foreach (CadBaseObject cadObject in cadImage.Objects)
                {
                    if (cadObject is CadXRecord xRecord)
                    {
                        foreach (CadCodeValue codeValue in xRecord.Objects)
                        {
                            if (codeValue.Value == "DISCRET_D")
                            {
                                // Here I find it
                            }
                        }
                    }
                }
               }

The problem is that I can’t find a properties in my cadObject to reference to the block in my Cad. I looked inside the CadInsertObject, the CadBaseEntity and I can’t find a way to reference the CadObject to one of those.

CadBlockDictionary dictionary = cadImage.BlockEntities;
                foreach (CadBaseEntity entity in cadImage.Entities)
                {
                    if (entity is CadInsertObject insertObject)
                    {
                        if (insertObject.OriginalBlockName == "LOG_0004")
                        {
                            foreach (CadBlockEntity entityValue in dictionary.Values)
                            {
                                if (entityValue.Name == insertObject.Name)
                                {
                                    foreach (CadBaseEntity bloc in entityValue.Entities)
                                    {

                                    }
                                }
                            }
                            if (insertObject != null && insertObject.ChildObjects != null && insertObject.ChildObjects.Count > 0)
                            {
                                // VariableBit is my Class that I create from the info in insertObject and the CadBaseEntity from cadImage
                                VariableBit variableBit = new(insertObject, cadImage);
                                variableBits.Add(variableBit);
                            }
                        }
                    }
                }

How do you reference a CadObject to a block (CadInsertObject or CadBlockEntity or CadBaseEntity or whatever?

Thank you!

To reference a CadObject to a block in your CAD file, you can utilize the CadInsertObject and the CadBlockEntity. Here’s a general approach based on your existing code:

  1. Load the CAD Image: Start by loading your CAD file using Aspose.CAD.Image.Load.

  2. Iterate Through Entities: Loop through the entities in the CAD image to find instances of CadInsertObject. This object represents the insertion of a block.

  3. Access the Original Block: For each CadInsertObject, you can access the original block using its name. This is done by referencing the BlockEntities dictionary of the CadImage.

  4. Link to Block Properties: Once you have the CadBlockEntity, you can access its properties and any associated custom properties.

Here’s a code snippet that demonstrates this process:

using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load(dwgPath))
{
    foreach (CadBaseEntity entity in cadImage.Entities)
    {
        if (entity is CadInsertObject insertObject)
        {
            // Get the original block entity using the insert object's name
            CadBlockEntity blockEntity = cadImage.BlockEntities[insertObject.OriginalBlockName];

            if (blockEntity != null)
            {
                // Now you can access properties of the block
                foreach (CadBaseObject blockObject in blockEntity.Entities)
                {
                    // Here you can work with each block object
                }
            }
        }
    }
}

In this code, insertObject.OriginalBlockName is used to retrieve the corresponding CadBlockEntity from the BlockEntities dictionary. This allows you to access the properties of the block that the CadInsertObject references.

If you need to find specific custom properties, you can further explore the CadXRecord objects associated with the block or the insert object, as you have already done in your initial implementation.

This approach should help you effectively reference and work with blocks in your CAD files. If you have any further questions or need additional examples, feel free to ask!

@SamCroteau,
Hi.
It looks like we need to go through few additional entities to find custom values of the dynamic block, please try if the example below is helpful. If not could you please attach the file with this block, so we can try to find the proper relation.

using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load(fileName))
{
    foreach (CadEntityBase entity in cadImage.Entities)
    {
        if (entity is CadInsertObject insertObject)
        {
			CadApplicationCodes appCodes = insertObject.ApplicationCodesContainer.GetCodes("", "ACAD_XDICTIONARY");

			string reference = string.Empty;

			foreach (CadCodeValue cadCodeValue in appCodes.CodesList)
			{
				if (cadCodeValue.Code == 360)
				{
					reference = cadCodeValue.Value;
					break;
				}
			}

			string blockRepReference = SearchReferenceInObjects(cadImage, reference, CadObjectTypeName.DICTIONARY, "AcDbBlockRepresentation");
			string dataCacheReference = SearchReferenceInObjects(cadImage, blockRepReference, CadObjectTypeName.DICTIONARY, "AppDataCache");
			string xrecordReference = SearchReferenceInObjects(cadImage, dataCacheReference, CadObjectTypeName.DICTIONARY, "ACAD_ENHANCEDBLOCKHISTORY");

			foreach (CadObjectBase object_ in cadImage.Objects)
			{
				if (object_ is CadXRecord xRecord)
				{
					if (xRecord.ObjectHandle == xrecordReference)
					{
						for (int i = 0; i < xRecord.Objects.Count; i++)
						{
							System.Console.WriteLine(xRecord.Objects[i].Code + " " + xRecord.Objects[i].Value);
						}
					}
				}
			}
        }
    }
} 

private static string SearchReferenceInObjects(CadImage cadImage, string reference, CadObjectTypeName typeToSearch, string nameToSearch)
{
	foreach (CadBaseObject baseObject in cadImage.Objects)
	{
		 if (baseObject.TypeName != typeToSearch)
		 {
			 continue;
		 }

		 CadDictionary dictionary = (CadDictionary)baseObject;
		 CadEntityAttribute attr;
		 string val;
		 if (dictionary.ObjectHandle == reference && dictionary.TryGetValue(nameToSearch, out attr, out val) && attr == CadEntityAttribute.Cad360)
		 {
			 return val;
		 }
	}

	return string.Empty;
}

Hi,
I tried your code and I did not succeed to find the reference of my block. Here is my object that I am trying to find the block associated with:

var cadXRecord = new CadXRecord
{
    Objects = new List<CadCodeValue>
    {
        new CadBinaryCodeValue
        {
            Data = new byte[]
            {
                236,
                122,
                21,
                8
            },
            Code = 1071
        },
        new CadBinaryCodeValue
        {
            Data = new byte[]
            {
                98,
                27,
                0,
                11
            },
            Code = 1071
        },
        new CadBinaryCodeValue
        {
            Data = new byte[]
            {
                33,
                0
            },
            Code = 70
        },
        new CadBinaryCodeValue
        {
            Data = new byte[]
            {
                1,
                0
            },
            Code = 70
        },
        new CadBinaryCodeValue
        {
            Data = new byte[]
            {
                0,
                0,
                0,
                0,
                0,
                0,
                53,
                189,
                126,
                98,
                41,
                16,
                71,
                76,
                29,
                64,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0
            },
            Code = 10
        },
        new CadBinaryCodeValue
        {
            Code = 1,
            Value = "DISCRET_D"
        }
    },
    DuplicateCloningFlag = 1,
    BinaryData310 = new byte[0],
    BinaryData311 = new byte[0],
    ChildObjects = new List<CadBase>(),
    Numreactors = 1,
    SoftOwner = "46E",
    EmbeddedObjectsContainer = new CadEmbeddedObjectContainer
    {
        EmbeddedObjects = new List<CadEmbeddedObject>()
    },

    ObjectHandle = "46F",
    XdataContainer = new CadXdataContainer
    {
        Xdatas = new List<CadXdata>()
    },
    Attributes = new List<CadObjectAttribute>(),
    ApplicationCodesContainer = new CadApplicationCodesContainer
    {
        Codes = new Dictionary<string, List<CadApplicationCodes>>()
    },
    Attribute102Values = new List<CadCodeValue>()
};

And here is my .dwg, can you help me find the referencing.

Thank you very much!

TEST_VARIABLE_1.zip (30,9 Ko)

@SamCroteau,
for this case you need to replace

string xrecordReference = SearchReferenceInObjects(cadImage, dataCacheReference, CadObjectTypeName.DICTIONARY, "ACAD_ENHANCEDBLOCKHISTORY");

with

string xrecordReference = SearchReferenceInObjects(cadImage, dataCacheReference, CadObjectTypeName.DICTIONARY, "ACAD_ENHANCEDBLOCKDATA");
xrecordReference = SearchReferenceInObjects(cadImage, xrecordReference, CadObjectTypeName.DICTIONARY, "1");

where the last xrecordReference gets 46F handle of the required XRecord.

Hi, thank you very much. But If I have several blocks, how can I identify each one? What do I need to change in those new lines ?

Here is a example:

ist<VariableBit> variableBits = new();

            string objectHandle1 = string.Empty;
            string objectHandle2 = string.Empty;

            using (CadImage cadImage = (CadImage)Aspose.CAD.Image.Load(dwgPath))
            {
                foreach (CadBaseObject cadObject in cadImage.Objects)
                {
                    if (cadObject is CadXRecord xRecord)
                    {
                        foreach (CadCodeValue codeValue in xRecord.Objects)
                        {
                            if (codeValue.Value == "DISCRET_D")
                            {
                                // Here I find the first one
                                objectHandle1 = xRecord.ObjectHandle.ToString();
                            }
                            if (codeValue.Value == "DISCRET_G")
                            {
                                // Here I find the second one
                                objectHandle2 = xRecord.ObjectHandle.ToString();
                            }
                        }
                    }
                }

Here is the file:
TEST_VARIABLE_2.zip (32,2 Ko)

Thank you !

@SamCroteau,
my example finds two XRecords with handles 46F and 7C6 for each of two blocks in the last DWG sample file, it appears it works. I guess we can not map these XRecords with corresponding blocks just with looping over cadImage.Objects like in your last example because the relation between block and XRecord has multiple dictionary objects in between. We need to analyze these dictionaries in chain starting from block to XRecord like in my example but probably this is not the only way to solve this problem :slight_smile:

Hi,
Okay thank you, did you find a way to explore those dictionaries and find the relation between my XRecords and my blocks?

Thank you!

@SamCroteau,
yes, my example above does this. Starting from insertObject, the analysis of application codes is performed, and the lines

string blockRepReference = SearchReferenceInObjects(cadImage, reference, CadObjectTypeName.DICTIONARY, "AcDbBlockRepresentation");
string dataCacheReference = SearchReferenceInObjects(cadImage, blockRepReference, CadObjectTypeName.DICTIONARY, "AppDataCache");
string xrecordReference = SearchReferenceInObjects(cadImage, dataCacheReference, CadObjectTypeName.DICTIONARY, "ACAD_ENHANCEDBLOCKDATA");
xrecordReference = SearchReferenceInObjects(cadImage, xrecordReference, CadObjectTypeName.DICTIONARY, "1");

find the sequence of dictionary objects and return in the last

xrecordReference

variable the reference to the related XRecord object for the insertObject being processed. Finally, the last piece of code searches for the proper XRecord by its handle and prints its content.

Hi Olek,
Thank you for reaching out. But I’m not sure to understand you. Can you send me a code that identify clearly the insertObject of my two blocks and associate clearly which one is DISCRET_D and which one is DISCRET_G:

if (codeValue.Value == “DISCRET_D”)
{
// Here I find the first one
objectHandle1 = xRecord.ObjectHandle.ToString();
}
if (codeValue.Value == “DISCRET_G”)
{
// Here I find the second one
objectHandle2 = xRecord.ObjectHandle.ToString();
}

Thank you!

@SamCroteau,
Hi,
please run the attached example for your file.
SearchForXRecord.zip (974 Bytes)