AutoCAD Map 3D Developer
Welcome to Autodesk’s AutoCAD Map 3D Developer Forums. Share your knowledge, ask questions, and explore popular AutoCAD Map 3D Developer topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Crash when copying OD records from object to newly created

9 REPLIES 9
Reply
Message 1 of 10
O_Eckmann
679 Views, 9 Replies

Crash when copying OD records from object to newly created

O_Eckmann
Mentor
Mentor

Hi,

 

I've written a plug-in to create building (3D Solid) from 2D closed polylines with OD : ZMIN and HEIGHT

1. open transaction

2. Clone 2D closed polyline

3. Update elevation according ZMIN field

4. Extrude 2D polyline according value of field HEIGHT

5. dictionnary <objectid, objectid> of 2D polyline, 3D solid

6. commit transaction

 

7. for each objectid of 2D polyline =>  copy original OD to 3D Solid

 

With small quantity of polyline no problem, but if I try with lots of polyline, Map crash

 

10 000 polylines => 10 000 3DSolid WITHOUT copy OD => OK

300 polylines => 300 3D SOlid WITH copy of OD => OK

10 000 polylines => 10 000 3D solid with copy OD => Crash : no specific message, sometimes Error report, and sometimes directly to desktop without any error message.

 

In debug mode, if I put a break at evry 300 objects, wait 10 seconds and continue for a new cyle of 300 objects, new pause of 10s, sometimes I can treat all objects (and sometimes it crashes)

I've made a screen cast of my problem

 

Here is my code
using _AcDb = Autodesk.AutoCAD.DatabaseServices;
using _AcAp = Autodesk.AutoCAD.ApplicationServices;
using _AcRx = Autodesk.AutoCAD.Runtime;
using _AcGe = Autodesk.AutoCAD.Geometry;
using _AcEd = Autodesk.AutoCAD.EditorInput;
using _AcCo = Autodesk.AutoCAD.Colors;

using _AcMp = Autodesk.Gis.Map;
using _AcMpOdt = Autodesk.Gis.Map.ObjectData;
using _AcMpCst = Autodesk.Gis.Map.Constants;
using _AcMpUtl = Autodesk.Gis.Map.Utilities;

