Trying To Read Object Data from a Civil3D drawing

Trying To Read Object Data from a Civil3D drawing

lee.morse
Enthusiast Enthusiast
1,182 Views
15 Replies
Message 1 of 16

Trying To Read Object Data from a Civil3D drawing

lee.morse
Enthusiast
Enthusiast

Hi,

 

Trying my first few tentative steps with coding for AutoCad with .NET, I am a NOOB.

 

I have several objects in my drawing with object data attached. I am trying to read through the object data, but the code does not seem to find it. The below code fails the check at 'If (extensionDict IsNot Nothing AndAlso extensionDict.Contains("ACAD_OBJECT_DATA"))', I would expect this not to fail if there is ObjectData.

 

Can anyone explain why I am not seeing what I am expecting?

 

 

 

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Geometry

Namespace AutoCADObjectDataReader


Public Class TemplateClass

<CommandMethod("ReadObjectData")>
Public Sub ReadObjectData()
Dim doc As Document = Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor

'ed.WriteMessage("Starting" & vbCrLf)

Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
Dim modelSpace As BlockTableRecord = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
For Each entityID As ObjectId In modelSpace
Dim MyEntity As Entity = tr.GetObject(entityID, OpenMode.ForRead)
'Check If the entity has extended data
If (MyEntity IsNot Nothing AndAlso MyEntity.ExtensionDictionary.IsValid) Then
Dim extensionDict As DBDictionary = tr.GetObject(MyEntity.ExtensionDictionary, OpenMode.ForRead)
'Check If the entity's extension dictionary contains object data
If (extensionDict IsNot Nothing AndAlso extensionDict.Contains("ACAD_OBJECT_DATA")) Then
Dim MyxRecord As Xrecord = tr.GetObject(extensionDict.GetAt("ACAD_OBJECT_DATA"), OpenMode.ForRead)
'Check If the Xrecord Is valid And has data
If (MyxRecord IsNot Nothing AndAlso MyxRecord.Data IsNot Nothing) Then
Dim MyresultBuffer As ResultBuffer = MyxRecord.Data
Dim values As TypedValue() = MyresultBuffer.AsArray()
'Output the Object data To the console
'Dim value As TypedValue
For Each value As TypedValue In values
ed.WriteMessage(value.Value.ToString() & vbCrLf)
Next

Else
ed.WriteMessage("MyxRecord is empty or not valid" & vbCrLf)
End If
Else
ed.WriteMessage("extensionDict is empty or not valid" & vbCrLf)
End If
Else
ed.WriteMessage("MyEntity is empty or not valid" & vbCrLf)
End If
Next
End Using

End Sub
End Class
End Namespace

0 Likes
Accepted solutions (1)
1,183 Views
15 Replies
Replies (15)
Message 2 of 16

norman.yuan
Mentor
Mentor

Firstly, please post the code by using the "</>" button in the toolbar of the message window, so that the code will be more read-able.

 

If you are talking about "ObjectData" of AutoCAD Map 3D/Civil 3D, then, what makes you think that the ObjectData is stored with Entity.ExtensionDictionary?

 

No, ObjectData is not stored with Entity.ExtensionDictionary. You should manuplate ObjectData with Map's .NET API by adding reference to ManagedMapApi.dll found in "C:\...[AutoCAD install folder]\Map" folder. Once you have this .NET assembly referenced, look into the namespace Autodesk.Gis.Map.ObjectData. You can also search for AutoCAD Map ObjectARX documentation and find sample code dealing with ObjectData.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 16

lee.morse
Enthusiast
Enthusiast

Hi Norman,

 


@norman.yuan wrote:

If you are talking about "ObjectData" of AutoCAD Map 3D/Civil 3D

 Yes exactly.

 


@norman.yuan wrote:

You can also search for AutoCAD Map ObjectARX documentation and find sample code dealing with ObjectData.


I think herein lies the problem. I struggled to find any examples or documentation, maybe I just don't know my way around the website well enough. Is anyone able to post some links?

 

Thank you.

Message 4 of 16

Jeff_M
Consultant
Consultant

Samples for c# and VB.NET are installed here:

C:\Program Files\Autodesk\AutoCAD 2024\Map\Development\Samples

 

Map3d Developer's guide

