Create Layouts and Viewoirts in External drawings

Create Layouts and Viewoirts in External drawings

Anonymous
Not applicable
2,202 Views
6 Replies
Message 1 of 7

Create Layouts and Viewoirts in External drawings

Anonymous
Not applicable

Is it possible to create layouts and viewports in an external drawing?  All the examples I've found in the documentation and on line assume using the current drawing.  The code below compiles and runs, creates the layouts, but when the created drawing is opened, the viewports are not there.

Thanks

Paul

0 Likes
2,203 Views
6 Replies
Replies (6)
Message 2 of 7

Keith.Brown
Advisor
Advisor

Short answer is yes it is possible.  

 

I just glanced at your code in passing and the only comment that I have is that I obtain paper space differently then what you did.  I use:

 

                Dim blockTable = CType(transaction.GetObject(database.BlockTableId, OpenMode.ForWrite), BlockTable)
                Dim paperSpace = CType(transaction.GetObject(blockTable(BlockTableRecord.PaperSpace), OpenMode.ForWrite), BlockTableRecord)

Not sure if that is what is wrong or not without going more in depth in analyzing your code.

0 Likes
Message 3 of 7

Anonymous
Not applicable

I beleive the problem is that Layout needs to be activated first. See:

http://adndevblog.typepad.com/autocad/2012/08/cloned-viewport-exists-but-is-invisible-in-a-newly-cre...

So the real question is:  How do I make the newly created Layout active in an external database?

Thanks
Paul

 

0 Likes
Message 4 of 7

_gile
Consultant
Consultant

Hi,

 