...


      Dictionary<_AcDb.ObjectId, _AcDb.ObjectId> dct3DSolid = new Dictionary<_AcDb.ObjectId, _AcDb.ObjectId>();

      // Boucle sur les entités
      using (_AcAp.DocumentLock lk = _acCurDoc.LockDocument())
      using (_AcDb.Transaction tr = _acCurDoc.TransactionManager.StartTransaction())
      {
        _AcDb.BlockTableRecord currentSpace = (_AcDb.BlockTableRecord)tr.GetObject(_acCurDb.CurrentSpaceId, _AcDb.OpenMode.ForWrite);
        foreach (_AcDb.ObjectId idCurve in _lsPoly)
        {
          _AcDb.Curve oCurve = tr.GetObject(idCurve, _AcDb.OpenMode.ForRead) as _AcDb.Curve;
          if (oCurve == null)
            continue;
          _AcDb.Curve oNewCurve = oCurve.Clone() as _AcDb.Curve;
          if (oNewCurve == null)
            continue;
          //extrait l'élévation
          if (ckbElevation.Checked)
          {
            sValue = RetrieveValue(idCurve, cbxElevTable.Text, cbxElevField.Text);
            if (!double.TryParse(sValue, out dElev))
              continue;
            // Met la curve à la bonne hauteur
            switch (oNewCurve.GetRXClass().DxfName)
            {
              case "CIRCLE":
                _AcDb.Circle oCirle = oNewCurve as _AcDb.Circle;
                oCirle.Center = new _AcGe.Point3d(oCirle.Center.X, oCirle.Center.Y, dElev);
                break;
              default:
                _AcDb.Polyline oPoly = oNewCurve as _AcDb.Polyline;
                if (oPoly != null)
                  oPoly.Elevation = dElev;
                break;
            }
          }

          // Extrait la hauteur
          sValue = RetrieveValue(idCurve, cbxHautTable.Text, cbxHautField.Text);
          if (!double.TryParse(sValue, out dHaut))
            continue;
          dHaut *= dFAct;
          if (dHaut <= 0)
            continue;
          // Crée le solide
          try
          {
            _AcDb.SweepOptions sweepOpts = new _AcDb.SweepOptions();
            _AcDb.Solid3d sol = new _AcDb.Solid3d();
            sol.CreateExtrudedSolid(oNewCurve, new _AcGe.Vector3d(0, 0, dHaut), sweepOpts);

            sol.Layer = ckbEntityLayer.Checked ? oCurve.Layer : tbxSolidLayer.Text;

            // Add 3D Solid to DB
            _AcDb.ObjectId id3DSolid = currentSpace.AppendEntity(sol);
            tr.AddNewlyCreatedDBObject(sol, true);

            dct3DSolid.Add(idCurve, id3DSolid);
          }
          catch (System.Exception ex)
          {
            _acCurEd.WriteMessage(ex.Message);
          }
        }
        tr.Commit();
      }

      if (ckbCopyOD.Checked)
      {
        foreach (_AcDb.ObjectId idCurve in dct3DSolid.Keys)
        {

          // Transfer OD fom base object to 3D Solid
          // Get and Initialize Records
          using (_AcMpOdt.Records records = _lsTables.GetObjectRecords(0, idCurve, _AcMpCst.OpenMode.OpenForWrite, false))
          {
            // SI pas de table associée
            if (records.Count == 0) continue;

            // Iterate through all records
            foreach (_AcMpOdt.Record oRecord in records)
            {
              // Get the table
              _AcMpOdt.Table table = _lsTables[oRecord.TableName];

              using (_AcMpOdt.Record oNewRecord = _AcMpOdt.Record.Create())
              {
                table.InitRecord(oNewRecord);

                // Get record info
                for (int i = 0; i < oRecord.Count; i++)
                {
                  _AcMpUtl.MapValue oVal = oRecord[i];
                  _AcMpUtl.MapValue oNewVal = oNewRecord[i];
                  oNewVal.Assign(oVal);
                }

                table.AddRecord(oNewRecord, dct3DSolid[idCurve]);
              }
            }
          }
        }

      }

 

Thanks for any help

 

Olivier

 

Olivier Eckmann

EESignature

0 Likes

Crash when copying OD records from object to newly created

Hi,

 

I've written a plug-in to create building (3D Solid) from 2D closed polylines with OD : ZMIN and HEIGHT

1. open transaction

2. Clone 2D closed polyline

3. Update elevation according ZMIN field

4. Extrude 2D polyline according value of field HEIGHT

5. dictionnary <objectid, objectid> of 2D polyline, 3D solid

6. commit transaction

 

7. for each objectid of 2D polyline =>  copy original OD to 3D Solid

 

With small quantity of polyline no problem, but if I try with lots of polyline, Map crash

 

10 000 polylines => 10 000 3DSolid WITHOUT copy OD => OK

300 polylines => 300 3D SOlid WITH copy of OD => OK

10 000 polylines => 10 000 3D solid with copy OD => Crash : no specific message, sometimes Error report, and sometimes directly to desktop without any error message.

 

In debug mode, if I put a break at evry 300 objects, wait 10 seconds and continue for a new cyle of 300 objects, new pause of 10s, sometimes I can treat all objects (and sometimes it crashes)

I've made a screen cast of my problem

 

Here is my code
using _AcDb = Autodesk.AutoCAD.DatabaseServices;
using _AcAp = Autodesk.AutoCAD.ApplicationServices;
using _AcRx = Autodesk.AutoCAD.Runtime;
using _AcGe = Autodesk.AutoCAD.Geometry;
using _AcEd = Autodesk.AutoCAD.EditorInput;
using _AcCo = Autodesk.AutoCAD.Colors;

using _AcMp = Autodesk.Gis.Map;
using _AcMpOdt = Autodesk.Gis.Map.ObjectData;
using _AcMpCst = Autodesk.Gis.Map.Constants;
using _AcMpUtl = Autodesk.Gis.Map.Utilities;