ADN Platform Technologies

Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 5 of 16

norman.yuan
Mentor
Mentor

Well, I simply did a quick search online for "ObjectData in AutoCAD Map .NET API", it led me to this:

 

https://documentation.help/AutoCAD-Map-3D-2008-.NET-API/WS1a9193826455f5ffd8d87110dc58fdc8f-7af4.htm... 

 

While it is for AutoCAD Map 2008, all its contents are valid because AutoCAD Map .NET API remained unchanged since Acad Map2006 or 2007. This documentation has quite some code samples (unfortunately in VB.NET).

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 6 of 16

norman.yuan
Mentor
Mentor

@Jeff_M the sample code you referred to is for Industrial Models, which is rarely/hardly used by anyone these days (or even many years ago) and do not deal with ObjectData.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 7 of 16

norman.yuan
Mentor
Mentor

@lee.morse You can also search "AutoCAD Map 3d Developer" discussion forum for "ObjectData". You should find some sample code and maybe are interested in some past discussions.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 8 of 16

hosneyalaa
Advisor
Advisor

@lee.morse 

Hi
Please attached drawing example

0 Likes
Message 9 of 16

lee.morse
Enthusiast
Enthusiast

Hi hoseyalaa,

Sorry for the delayed reply, I have been on holiday, and I work a 7 on 7 off roster. I have attached a sample drawing.

0 Likes
Message 10 of 16

Jeff_M
Consultant
Consultant

@lee.morse Here is a chunk of code from a project of mine. It uses a WPF window so not everything here will make total sense but it should give you an idea of how to get the OD from an entity.

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.Gis.Map;
using Autodesk.Gis.Map.ObjectData;
using System;
using System.Collections.Generic;
using Constants = Autodesk.Gis.Map.Constants;
using MapOD = Autodesk.Gis.Map.ObjectData;


           var doc = Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            var db = doc.Database;
            var ssOpt = new PromptSelectionOptions();
            ssOpt.MessageForAdding = "\nSelect object to edit ObjectData:";
            ssOpt.SingleOnly = true;
            var ssFilter = new SelectionFilter(new TypedValue[] { new TypedValue(0, "*POLYLINE,LINE,INSERT,CIRCLE,ARC") });
            var ssRes = ed.GetSelection(ssOpt, ssFilter);
            if (ssRes.Status != PromptStatus.OK)
                return;
            ODDataWindow form = null;
            var tables = HostMapApplicationServices.Application.ActiveProject.ODTables;
            while (ssRes.Status == PromptStatus.OK)
            {
                ObjectId id = ssRes.Value.GetObjectIds()[0];
                using (var records = tables.GetObjectRecords(0, id, Constants.OpenMode.OpenForRead, true))
                {
                    if (records == null || records.Count < 1)
                    {
                        ed.WriteMessage("\nNo ObjectData attached to this entity, please select another.");
                        ssRes = ed.GetSelection(ssOpt, ssFilter);
                        continue;
                    }
                    mview = new ODModelView(records);
                    form = new ODDataWindow(mview);
                }
                if (Application.ShowModalWindow(form) == true)
                {
                    UpdateOD(id);
                }
                ssRes = ed.GetSelection(ssOpt, ssFilter);
            }
            mview = null;
Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 11 of 16

Jeff_M
Consultant
Consultant

And the constructor for the ViewModel which accepts the records as the argument:

        public ODModelView(Records records)
        {
            System.IFormatProvider icInfo = System.Globalization.CultureInfo.InvariantCulture;
            var tables = HostMapApplicationServices.Application.ActiveProject.ODTables;
            var theData = new Dictionary<string, List<QuuxOData>>();
            EntityOD = new ObservableCollection<Dictionary<string, List<QuuxOData>>>();
            foreach (Record rec in records)
            {
                var tblname = rec.TableName;
                var defs = tables[tblname].FieldDefinitions;
                var tblData = new List<QuuxOData>();
                for (int i = 0; i < rec.Count; i++)
                {
                    var myod = new QuuxOData();
                    var fld = defs[i];
                    var entry = rec[i];
                    //myod.TableName = tblname;
                    myod.Name = fld.Name;
                    myod.DataType = entry.Type;
                    switch (entry.Type)
                    {
                        case Constants.DataType.Character:
                            myod.Value = entry.StrValue.ToUpper();
                            break;
                        case Constants.DataType.Integer:
                            myod.Value = entry.Int32Value;
                            break;
                        case Constants.DataType.Point:
                            myod.Value = entry.Point;
                            break;
                        case Constants.DataType.Real:
                            myod.Value = entry.DoubleValue;
                            break;
                    }
                    tblData.Add(myod);
                }
                theData.Add(tblname, tblData);
            }
            EntityOD.Add(theData);

        }
