Search code examples
c#autocadautocad-pluginautodesk-designautomationobjectarx

Why do viewports created using commands in ObjectARX not save to the database?


Summary

I'm trying to write a C# ObjectARX script to create a viewport that fits the extents of the layout using the -VPORTS Fit command, but for some reason the new viewport shows in AutoCAD but is never saved to the output drawing.

Some things I've tried

  • Using acDoc.SendStringToExecute() instead of acDoc.Editor.Command()
  • Using -VPORTS instead of ._VIEWPORTS
  • Running the commands before commiting the transaction
    • Caused AutoCAD to freeze and crash. I think I have to commit the new layout before I can make the viewport

Code Snippet

[CommandMethod("CreateViewport")]
public static void CreateViewport()
{
    // Get the current document and database, and start a transaction
    Document acDoc = Application.DocumentManager.MdiActiveDocument;
    Database acCurDb = acDoc.Database;

    try
    {
        Entity acObj = null;

        using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
        {
            // Omitted code for opening block record ...

            // Switch to the previous Paper space layout
            Application.SetSystemVariable("TILEMODE", 0);
            acDoc.Editor.SwitchToPaperSpace();

            // Omitted code for creating a polyline in model space to focus on (acObj) ...
            // Omitted code for creating a new layout ...

            // Save the new objects to the database
            acTrans.Commit();
        }

        // This is the part that shows in AutoCAD but doesn't save
        acDoc.Editor.Command("._VIEWPORTS", "Fit");
        acDoc.Editor.Command("._MSPACE");
        acDoc.Editor.Command("._ZOOM", "_O", SelectionSet.FromObjectIds(new ObjectId[] { acObj.ObjectId }), "");
        acDoc.Editor.Command("._PSPACE");
        acDoc.Editor.Command("._ZOOM", "E");

        acCurDb.SaveAs("OutputDrawing.dwg", DwgVersion.AC1027);
    }
    catch (Exception ex)
    {
        Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
    }
}

Solution

  • I have spoken directly with Autodesk on this, and it looks like my issue was the way I was deleting old viewports and creating a new one. They provided the following change to my code with works as intended

    [CommandMethod("CreateViewport")]
    public static void CreateViewport()
    {
        // Get the current document and database, and start a transaction
        Document acDoc = Application.DocumentManager.MdiActiveDocument;
        Database acCurDb = acDoc.Database;
        try
        {
            Entity acObj = null;
            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                // Open the Block table for read
                BlockTable acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
                // Open the Block table record Model space for write
                BlockTableRecord acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                // Draw the desired viewport on the default layer
                // Create a circle that is at 2,3 with a radius of 4.25
                Circle acCirc = new Circle();
                acCirc.SetDatabaseDefaults();
                acCirc.Center = new Point3d(2, 3, 0);
                acCirc.Radius = 4.25;
                acObj = acCirc;
                acBlkTblRec.AppendEntity(acObj);
                acTrans.AddNewlyCreatedDBObject(acObj, true);
                // Set current layer to 0
                acCurDb.Clayer = acObj.LayerId;
                // Switch to the previous Paper space layout
                Application.SetSystemVariable("TILEMODE", 0);
                acDoc.Editor.SwitchToPaperSpace();
                // List Layouts
                DBDictionary layoutDic = acTrans.GetObject(acCurDb.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
                LayoutManager acLayoutMgr = LayoutManager.Current;
                Layout acLayout = null;
                foreach (DBDictionaryEntry entry in layoutDic)
                {
                    ObjectId layoutId = entry.Value;
                    Layout currentLayout = acTrans.GetObject(layoutId, OpenMode.ForRead) as Layout;
                    if (currentLayout.LayoutName == "Layout1")
                    {
                        acLayout = acTrans.GetObject(layoutId, OpenMode.ForWrite) as Layout;
                        // Delete any existing view ports
                        ObjectIdCollection acViewports = acLayout.GetViewports();
                        foreach (ObjectId acViewportID in acViewports)
                        {
                            Viewport acVport = acTrans.GetObject(acViewportID, OpenMode.ForWrite) as Viewport;
                            acVport.Erase();
                        }
                        //create a blank viewport, we need at least one viewport
                        var btr = (BlockTableRecord)acTrans.GetObject(acLayout.BlockTableRecordId, OpenMode.ForWrite);
                        var vp = new Viewport();
                        btr.AppendEntity(vp);
                        acTrans.AddNewlyCreatedDBObject(vp, true);
                        break;
                    }
                }
                // If layout wasn't found, make it
                if (acLayout == null)
                {
                    ObjectId objID = acLayoutMgr.CreateLayout("Layout1");
                    acLayout = acTrans.GetObject(objID, OpenMode.ForWrite) as Layout;
                }
    
                // Set the layout current if it is not already
                if (acLayout.TabSelected == false)
                {
                    acLayoutMgr.CurrentLayout = acLayout.LayoutName;
                }
                PlotSettings acPlSet = new PlotSettings(acLayout.ModelType);
                acPlSet.CopyFrom(acLayout);
                // Update the PlotConfigurationName property of the PlotSettings object
                PlotSettingsValidator acPlSetVdr = PlotSettingsValidator.Current;
                acPlSetVdr.SetPlotConfigurationName(acPlSet, "DWG To PDF.pc3", "ANSI_B_(11.00_x_17.00_Inches)");
                // Zoom to show the whole paper
                acPlSetVdr.SetZoomToPaperOnUpdate(acPlSet, true);
                // Update the layout
                if (!acLayout.IsWriteEnabled)
                {
                    acLayout.UpgradeOpen();
                }                    
    
                acLayout.CopyFrom(acPlSet);
                // Save the new objects to the database
                acTrans.Commit();
            }
            acDoc.Editor.Command("._VIEWPORTS", "Fit");
            acDoc.Editor.Command("._MSPACE");
            acDoc.Editor.Command("._ZOOM", "_O", SelectionSet.FromObjectIds(new ObjectId[] { acObj.ObjectId }), "");
            acDoc.Editor.Command("._PSPACE");
            acDoc.Editor.Command("._ZOOM", "E");
            string dwgPath = @"D:\Work\Cases\8360\OutputDrawing_.dwg";
            dwgPath = dwgPath.Insert(dwgPath.IndexOf(".dwg"), DateTime.Now.ToString("yyyyMMddHHmmssffff"));
            acCurDb.SaveAs(dwgPath, DwgVersion.AC1032);
        }
        catch (System.Exception ex)
        {
            Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
        }
    }