...


      Dictionary<_AcDb.ObjectId, _AcDb.ObjectId> dct3DSolid = new Dictionary<_AcDb.ObjectId, _AcDb.ObjectId>();

      // Boucle sur les entités
      using (_AcAp.DocumentLock lk = _acCurDoc.LockDocument())
      using (_AcDb.Transaction tr = _acCurDoc.TransactionManager.StartTransaction())
      {
        _AcDb.BlockTableRecord currentSpace = (_AcDb.BlockTableRecord)tr.GetObject(_acCurDb.CurrentSpaceId, _AcDb.OpenMode.ForWrite);
        foreach (_AcDb.ObjectId idCurve in _lsPoly)
        {
          _AcDb.Curve oCurve = tr.GetObject(idCurve, _AcDb.OpenMode.ForRead) as _AcDb.Curve;
          if (oCurve == null)
            continue;
          _AcDb.Curve oNewCurve = oCurve.Clone() as _AcDb.Curve;
          if (oNewCurve == null)
            continue;
          //extrait l'élévation
          if (ckbElevation.Checked)
          {
            sValue = RetrieveValue(idCurve, cbxElevTable.Text, cbxElevField.Text);
            if (!double.TryParse(sValue, out dElev))
              continue;
            // Met la curve à la bonne hauteur
            switch (oNewCurve.GetRXClass().DxfName)
            {
              case "CIRCLE":
                _AcDb.Circle oCirle = oNewCurve as _AcDb.Circle;
                oCirle.Center = new _AcGe.Point3d(oCirle.Center.X, oCirle.Center.Y, dElev);
                break;
              default:
                _AcDb.Polyline oPoly = oNewCurve as _AcDb.Polyline;
                if (oPoly != null)
                  oPoly.Elevation = dElev;
                break;
            }
          }

          // Extrait la hauteur
          sValue = RetrieveValue(idCurve, cbxHautTable.Text, cbxHautField.Text);
          if (!double.TryParse(sValue, out dHaut))
            continue;
          dHaut *= dFAct;
          if (dHaut <= 0)
            continue;
          // Crée le solide
          try
          {
            _AcDb.SweepOptions sweepOpts = new _AcDb.SweepOptions();
            _AcDb.Solid3d sol = new _AcDb.Solid3d();
            sol.CreateExtrudedSolid(oNewCurve, new _AcGe.Vector3d(0, 0, dHaut), sweepOpts);

            sol.Layer = ckbEntityLayer.Checked ? oCurve.Layer : tbxSolidLayer.Text;

            // Add 3D Solid to DB
            _AcDb.ObjectId id3DSolid = currentSpace.AppendEntity(sol);
            tr.AddNewlyCreatedDBObject(sol, true);

            dct3DSolid.Add(idCurve, id3DSolid);
          }
          catch (System.Exception ex)
          {
            _acCurEd.WriteMessage(ex.Message);
          }
        }
        tr.Commit();
      }

      if (ckbCopyOD.Checked)
      {
        foreach (_AcDb.ObjectId idCurve in dct3DSolid.Keys)
        {

          // Transfer OD fom base object to 3D Solid
          // Get and Initialize Records
          using (_AcMpOdt.Records records = _lsTables.GetObjectRecords(0, idCurve, _AcMpCst.OpenMode.OpenForWrite, false))
          {
            // SI pas de table associée
            if (records.Count == 0) continue;

            // Iterate through all records
            foreach (_AcMpOdt.Record oRecord in records)
            {
              // Get the table
              _AcMpOdt.Table table = _lsTables[oRecord.TableName];

              using (_AcMpOdt.Record oNewRecord = _AcMpOdt.Record.Create())
              {
                table.InitRecord(oNewRecord);

                // Get record info
                for (int i = 0; i < oRecord.Count; i++)
                {
                  _AcMpUtl.MapValue oVal = oRecord[i];
                  _AcMpUtl.MapValue oNewVal = oNewRecord[i];
                  oNewVal.Assign(oVal);
                }

                table.AddRecord(oNewRecord, dct3DSolid[idCurve]);
              }
            }
          }
        }

      }

 

Thanks for any help

 

Olivier

 

Olivier Eckmann

EESignature

9 REPLIES 9
Message 2 of 10
norman.yuan
in reply to: O_Eckmann

norman.yuan
Mentor
Mentor