Jeff_M, also a frequent Swamper
EESignature
0 Likes
Message 12 of 16

lee.morse
Enthusiast
Enthusiast

Hi Jeff,

 

Thank you. I have managed to grab the Projects ODTables. Where I am now getting stumped is trying to iterate through all the records from the table. This line of code:

 

 

 

 

 

 

records = tables.GetObjectRecords(0, id, Constants.OpenMode.OpenForRead, true)

 

 

 

 

 

 

...seems very specifically for an object(s) with a known object id. How do I select and iterate through all objectData Records (I assume that I am allowed to have Records not attached to an Object)? I have browsed through the documentation here "https://documentation.help/AutoCAD-Map-3D-2008-.NET-API/WS73099cc142f487551d92abb10dc573c45d-7bc0.ht... and cannot see a reference for how to do this.

 

This is my code so far. The commented sections clumsily indicate what I am trying to do (I think):

 

 

Dim acMapApp As MapApplication = HostMapApplicationServices.Application
Dim acActiveProject As Project.ProjectModel = acMapApp.ActiveProject
Dim acTableList As ObjectData.Tables = acActiveProject.ODTables
Dim odTableName As String
Dim odTable As ObjectData.Table


If (acTableList.TablesCount > 0) Then
                ed.WriteMessage("number of tables in table list = " + acTableList.TablesCount.ToString & vbCrLf)

                For Each odTableName In acTableList.GetTableNames()
                    ed.WriteMessage("Table Name = " & odTableName & vbCrLf)
                    odTable = acTableList.Item(odTableName)
                    Dim odFieldName As ObjectData.FieldDefinition
                    Dim odFieldDefs As ObjectData.FieldDefinitions = odTable.FieldDefinitions
                    Dim odRecord As ObjectData.Records
                    Dim odCount As Integer = odTable.FieldDefinitions.Count
                    'odRecord  = odTable.GetObjectTableRecords(0, id, Constants.OpenMode.OpenForRead, True)

                    ed.WriteMessage("Count of Fields: " & odCount & vbCrLf)

                    For i As Integer = 0 To odCount - 1
                        odFieldName = odFieldDefs.Item(i)

                        ed.WriteMessage(i & ":" & odFieldName.Name & vbCrLf)

                    Next


                    'For Each myRec As Record In odRecords
                    '    ed.WriteMessage("Records: " & myRec.Count & vbCrLf)
                    '    
                    '    ed.WriteMessage("Record Contents: " & myRec.ToString)
                    'Next

                Next

 

 

Apologies all if I am being painful.

0 Likes
Message 13 of 16

hosneyalaa
Advisor
Advisor

HI @lee.morse 

TRY

 


[Autodesk.AutoCAD.Runtime.CommandMethodAttribute("ShowRecords")]
		public void CommandShowRecords()
		{
			try
			{
				Tables tables = HostMapApplicationServices.Application.ActiveProject.ODTables;

				
				if (tables.TablesCount < 1)
				{
					AcadEditor.WriteMessage("\n You have not created the ObjectData table, yet. ");
					return;
				}
				PromptSelectionOptions options = new PromptSelectionOptions();

				// Single select mode
				options.SingleOnly = true;
				options.SinglePickInSpace = true;
				options.MessageForAdding = "Select an entity:";
				AcadEditor.WriteMessage("\n Please select the target entity: ");
				PromptSelectionResult result = AcadEditor.GetSelection(options);

				if (result.Status != PromptStatus.OK)
				{
					AcadEditor.WriteMessage("\n User cancelled! ");
					return;
				}

				ObjectId[] ids = result.Value.GetObjectIds();
				if (ids.Length != 1)
				{
					AcadEditor.WriteMessage("\n Invalid selection! ");
					return;
				}

				if (!ShowObjectDataInfo(tables, ids[0]))
				{
					AcadEditor.WriteMessage("\n Failed to get the information from the entity. ");
				}
			}
			catch (System.Exception err)
			{
				AcadEditor.WriteMessage(err.Message);
			}
		}




		private static Editor AcadEditor
		{
			get
			{
				return Application.DocumentManager.MdiActiveDocument.Editor;
			}
		}