Try to make the side database the working one and then use the LayoutManager (don't forget to reset the working database to the active document one).

 

HostApplicationServices.WorkingDatabase = sideDatabase;
LayoutManager layoutMgr = LayoutManager.Current;
layoutMgr.CurrentLayout = "TheNewlyCreatedLayout"; 


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 5 of 7

Anonymous
Not applicable

Ok, that helped somewhat.  One of the viewports gets created (not both), but now AutoCAD crashes after it's all done.

I had to separate the viewport creation into two transactions.  Inside one transaction, only the second viewport would be created; the first not at all.  With a separate transactions, the first viewport gets created, but nothing is visible inside it.

Also, after the command is done, and control is passed back the user, a few seconds later AutoCAD crashes.  This does not happen if I remove the viewport creation code.

 

 

public static void CreateLayoutDrawing(string file1, string file2)
{
  Document doc = Application.DocumentManager.MdiActiveDocument;
  Editor ed = doc.Editor;
  //Database db = doc.Database;
  BlockTable bt;
  BlockTableRecord btr;
  BlockReference bref;
  Object obj;
  ObjectId loid;
  DBObject dbobj;
  Point3d pt;
  Transaction tr;
  Layout layout;
  Viewport vp;

  // A new database, drawing
  Database db = new Database(false, true);
      
  try
  {
    db.ReadDwgFile(file1, System.IO.FileShare.ReadWrite, true, "");
  }
  catch (System.Exception)
  {
    ed.WriteMessage("\nUnable to open file: " + file1);
    return;
  }

  HostApplicationServices.WorkingDatabase = db;
  LayoutManager lmgr = LayoutManager.Current;

  tr = db.TransactionManager.StartTransaction();
  using (tr)
  {

    bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

    btr = new BlockTableRecord();
    btr.Name = "*Paper_Space";
    layout = new Layout();
    layout.LayoutName = "Block 1";
    bt.UpgradeOpen();
    loid = bt.Add(btr);
    bt.DowngradeOpen();
    tr.AddNewlyCreatedDBObject(btr, true);
    // Add the layout to the layout dictionary associating the databse and block table record to the layout
    layout.AddToLayoutDictionary(db, loid);
    tr.AddNewlyCreatedDBObject(layout, true);

    lmgr.CurrentLayout = "Block 1";
    //db.TileMode = true;	// Makes no difference if true or false

    // Create and Setup the viewport
    vp = new Viewport();
    vp.SetDatabaseDefaults();
    vp.ViewCenter = new Point2d(10, 10);
    vp.ViewHeight = 15;
    btr.AppendEntity(vp);
    tr.AddNewlyCreatedDBObject(vp, true);
    vp.CenterPoint = new Point3d(3, 2, 0);
    vp.Height = 7;
    vp.Width = 12;
    vp.Visible = true;

    tr.Commit();
    // Almost works.  Viewport exists, but nothing is visible in it.
    // If I try to put both View ports in the same transaction, then "Block 1" does
    // not get created at all.
  }

  tr = db.TransactionManager.StartTransaction();
  using (tr)
  {
    bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

    btr = new BlockTableRecord();
    btr.Name = "*Paper_Space";
    layout = new Layout();
    layout.LayoutName = "Block 2";
    bt.UpgradeOpen();
    loid = bt.Add(btr);
    bt.DowngradeOpen();
    tr.AddNewlyCreatedDBObject(btr, true);
    // Add the layout to the layout dictionary associating the databse and block table record to the layout
    layout.AddToLayoutDictionary(db, loid);
    tr.AddNewlyCreatedDBObject(layout, true);

    lmgr.CurrentLayout = "Block 2";
    //db.TileMode = true;	// Makes no difference if true or false

    // Create and Setup the viewport
    vp = new Viewport();
    vp.SetDatabaseDefaults();
    vp.ViewCenter = new Point2d(10, 10);
    vp.ViewHeight = 15;
    btr.AppendEntity(vp);
    tr.AddNewlyCreatedDBObject(vp, true);
    vp.CenterPoint = new Point3d(3, 2, 0);
    vp.Height = 7;
    vp.Width = 12;
    vp.Visible = true;

    tr.Commit();
	// This one works. And it's exactly the same as the first, which doesn't
	// Why ?????
  }

  HostApplicationServices.WorkingDatabase = doc.Database;

  // Save the new drawing
  db.SaveAs(file2, true, DwgVersion.Current, db.SecurityParameters);
  db.Dispose();
}

// After this is all done, AutoCAD crashes. Not immediately, but after a few seconds.
// If I remove the viewport creation code, no crash.
0 Likes
Message 6 of 7

SENL1362
Advisor
Advisor

I've had better results using the LayoutManager to create layouts, like so:

           LayoutManager layoutManager = LayoutManager.Current;
            layoutId = layoutManager.GetLayoutId(layoutName);
            if (layoutId.IsNull)
            {
               
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                layoutId = layoutManager.CreateLayout(layoutName);
               Layout layout = (Layout)tr.GetObject(layoutId, OpenMode.ForRead);
                layout.UpgradeOpen();
                layout.Initialize();
                tr.Commit();
             }

... using (Transaction tr = db.TransactionManager.StartTransaction()) { Layout layout = (Layout)tr.GetObject(layoutId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead); Viewport vp = new Viewport(); vp.SetDatabaseDefaults(); btr.UpgradeOpen(); btr.AppendEntity(vp); tr.AddNewlyCreatedDBObject(vp, true); vp.Visible = true; vp.On = true; vp.Locked = true; vp.UpdateDisplay(); tr.Commit(); } ...
0 Likes
Message 7 of 7

Anonymous
Not applicable

Hello,

 

I know it's an old topic but I've been having the same problem while creating viewports on unnactivated layouts and I came up with a solution.

Its a tricky workaround and I'd like to share it 😄

 

First I create the layout and its blocktablerecord:

 

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                DBDictionary layoutsEx = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
                BlockTable blkTbl = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;

                using (BlockTableRecord blkBlkRec = new BlockTableRecord())
                {
                    int layoutCount = layoutsEx.Count - 1;

                    blkBlkRec.Name = "*Paper_Space" + layoutCount.ToString();
                    blkTbl.Add(blkBlkRec);
                    tr.AddNewlyCreatedDBObject(blkBlkRec, true);

                    DBDictionary layouts = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForWrite) as DBDictionary;

                    using (Layout lay = new Layout())
                    {
                        lay.LayoutName = LayoutName;
                        lay.AddToLayoutDictionary(db, blkBlkRec.ObjectId);
                        tr.AddNewlyCreatedDBObject(lay, true);
                    }

 

The thing is that AutoCad always recognize the first Viewport on a layout's Blocktablerecord as the layout's own ViewportTableRecord alike (because Layouts do no have ViewportTable like the Modelspace), so when you create and configure the first Viewport of a Layouts BlockTableRecord manually AutoCad makes a mess and assumes it to be Layout View.

 

As a solution, before committing the transaction I'd add a Viewport to the BlockTableRecord with the same custom properties that Autocad would use in this situation:

 

                    using (Autodesk.AutoCAD.DatabaseServices.Viewport VP = new Autodesk.AutoCAD.DatabaseServices.Viewport()
                        {
                            Color = Color.FromRgb(51, 51, 51),
                            BackClipDistance = 0,
                            BackClipOn = false,
                            Background = ObjectId.Null,
                            Brightness = 0,
                            CenterPoint = new Point3d(0, 0, 0),
                            CircleSides = 1000,
                            Contrast = 0,
                            CustomScale = 0.0143,
                            DefaultLightingOn = true,
                            DefaultLightingType = Autodesk.AutoCAD.DatabaseServices.DefaultLightingType.TwoDistantLights,
                            Elevation = 0,
                            FastZoomOn = true,
                            FrontClipAtEyeOn = true,
                            FrontClipDistance = 0,
                            FrontClipOn = false,
                            GridAdaptive = true,
                            GridBoundToLimits = false,
                            GridFollow = false,
                            GridIncrement = new Vector2d(10, 10),
                            GridMajor = 5,
                            GridSubdivisionRestricted = true,
                            Height = 9,
                            HiddenLinesRemoved = false,
                            LensLength = 50,
                            Locked = false,
                            NonRectClipEntityId = ObjectId.Null,
                            NonRectClipOn = false,
                            PerspectiveOn = false,
                            ShadePlot = ShadePlotType.AsDisplayed,
                            SnapAngle = 0,
                            SnapBasePoint = new Point2d(0, 0),
                            SnapIncrement = new Vector2d(10, 10),
                            SnapIsometric = false,
                            SnapIsoPair = 0,
                            SnapOn = false,
                            TwistAngle = 0,
                            UcsFollowModeOn = false,
                            UcsIconAtOrigin = false,
                            UcsIconVisible = false,
                            VisualStyleId = (db.VisualStyleDictionaryId.GetObject(OpenMode.ForRead) as DBDictionary).GetAt("2dWireframe")
                            })
                    {
                        blkBlkRec.AppendEntity(VP);
                        tr.AddNewlyCreatedDBObject(VP, true);

//These properties after adding to Database because they are Database Dependent: VP.GridOn = false; VP.UcsFollowModeOn = false; VP.UcsIconAtOrigin = false; VP.UcsIconVisible = true; VP.UcsPerViewport = true; } } tr.Commit(); }

Now you can add to this layout BlockTableRecord as many viewports as you'd like and there should be no more errors. 😄

 

0 Likes