It is interesting to see someone using Solid3d entities with AcadMap.

 

I guess you have already tried to isolate the issue from  ObjectData side, or from Solid3d entity side (say, run code that only create Solid3d entities without reading/writing ObjectData), right? If so, then the problem would be on ObjectData side.

 

In my past experience with ObjectData, either with COM API.VBA, or .NET API, I did run into similar issue that AutoCAD crashes when reading/writing ObjectData from/to too many entities. I observed AutoCAD's memory usage went up if I ran code that access ObjectData of a lot entities, say, from my custom command. After the command finished, the memory were not released (or maybe only portion of it was released). If the command were executed a few times, AutoCAD would eventually ate all the memory available and crashed.

 

When in the process of AutoCAD memory fragmenting is inevitable, but it seems ObjectData's memory handling is especially bad, no matter how vigorously we try to wrap all the disposable map object with "using...." block. In my cases, I remember I ran into this when there are quite more than 10000 entities,  while you ran into it with 10000 or less entities (but it is Solid3d, which I never used in Map).

 

In you case, you can try your code:

 

1. Watch memory use to see if the crash occurs with AutoCAD consuming exceptional high memory.

2. Run the Solid3d creation only process;

3. Add ObjectData reading (from the original Polyline) only to the process;

4. Add ObjectData writing (to the Solid3d entities) to the process.

 

With 2, 3, 4, watch the memory use. This way you might be able to tell where the high memory use happens. Not necessarily this would lead to a solution, but you may know where the problem lies in.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes

It is interesting to see someone using Solid3d entities with AcadMap.

 

I guess you have already tried to isolate the issue from  ObjectData side, or from Solid3d entity side (say, run code that only create Solid3d entities without reading/writing ObjectData), right? If so, then the problem would be on ObjectData side.

 

In my past experience with ObjectData, either with COM API.VBA, or .NET API, I did run into similar issue that AutoCAD crashes when reading/writing ObjectData from/to too many entities. I observed AutoCAD's memory usage went up if I ran code that access ObjectData of a lot entities, say, from my custom command. After the command finished, the memory were not released (or maybe only portion of it was released). If the command were executed a few times, AutoCAD would eventually ate all the memory available and crashed.

 

When in the process of AutoCAD memory fragmenting is inevitable, but it seems ObjectData's memory handling is especially bad, no matter how vigorously we try to wrap all the disposable map object with "using...." block. In my cases, I remember I ran into this when there are quite more than 10000 entities,  while you ran into it with 10000 or less entities (but it is Solid3d, which I never used in Map).

 

In you case, you can try your code:

 

1. Watch memory use to see if the crash occurs with AutoCAD consuming exceptional high memory.

2. Run the Solid3d creation only process;

3. Add ObjectData reading (from the original Polyline) only to the process;

4. Add ObjectData writing (to the Solid3d entities) to the process.

 

With 2, 3, 4, watch the memory use. This way you might be able to tell where the high memory use happens. Not necessarily this would lead to a solution, but you may know where the problem lies in.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 3 of 10
fieldguy
in reply to: O_Eckmann

fieldguy
Advisor
Advisor

no help from me - sorry. just some suggestions.  you might get some information from the crash report (>>example<< ). i have not checked memory usage but also have never worked with 10000 entities. in the past i have used explicit declarations of tables, records, and record objects, and "Dispose()" method if it is available for the object, just to make sure the problem was not related to a "using" statement.  

Check the "ObjectData.cs" sample in the Map ObjectARX SDK ????\Map Samples\DotNet\ObjectDataCS folder.  the  "AddODRecord" uses a Try/Catch structure.

again - just guessing. good luck!  maybe you could easily create 100000 entities for testing? 

0 Likes

no help from me - sorry. just some suggestions.  you might get some information from the crash report (>>example<< ). i have not checked memory usage but also have never worked with 10000 entities. in the past i have used explicit declarations of tables, records, and record objects, and "Dispose()" method if it is available for the object, just to make sure the problem was not related to a "using" statement.  

Check the "ObjectData.cs" sample in the Map ObjectARX SDK ????\Map Samples\DotNet\ObjectDataCS folder.  the  "AddODRecord" uses a Try/Catch structure.

again - just guessing. good luck!  maybe you could easily create 100000 entities for testing? 

Message 4 of 10
O_Eckmann
in reply to: norman.yuan

O_Eckmann
Mentor
Mentor

Hi @norman.yuan ,

 

In my plug-in I've already 2 functions to export/import OD (similar to ATTIN and ATTOUT) to and from text tabbed file.

I've already export and import (update) more than 200 000 objects (DWG of 730Mo) without any problem.

I've no crash when reading/updating OD. Problem appears only when I create (lots of) record and add to objets (generally new created objects).

 

I try to explore your memory request to find possible solution. I'm not a specialist to follow memory usage but I'll check that.

 

I post info when I've tried.

 

I'll try solution of @fieldguy too with basic AddRecord function on existing objects and on newly created objects to see possible crash (or not).

 

Olivier

 

Olivier Eckmann

EESignature

0 Likes

Hi @norman.yuan ,

 

In my plug-in I've already 2 functions to export/import OD (similar to ATTIN and ATTOUT) to and from text tabbed file.

I've already export and import (update) more than 200 000 objects (DWG of 730Mo) without any problem.

I've no crash when reading/updating OD. Problem appears only when I create (lots of) record and add to objets (generally new created objects).

 

I try to explore your memory request to find possible solution. I'm not a specialist to follow memory usage but I'll check that.

 

I post info when I've tried.

 

I'll try solution of @fieldguy too with basic AddRecord function on existing objects and on newly created objects to see possible crash (or not).

 

Olivier

 

Olivier Eckmann

EESignature

Message 5 of 10
O_Eckmann
in reply to: fieldguy

O_Eckmann
Mentor
Mentor

Hi @fieldguy ,

 

I've tried with sample function CreateTable and AddODRecord found in ObjectSampleCS with this code :

    [_AcRx.CommandMethodAttribute("TEST_OD1", _AcRx.CommandFlags.Modal)]
    public void TEST_OD1()
    {
      _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;
      _AcEd.Editor ed = doc.Editor;
      ed.WriteMessage("\nTry to create table named TEST_OD...");
      CreateTable(aMap.HostMapApplicationServices.Application.ActiveProject.ODTables, "TEST_OD");
      ed.WriteMessage("\n   ... table named TEST_OD created successfully");
    }

    [_AcRx.CommandMethodAttribute("TEST_OD2", _AcRx.CommandFlags.Modal)]
    public void TEST_OD2()
    {
      _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;
      _AcEd.Editor ed = doc.Editor;
      ed.WriteMessage("\nTry to add record of table named TEST_OD to selected objects ...");

      _AcEd.PromptSelectionOptions pso = new _AcEd.PromptSelectionOptions();
      pso.MessageForAdding = "\nSelect objects to add record : ";
      _AcEd.PromptSelectionResult psr = ed.GetSelection(pso);

      foreach (_AcDb.ObjectId id in psr.Value.GetObjectIds())
      {
        AddODRecord(aMap.HostMapApplicationServices.Application.ActiveProject.ODTables, "TEST_OD", id);
      }

      ed.WriteMessage("\n   ... all records added successfully");
    }

1st function to create table is OK

2nd function to add Record on 10000 2D polylines crash. Here is screencast

Olivier Eckmann

EESignature

0 Likes

Hi @fieldguy ,

 

I've tried with sample function CreateTable and AddODRecord found in ObjectSampleCS with this code :

    [_AcRx.CommandMethodAttribute("TEST_OD1", _AcRx.CommandFlags.Modal)]
    public void TEST_OD1()
    {
      _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;
      _AcEd.Editor ed = doc.Editor;
      ed.WriteMessage("\nTry to create table named TEST_OD...");
      CreateTable(aMap.HostMapApplicationServices.Application.ActiveProject.ODTables, "TEST_OD");
      ed.WriteMessage("\n   ... table named TEST_OD created successfully");
    }

    [_AcRx.CommandMethodAttribute("TEST_OD2", _AcRx.CommandFlags.Modal)]
    public void TEST_OD2()
    {
      _AcAp.Document doc = _AcAp.Application.DocumentManager.MdiActiveDocument;
      _AcEd.Editor ed = doc.Editor;
      ed.WriteMessage("\nTry to add record of table named TEST_OD to selected objects ...");

      _AcEd.PromptSelectionOptions pso = new _AcEd.PromptSelectionOptions();
      pso.MessageForAdding = "\nSelect objects to add record : ";
      _AcEd.PromptSelectionResult psr = ed.GetSelection(pso);

      foreach (_AcDb.ObjectId id in psr.Value.GetObjectIds())
      {
        AddODRecord(aMap.HostMapApplicationServices.Application.ActiveProject.ODTables, "TEST_OD", id);
      }

      ed.WriteMessage("\n   ... all records added successfully");
    }

1st function to create table is OK

2nd function to add Record on 10000 2D polylines crash. Here is screencast

Olivier Eckmann

EESignature

Message 6 of 10
O_Eckmann
in reply to: O_Eckmann

O_Eckmann
Mentor
Mentor

 

If I try again with 840 objects OK, with 2500 objects it crash. And memory usage doesn't seem to be so high.
 
 

Olivier Eckmann

EESignature

0 Likes

 

If I try again with 840 objects OK, with 2500 objects it crash. And memory usage doesn't seem to be so high.
 
 

Olivier Eckmann

EESignature

Message 7 of 10
O_Eckmann
in reply to: O_Eckmann

O_Eckmann
Mentor
Mentor

Sorry for 3 messages, but I don't know how to add 2 screencast in 1 answer.

 
Olivier

Olivier Eckmann

EESignature

0 Likes

Sorry for 3 messages, but I don't know how to add 2 screencast in 1 answer.

 
Olivier

Olivier Eckmann

EESignature

Message 8 of 10
O_Eckmann
in reply to: norman.yuan

O_Eckmann
Mentor
Mentor

Hi @norman.yuan , @fieldguy ,

 

I think I've found a solution. Sometimes in debug mode I obtain a crash with an error on DisposalUnwrapped on Table.

So when I use a Table, I try to include it in a "using" and it seems to work.

In my original code i just replace (after lots of other modifications 😀 )

              // Get the table
              _AmOd.Table table = _lsTables[oCurveRecord.TableName];
              using (_AmOd.Record oNewRecord = _AmOd.Record.Create())
              {
                ...

 by 

              // Get the table
              using (_AmOd.Table table = _lsTables[oCurveRecord.TableName])
              using (_AmOd.Record oNewRecord = _AmOd.Record.Create())
              {
                  ...

and I can't reproduce the crash even on 10 000 3DSolid created.

 

Olivier

Olivier Eckmann

EESignature

0 Likes

Hi @norman.yuan , @fieldguy ,

 

I think I've found a solution. Sometimes in debug mode I obtain a crash with an error on DisposalUnwrapped on Table.

So when I use a Table, I try to include it in a "using" and it seems to work.

In my original code i just replace (after lots of other modifications 😀 )

              // Get the table
              _AmOd.Table table = _lsTables[oCurveRecord.TableName];
              using (_AmOd.Record oNewRecord = _AmOd.Record.Create())
              {
                ...

 by 

              // Get the table
              using (_AmOd.Table table = _lsTables[oCurveRecord.TableName])
              using (_AmOd.Record oNewRecord = _AmOd.Record.Create())
              {
                  ...

and I can't reproduce the crash even on 10 000 3DSolid created.

 

Olivier

Olivier Eckmann

EESignature

Message 9 of 10
fieldguy
in reply to: O_Eckmann

fieldguy
Advisor
Advisor

good work!  i can use that logic as well. i am curious what your application is doing - can you share a bit more info?

TIA

0 Likes

good work!  i can use that logic as well. i am curious what your application is doing - can you share a bit more info?

TIA

Message 10 of 10
O_Eckmann
in reply to: fieldguy

O_Eckmann
Mentor
Mentor

Hi @fieldguy ,

 

My plug-in is available in this discussion (message 25, 43 and following for the evolutions)

 

Olivier

Olivier Eckmann

EESignature

0 Likes

Hi @fieldguy ,

 

My plug-in is available in this discussion (message 25, 43 and following for the evolutions)

 

Olivier

Olivier Eckmann

EESignature

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report