public bool ShowObjectDataInfo(Tables tables, ObjectId id)
		{
			ErrorCode errCode = ErrorCode.OK; 
			try
			{
				bool success = true;

				// Get and Initialize Records
				using (Records records
						   = tables.GetObjectRecords(0, id, Autodesk.Gis.Map.Constants.OpenMode.OpenForRead, false))
				{
					if (records.Count == 0)
					{
						AcadEditor.WriteMessage("\n There is no ObjectData record attached on the entity. ");
						return true;
					}

					int index = 0;

					// Iterate through all records
					foreach (Record record in records)
					{
						String msg = null;
						msg = String.Format("\nRecord {0} :  {1}", index , Environment.NewLine);
						index++;
						AcadEditor.WriteMessage(msg);

						// Get the table
						Autodesk.Gis.Map.ObjectData.Table table = tables[record.TableName];

						int valInt = 0;
						double valDouble = 0.0;
						string str = null;

						// Get record info
						for (int i = 0; i < record.Count; i++)
						{
							FieldDefinitions tableDef = table.FieldDefinitions;
							FieldDefinition column = null;
							column = tableDef[i];
							string colName = column.Name;
							MapValue val = record[i];

							switch (val.Type)
							{
                                case Autodesk.Gis.Map.Constants.DataType.Integer:
									valInt = val.Int32Value;
									msg = string.Format("{0} ", valInt);
									AcadEditor.WriteMessage(String.Format("{0}--> {1}{2}", colName, msg, Environment.NewLine));
									
									
									break;

                                case Autodesk.Gis.Map.Constants.DataType.Real:
									valDouble = val.DoubleValue;
									msg = string.Format("{0} ", valDouble);
									AcadEditor.WriteMessage(String.Format("{0}--> {1}{2}", colName, msg, Environment.NewLine));
									//AcadEditor.WriteMessage(msg);
									break;

                                case Autodesk.Gis.Map.Constants.DataType.Character:
									str = val.StrValue;
									msg = string.Format("{0} ", str);
									AcadEditor.WriteMessage(String.Format("{0}--> {1}{2}", colName, msg, Environment.NewLine));
									
									break;

                                case Autodesk.Gis.Map.Constants.DataType.Point:
								{
									Point3d pt = val.Point;
									double x = pt.X;
									double y = pt.Y;
									double z = pt.Z;
									msg = string.Format("Point({0},{1},{2}) ", x, y, z);
										AcadEditor.WriteMessage(String.Format("{0}----> {1}{2}", colName, msg, Environment.NewLine));
										
								}
									break;

								default:
									AcadEditor.WriteMessage("\nWrong data type\n");
									success = false;
									break;
							}
						}
					}
				}

				return success;
			}
			catch (MapException e)
			{
				errCode = (ErrorCode)(e.ErrorCode);
				// Deal with the exception here as your will

				return false;
			}
		}

 

 

Capture9.JPG

0 Likes
Message 14 of 16

lee.morse
Enthusiast
Enthusiast

Thank you hosneyalaa,

 

Great code that works well, however, as my above comment, this line of code:

 

= tables.GetObjectRecords(0, id, Autodesk.Gis.Map.Constants.OpenMode.OpenForRead, false))

 

.. is for a specific object id. Is there a way to iterate through all objectData without the input of a specific object id?

0 Likes
Message 15 of 16

hosneyalaa
Advisor
Advisor

@lee.morse 

I didn't understand you
Can you explain with pictures?
Do you want the code to Works with all elements in the drawing
without choosing

0 Likes
Message 16 of 16

norman.yuan
Mentor
Mentor
Accepted solution

Well, you can only iterate all Entities to get all ObjectData. So, yes, it is time-consuming process if the drawing has a lot of entities and only some of the entities have ObjectData record of particular ODTable attached.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes